Cleanup
This commit is contained in:
parent
0c144f992b
commit
7325fb5c63
@ -16,25 +16,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
add_executable(
|
||||
cg1
|
||||
|
||||
WIN32
|
||||
src/main.cpp
|
||||
|
||||
src/frame.hpp
|
||||
src/drawing_assets.hpp
|
||||
src/drawing_assets.cpp
|
||||
src/painter.cpp
|
||||
src/painter.hpp
|
||||
src/old_main.cpp
|
||||
|
||||
src/ui.hpp
|
||||
src/ui.cpp
|
||||
)
|
||||
|
||||
qt5_use_modules(cg1 Widgets)
|
||||
|
||||
add_subdirectory(renderer-api)
|
||||
add_subdirectory(utilities)
|
||||
add_subdirectory(qt-utilities)
|
||||
|
@ -1,139 +0,0 @@
|
||||
#include <varargs.h>
|
||||
#include "frame.hpp"
|
||||
#include "drawing_assets.hpp"
|
||||
|
||||
void draw_circle(Frame *frame, int cx, int cy, int radius, COLOR outline) {
|
||||
int x = 0, y = radius;
|
||||
while (x < y) {
|
||||
int D1 = x * x + y * y - radius * radius;
|
||||
int D2 = x * x + (y - 1) * (y - 1) - radius * radius;
|
||||
|
||||
if (D1 > -D2)
|
||||
y--;
|
||||
|
||||
frame->set_pixel(cx + x, cy + y, outline);
|
||||
frame->set_pixel(cx + x, cy - y, outline);
|
||||
frame->set_pixel(cx + y, cy + x, outline);
|
||||
frame->set_pixel(cx + y, cy - x, outline);
|
||||
frame->set_pixel(cx - x, cy + y, outline);
|
||||
frame->set_pixel(cx - x, cy - y, outline);
|
||||
frame->set_pixel(cx - y, cy + x, outline);
|
||||
frame->set_pixel(cx - y, cy - x, outline);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_line(Frame *frame, int x1, int y1, int x2, int y2, COLOR color) {
|
||||
int dy = y2 - y1, dx = x2 - x1;
|
||||
if (dx == 0 && dy == 0) {
|
||||
frame->set_pixel(x1, y1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
if (abs(dx) > abs(dy)) {
|
||||
if (x2 < x1) {
|
||||
std::swap(x1, x2);
|
||||
std::swap(y1, y2);
|
||||
dx = -dx;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
int y, dx2 = dx / 2, p = 0;
|
||||
if (dy < 0) dx2 = -dx2;
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
y = (p + dx2) / dx + y1;
|
||||
p += dy;
|
||||
frame->set_pixel(x, y, color);
|
||||
}
|
||||
} else {
|
||||
if (y2 < y1) {
|
||||
std::swap(x1, x2);
|
||||
std::swap(y1, y2);
|
||||
dx = -dx;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
int x, dy2 = dy / 2, p = 0;
|
||||
if (dx < 0) dy2 = -dy2;
|
||||
for (int y = y1; y <= y2; y++) {
|
||||
x = (p + dy2) / dy + x1;
|
||||
p += dx;
|
||||
frame->set_pixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fill_triangle(Frame *f, int x0, int y0, int x1, int y1, int x2, int y2, Shader const *shader) {
|
||||
// Отсортируем точки таким образом, чтобы выполнилось условие: y0 < y1 < y2
|
||||
if (y1 < y0) {
|
||||
std::swap(y1, y0);
|
||||
std::swap(x1, x0);
|
||||
}
|
||||
if (y2 < y1) {
|
||||
std::swap(y2, y1);
|
||||
std::swap(x2, x1);
|
||||
}
|
||||
if (y1 < y0) {
|
||||
std::swap(y1, y0);
|
||||
std::swap(x1, x0);
|
||||
}
|
||||
// Определяем номера строк пикселей, в которых располагаются точки треугольника
|
||||
int Y0 = (int) (y0 + 0.5f);
|
||||
int Y1 = (int) (y1 + 0.5f);
|
||||
int Y2 = (int) (y2 + 0.5f);
|
||||
// Отсечение невидимой части треугольника
|
||||
if (Y0 < 0) Y0 = 0;
|
||||
else if (Y0 >= f->height) Y0 = f->height;
|
||||
if (Y1 < 0) Y1 = 0;
|
||||
else if (Y1 >= f->height) Y1 = f->height;
|
||||
if (Y2 < 0) Y2 = 0;
|
||||
else if (Y2 >= f->height) Y2 = f->height;
|
||||
// Рисование верхней части треугольника
|
||||
for (float y = Y0 + 0.5f; y < Y1; y++) {
|
||||
int X0 = (int) ((y - y0) / (y1 - y0) * (x1 - x0) + x0 + 0.5f);
|
||||
int X1 = (int) ((y - y0) / (y2 - y0) * (x2 - x0) + x0 + 0.5f);
|
||||
if (X0 > X1) std::swap(X0, X1);
|
||||
if (X0 < 0) X0 = 0;
|
||||
if (X1 > f->width) X1 = f->width;
|
||||
for (int x = X0; x < X1; x++) {
|
||||
f->set_pixel(x, y, shader->get_color(x + 0.5f, y));
|
||||
}
|
||||
}
|
||||
// Рисование нижней части треугольника
|
||||
for (float y = Y1 + 0.5f; y < Y2; y++) {
|
||||
int X0 = (int) ((y - y1) / (y2 - y1) * (x2 - x1) + x1 + 0.5f);
|
||||
int X1 = (int) ((y - y0) / (y2 - y0) * (x2 - x0) + x0 + 0.5f);
|
||||
if (X0 > X1) std::swap(X0, X1);
|
||||
if (X0 < 0) X0 = 0;
|
||||
if (X1 > f->width) X1 = f->width;
|
||||
for (int x = X0; x < X1; x++) {
|
||||
f->set_pixel(x, y, shader->get_color(x + 0.5f, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
COLOR ColorFromHSV(double hue, double saturation, double value) {
|
||||
int hi = int(floor(hue / 60)) % 6;
|
||||
double f = hue / 60 - floor(hue / 60);
|
||||
value = value * 255;
|
||||
const auto v = (unsigned char) (value);
|
||||
const auto p = (unsigned char) (value * (1 - saturation));
|
||||
const auto q = (unsigned char) (value * (1 - f * saturation));
|
||||
const auto t = (unsigned char) (value * (1 - (1 - f) * saturation));
|
||||
switch (hi) {
|
||||
case 0:
|
||||
return COLOR{v, t, p};
|
||||
case 1:
|
||||
return COLOR{q, v, p};
|
||||
case 2:
|
||||
return COLOR{p, v, t};
|
||||
case 3:
|
||||
return COLOR{p, q, v};
|
||||
case 4:
|
||||
return COLOR{t, p, v};
|
||||
default:
|
||||
return COLOR{v, p, q};
|
||||
}
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "frame.hpp"
|
||||
|
||||
void draw_circle(Frame *frame, int cx, int cy, int radius, COLOR outline);
|
||||
|
||||
inline void draw_circle(Frame *frame, Point c, int radius, COLOR outline) {
|
||||
draw_circle(frame, c.x, c.y, radius, outline);
|
||||
}
|
||||
|
||||
void draw_line(Frame *frame, int x1, int y1, int x2, int y2, COLOR color);
|
||||
|
||||
inline void draw_line(Frame *frame, Point p1, Point p2, COLOR color) {
|
||||
draw_line(frame, p1.x, p1.y, p2.x, p2.y, color);
|
||||
}
|
||||
|
||||
template<class ...>
|
||||
struct draw_polyline_ {
|
||||
template<class ...point_t>
|
||||
friend
|
||||
void draw_polyline(Frame *frame, COLOR color, point_t ...points);
|
||||
|
||||
template<class ...>
|
||||
friend
|
||||
struct draw_polyline_;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
template<class p0_t, class p1_t, class ...pp_t>
|
||||
struct draw_polyline_<p0_t, p1_t, pp_t...> {
|
||||
template<class ...point_t>
|
||||
friend
|
||||
void draw_polyline(Frame *frame, COLOR color, point_t ...points);
|
||||
|
||||
template<class ...>
|
||||
friend
|
||||
struct draw_polyline_;
|
||||
private:
|
||||
static_assert(std::is_same_v<p0_t, Point>);
|
||||
static_assert(std::is_same_v<p1_t, Point>);
|
||||
|
||||
static void draw(Frame *frame, COLOR color, p0_t p0, p1_t p1, pp_t ...points) {
|
||||
draw_line(frame, p0, p1, color);
|
||||
draw_polyline_<p1_t, pp_t...>::draw(frame, color, p1, points...);
|
||||
}
|
||||
|
||||
static constexpr bool HAS_ANY = true;
|
||||
|
||||
static Point first(p0_t p0, p1_t p1, pp_t ...points) {
|
||||
return p0;
|
||||
}
|
||||
|
||||
static Point last(p0_t p0, p1_t p1, pp_t ...points) {
|
||||
return draw_polyline_<p1_t, pp_t...>::last(p1, points...);
|
||||
}
|
||||
};
|
||||
|
||||
template<class p0_t>
|
||||
struct draw_polyline_<p0_t> {
|
||||
template<class ...point_t>
|
||||
friend
|
||||
void draw_polyline(Frame *frame, COLOR color, point_t ...points);
|
||||
|
||||
template<class ...>
|
||||
friend
|
||||
struct draw_polyline_;
|
||||
private:
|
||||
static_assert(std::is_same_v<p0_t, Point>);
|
||||
|
||||
static void draw(Frame *frame, COLOR color, p0_t p0) {}
|
||||
|
||||
static constexpr bool HAS_ANY = true;
|
||||
|
||||
|
||||
static Point first(p0_t p0) {
|
||||
return p0;
|
||||
}
|
||||
|
||||
static Point last(p0_t p0) {
|
||||
return p0;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct draw_polyline_<> {
|
||||
template<class ...point_t>
|
||||
friend
|
||||
void draw_polyline(Frame *frame, COLOR color, point_t ...points);
|
||||
|
||||
template<class ...>
|
||||
friend
|
||||
struct draw_polyline_;
|
||||
private:
|
||||
static void draw(Frame *frame, COLOR color) {}
|
||||
|
||||
static constexpr bool HAS_ANY = false;
|
||||
|
||||
static Point first() {
|
||||
return Point{0, 0};
|
||||
}
|
||||
|
||||
static Point last() {
|
||||
return Point{0, 0};
|
||||
}
|
||||
};
|
||||
|
||||
template<class ...point_t>
|
||||
void draw_polyline(Frame *frame, COLOR color, point_t ...points) {
|
||||
if constexpr (!draw_polyline_<point_t...>::HAS_ANY) {}
|
||||
else {
|
||||
draw_polyline_<point_t...>::draw(frame, color, points...);
|
||||
draw_line(frame, draw_polyline_<point_t...>::last(points...), draw_polyline_<point_t...>::first(points...), color);
|
||||
}
|
||||
}
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
[[nodiscard]] virtual COLOR get_color(int x, int y) const = 0;
|
||||
};
|
||||
|
||||
class MonoShader : public Shader {
|
||||
private:
|
||||
COLOR color;
|
||||
public:
|
||||
explicit MonoShader(COLOR color) : color{color} {}
|
||||
|
||||
[[nodiscard]] COLOR get_color(int x, int y) const override {
|
||||
return this->color;
|
||||
}
|
||||
};
|
||||
|
||||
class BarycentricInterpolatorShader : public Shader {
|
||||
private:
|
||||
int x0, y0, x1, y1, x2, y2, S;
|
||||
COLOR C0, C1, C2;
|
||||
public:
|
||||
BarycentricInterpolatorShader(float _x0, float _y0, float _x1, float _y1, float
|
||||
_x2, float _y2, COLOR A0, COLOR A1, COLOR A2) :
|
||||
x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2),
|
||||
S((_y1 - _y2) * (_x0 - _x2) + (_x2 - _x1) * (_y0 - _y2)), C0(A0), C1(A1),
|
||||
C2(A2) {
|
||||
}
|
||||
|
||||
COLOR get_color(int x, int y) const override {
|
||||
// Барицентрическая интерполяция
|
||||
float h0 = ((y1 - y2) * (x - x2) + (x2 - x1) * (y - y2)) / S;
|
||||
float h1 = ((y2 - y0) * (x - x2) + (x0 - x2) * (y - y2)) / S;
|
||||
float h2 = 1 - h0 - h1;
|
||||
float r = h0 * C0.red + h1 * C1.red + h2 * C2.red;
|
||||
float g = h0 * C0.green + h1 * C1.green + h2 * C2.green;
|
||||
float b = h0 * C0.blue + h1 * C1.blue + h2 * C2.blue;
|
||||
float a = h0 * C0.alpha + h1 * C1.alpha + h2 * C2.alpha;
|
||||
return COLOR(r, g, b, a);
|
||||
}
|
||||
};
|
||||
|
||||
void fill_triangle(Frame *f, int x0, int y0, int x1, int y1, int x2, int y2, Shader const *shader);
|
||||
|
||||
|
||||
inline void fill_triangle(Frame *f, Point p0, Point p1, Point p2, Shader const *shader) {
|
||||
fill_triangle(f, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, shader);
|
||||
}
|
||||
|
||||
inline void fill_triangle(Frame *f, int x0, int y0, int x1, int y1, int x2, int y2, COLOR color) {
|
||||
MonoShader s{color};
|
||||
fill_triangle(f, x0, y0, x1, y1, x2, y2, &s);
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void fill_triangle(Frame *f, Point p0, Point p1, Point p2, COLOR color) {
|
||||
MonoShader s{color};
|
||||
fill_triangle(f, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, &s);
|
||||
}
|
||||
|
||||
COLOR ColorFromHSV(double hue, double saturation, double value);
|
@ -1,74 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
struct COLOR {
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
unsigned char blue;
|
||||
unsigned char alpha;
|
||||
|
||||
COLOR() : red(0), green(0), blue(0), alpha(255) {}
|
||||
|
||||
COLOR(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
|
||||
|
||||
};
|
||||
|
||||
class Point {
|
||||
public:
|
||||
int x;
|
||||
int y;
|
||||
|
||||
inline Point(int x, int y) : x{x}, y{y} {};
|
||||
|
||||
[[nodiscard]] Point rotated_around(int cx, int cy, double angle_radians) const {
|
||||
return Point{
|
||||
static_cast<int>((this->x - cx) * std::cos(angle_radians) - (this->y - cy) * std::sin(angle_radians) + cx),
|
||||
static_cast<int>((this->x - cx) * std::sin(angle_radians) + (this->y - cy) * std::cos(angle_radians) + cy)
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] Point rotated_around(Point p, double angle_radians) const {
|
||||
return this->rotated_around(p.x, p.y, angle_radians);
|
||||
}
|
||||
|
||||
[[nodiscard]] Point moved(int dx, int dy) const {
|
||||
return Point{this->x + dx, this->y + dy};
|
||||
}
|
||||
};
|
||||
|
||||
class Frame {
|
||||
COLOR *pixels;
|
||||
public:
|
||||
const int width, height;
|
||||
|
||||
inline Frame(int _width, int _height) : width{_width}, height{_height} {
|
||||
int size = width * height;
|
||||
|
||||
this->pixels = new COLOR[size];
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]]inline COLOR _get_pixel(int x, int y) const {
|
||||
return this->pixels[y * this->width + x];
|
||||
}
|
||||
|
||||
[[nodiscard]] inline COLOR &_get_pixel(int x, int y) {
|
||||
return this->pixels[y * this->width + x];
|
||||
}
|
||||
|
||||
public:
|
||||
inline void set_pixel(int x, int y, COLOR color) {
|
||||
this->_get_pixel(x, y) = color;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline COLOR get_pixel(int x, int y) const {
|
||||
return this->_get_pixel(x, y);
|
||||
}
|
||||
|
||||
|
||||
inline ~Frame() {
|
||||
delete[]this->pixels;
|
||||
}
|
||||
};
|
13
src/main.cpp
13
src/main.cpp
@ -1,13 +0,0 @@
|
||||
#include <QApplication>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "ui.hpp"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
QApplication qapp(argc, argv);
|
||||
|
||||
auto w = new MainWindow();
|
||||
w->show();
|
||||
|
||||
QApplication::exec();
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
#include <tuple>
|
||||
#include "frame.hpp"
|
||||
#include "drawing_assets.hpp"
|
||||
#include "painter.hpp"
|
||||
|
||||
|
||||
class DemoPainter : public Painter {
|
||||
public:
|
||||
void draw(PainterState *state, Frame *frame) const override {
|
||||
int W = frame->width, H = frame->height;
|
||||
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
|
||||
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1) / sqrt(2);
|
||||
if (a < 1) return; // Если окно очень маленькое, то ничего не рисуем
|
||||
float angle = state->angle; // Угол поворота
|
||||
a = a / 2;
|
||||
|
||||
Point center{W / 2, H / 2};
|
||||
|
||||
draw_polyline(
|
||||
frame, COLOR{200, 30, 45},
|
||||
center.moved(a, a).rotated_around(center, angle),
|
||||
center.moved(a, -a).rotated_around(center, angle),
|
||||
center.moved(-a, -a).rotated_around(center, angle),
|
||||
center.moved(-a, a).rotated_around(center, angle)
|
||||
);
|
||||
|
||||
|
||||
// Рисуем описанную окружность
|
||||
draw_circle(frame, center, int(a * sqrt(2) + 0.5f), COLOR(100, 100, 250));
|
||||
|
||||
// Рисуем пиксель, на который кликнул пользователь
|
||||
if (state->clicked_pixel.x >= 0 && state->clicked_pixel.x < W &&
|
||||
state->clicked_pixel.y >= 0 && state->clicked_pixel.y < H)
|
||||
frame->set_pixel(state->clicked_pixel.x, state->clicked_pixel.y, {34, 175, 60}); // Пиксель зелёного цвета
|
||||
}
|
||||
};
|
||||
|
||||
class Variant3S1Painter : public Painter {
|
||||
public:
|
||||
void draw(PainterState *state, Frame *frame) const override {
|
||||
int W = frame->width, H = frame->height;
|
||||
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
|
||||
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1);
|
||||
if (a < 1) return; // Если окно очень маленькое, то ничего не рисуем
|
||||
float angle = state->angle; // Угол поворота
|
||||
a = a / 2;
|
||||
|
||||
Point center{W / 2, H / 2};
|
||||
|
||||
|
||||
|
||||
// Рисуем описанную окружность
|
||||
draw_circle(frame, center, a, COLOR(0, 0, 0));
|
||||
draw_polyline(
|
||||
frame, COLOR{0, 200, 0},
|
||||
center.moved(0, a).rotated_around(center, 0 + angle),
|
||||
center.moved(0, a).rotated_around(center, +2.0944 + angle),
|
||||
center.moved(0, a).rotated_around(center, -2.0944 + angle)
|
||||
);
|
||||
draw_circle(frame, center, a / 2, COLOR(0, 200, 0));
|
||||
draw_circle(frame, center.moved(0, a * 2 / 3).rotated_around(center, angle), a / 6, COLOR(0, 200, 0));
|
||||
draw_circle(frame, center.moved(0, a * 2 / 3).rotated_around(center, +2.0944 + angle), a / 6, COLOR(0, 200, 0));
|
||||
draw_circle(frame, center.moved(0, a * 2 / 3).rotated_around(center, -2.0944 + angle), a / 6, COLOR(0, 200, 0));
|
||||
|
||||
// Рисуем пиксель, на который кликнул пользователь
|
||||
if (state->clicked_pixel.x >= 0 && state->clicked_pixel.x < W &&
|
||||
state->clicked_pixel.y >= 0 && state->clicked_pixel.y < H)
|
||||
frame->set_pixel(state->clicked_pixel.x, state->clicked_pixel.y, {34, 175, 60}); // Пиксель зелёного цвета
|
||||
}
|
||||
};
|
||||
|
||||
static auto predefined_painters_ = std::make_tuple(
|
||||
DemoPainter(),
|
||||
Variant3S1Painter()
|
||||
);
|
||||
|
||||
Painter const *const predefined_painters[] = {
|
||||
&std::get<0>(predefined_painters_),
|
||||
&std::get<1>(predefined_painters_),
|
||||
nullptr
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "frame.hpp"
|
||||
|
||||
class PainterState {
|
||||
public:
|
||||
float angle = 0;
|
||||
struct {
|
||||
unsigned short x = -1, y = -1;
|
||||
} clicked_pixel;
|
||||
|
||||
PainterState() = default;
|
||||
|
||||
void set_clicked_pixel(unsigned short x, unsigned short y) {
|
||||
this->clicked_pixel.x = x;
|
||||
this->clicked_pixel.y = y;
|
||||
}
|
||||
};
|
||||
|
||||
class Painter {
|
||||
public:
|
||||
virtual void draw(PainterState *state, Frame *frame) const = 0;
|
||||
};
|
||||
|
||||
extern Painter const *const predefined_painters[];
|
||||
|
||||
|
||||
class PixelGridPainter : public Painter {
|
||||
private:
|
||||
const COLOR c1;
|
||||
const COLOR c2;
|
||||
public:
|
||||
inline PixelGridPainter(COLOR c1, COLOR c2) : c1{c1}, c2{c2} {}
|
||||
|
||||
inline void draw(PainterState *state, Frame *frame) const override {
|
||||
for (int y = 0; y < frame->height; y++) {
|
||||
for (int x = 0; x < frame->width; x++) {
|
||||
if ((x + y) % 2 == 0)
|
||||
frame->set_pixel(x, y, this->c1);
|
||||
else
|
||||
frame->set_pixel(x, y, this->c2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
#include "frame.hpp"
|
||||
#include "shaders.hpp"
|
||||
|
||||
COLOR BarycentricInterpolator::get_color(int x, int y) const {
|
||||
// Барицентрическая интерполяция
|
||||
float h0 = ((y1 - y2) * (x - x2) + (x2 - x1) * (y - y2)) / S;
|
||||
float h1 = ((y2 - y0) * (x - x2) + (x0 - x2) * (y - y2)) / S;
|
||||
float h2 = 1 - h0 - h1;
|
||||
float r = h0 * C0.red + h1 * C1.red + h2 * C2.red;
|
||||
float g = h0 * C0.green + h1 * C1.green + h2 * C2.green;
|
||||
float b = h0 * C0.blue + h1 * C1.blue + h2 * C2.blue;
|
||||
float a = h0 * C0.alpha + h1 * C1.alpha + h2 * C2.alpha;
|
||||
return COLOR(r, g, b, a);
|
||||
}
|
||||
|
||||
|
||||
COLOR RadialBrush::get_color(int x, int y) const {
|
||||
double dx = (double) x - cx, dy = (double) y - cy;
|
||||
double radius = sqrt(dx * dx + dy * dy);
|
||||
float h0 = (sin(radius / 10 + angle) + 1.0f) / 2;
|
||||
float h1 = 1 - h0;
|
||||
float r = h0 * C0.red + h1 * C1.red;
|
||||
float g = h0 * C0.green + h1 * C1.green;
|
||||
float b = h0 * C0.blue + h1 * C1.blue;
|
||||
return COLOR(r, g, b);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "painter.hpp"
|
||||
#include "drawing_assets.hpp"
|
||||
|
||||
class BarycentricInterpolator : public Shader {
|
||||
private:
|
||||
float x0, y0, x1, y1, x2, y2, S;
|
||||
COLOR C0, C1, C2;
|
||||
public:
|
||||
inline BarycentricInterpolator(float _x0, float _y0, float _x1, float _y1, float _x2, float _y2, COLOR A0, COLOR A1, COLOR A2) :
|
||||
x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2),
|
||||
S((_y1 - _y2) * (_x0 - _x2) + (_x2 - _x1) * (_y0 - _y2)),
|
||||
C0(A0), C1(A1), C2(A2) {}
|
||||
|
||||
inline BarycentricInterpolator(Point p0, Point p1, Point p2, COLOR A0, COLOR A1, COLOR A2) :
|
||||
BarycentricInterpolator(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, A0, A1, A2) {}
|
||||
|
||||
COLOR get_color(int x, int y) const override;
|
||||
};
|
||||
|
||||
|
||||
class RadialBrush : public Shader {
|
||||
private:
|
||||
float cx, cy;
|
||||
COLOR C0, C1;
|
||||
float angle;
|
||||
public:
|
||||
RadialBrush(float _x0, float _y0, float _x1, float _y1, COLOR A0, COLOR A1, float _angle) :
|
||||
cx((_x0 + _x1) / 2.0f), cy((_y0 + _y1) / 2.0f),
|
||||
C0(A0), C1(A1), angle(_angle) {}
|
||||
|
||||
|
||||
COLOR get_color(int x, int y) const override;
|
||||
};
|
129
src/ui.cpp
129
src/ui.cpp
@ -1,129 +0,0 @@
|
||||
#include <QWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QResizeEvent>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <iostream>
|
||||
|
||||
#include "ui.hpp"
|
||||
|
||||
const QString StatusBar::_scale_label_template{"[F2]/[F3] Масштаб: %1 пикселей"};
|
||||
const QString StatusBar::_painter_label_template{"[Q] Отображаемая фигура: %1/%2"};
|
||||
const QString StatusBar::_x_template{"X=%1"};
|
||||
const QString StatusBar::_y_template{"Y=%1"};
|
||||
|
||||
StatusBar::StatusBar(QWidget *parent) : QWidget(parent) {
|
||||
this->_layout = new QGridLayout(parent);
|
||||
this->setLayout(this->_layout);
|
||||
|
||||
auto add_label = [&](QLabel **dst, QString text, int row, int column, QFlags<Qt::AlignmentFlag> alignment) {
|
||||
*dst = new QLabel(text, this);
|
||||
this->_layout->addWidget(*dst, row, column, alignment);
|
||||
};
|
||||
|
||||
add_label(&(this->_scale_label), StatusBar::_scale_label_template.arg("??"), 0, 0, Qt::AlignRight);
|
||||
add_label(&(this->_painter_label), StatusBar::_painter_label_template.arg("??", "??"), 1, 0, Qt::AlignRight);
|
||||
|
||||
add_label(&(this->_screen_coordinates.title), "Экранные координаты:", 0, 1, Qt::AlignRight);
|
||||
add_label(&(this->_screen_coordinates.x), StatusBar::_x_template.arg("??"), 0, 2, Qt::AlignHCenter);
|
||||
add_label(&(this->_screen_coordinates.y), StatusBar::_y_template.arg("??"), 0, 3, Qt::AlignHCenter);
|
||||
|
||||
add_label(&(this->_scaled_coordinates.title), "Системные координаты:", 1, 1, Qt::AlignRight);
|
||||
add_label(&(this->_scaled_coordinates.x), StatusBar::_x_template.arg("??"), 1, 2, Qt::AlignHCenter);
|
||||
add_label(&(this->_scaled_coordinates.y), StatusBar::_y_template.arg("??"), 1, 3, Qt::AlignHCenter);
|
||||
|
||||
this->_layout->setColumnStretch(4, 1);
|
||||
}
|
||||
|
||||
void StatusBar::set_coordinates(unsigned int screen_x, unsigned int screen_y, unsigned int scaled_x, unsigned int scaled_y) {
|
||||
this->_screen_coordinates.x->setText(StatusBar::_x_template.arg(screen_x));
|
||||
this->_screen_coordinates.y->setText(StatusBar::_y_template.arg(screen_y));
|
||||
|
||||
this->_scaled_coordinates.x->setText(StatusBar::_x_template.arg(scaled_x));
|
||||
this->_scaled_coordinates.y->setText(StatusBar::_y_template.arg(scaled_y));
|
||||
}
|
||||
|
||||
void StatusBar::set_scale(unsigned int current_scale) {
|
||||
this->_scale_label->setText(StatusBar::_scale_label_template.arg(current_scale));
|
||||
}
|
||||
|
||||
void StatusBar::set_painter_index(unsigned int index, unsigned int painters_count) {
|
||||
this->_painter_label->setText(StatusBar::_painter_label_template.arg(index).arg(painters_count));
|
||||
}
|
||||
|
||||
Canvas::Canvas(QWidget *parent) : QWidget(parent), _current_frame{}, _sync{} {
|
||||
this->setMouseTracking(true);
|
||||
this->grabKeyboard();
|
||||
|
||||
this->_mouse_processing.is_pressed = false;
|
||||
this->_mouse_processing.pressed_at = QPoint(0, 0);
|
||||
this->_mouse_processing.is_moved_while_pressed = false;
|
||||
}
|
||||
|
||||
void Canvas::set_frame(QImage &f) {
|
||||
this->_sync.lock();
|
||||
this->_current_frame = std::move(f);
|
||||
this->_sync.unlock();
|
||||
}
|
||||
|
||||
void Canvas::paintEvent(QPaintEvent *event) {
|
||||
QPainter painter{};
|
||||
painter.begin(this);
|
||||
this->_sync.lock();
|
||||
painter.drawImage(this->_current_frame.rect(), this->_current_frame);
|
||||
this->_sync.unlock();
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void Canvas::resizeEvent(QResizeEvent *event) {
|
||||
QWidget::resizeEvent(event);
|
||||
emit this->resized(event->size());
|
||||
}
|
||||
|
||||
MainWindow::MainWindow() : QWidget{} {
|
||||
this->_layout = new QGridLayout(this);
|
||||
this->setLayout(this->_layout);
|
||||
|
||||
this->_status_bar = new StatusBar(this);
|
||||
this->_layout->addWidget(this->_status_bar, 0, 0);
|
||||
|
||||
this->_canvas = new Canvas(this);
|
||||
this->_layout->addWidget(this->_canvas, 1, 0);
|
||||
|
||||
this->_layout->setColumnStretch(0, 1);
|
||||
this->_layout->setRowStretch(1, 1);
|
||||
}
|
||||
|
||||
void Canvas::keyPressEvent(QKeyEvent *event) {
|
||||
emit this->key_pressed(static_cast<Qt::Key>(event->key()));
|
||||
std::cout << "key pressed" << std::endl;
|
||||
}
|
||||
|
||||
void Canvas::mousePressEvent(QMouseEvent *event) {
|
||||
this->_mouse_processing.is_pressed = true;
|
||||
this->_mouse_processing.pressed_at = event->pos();
|
||||
this->_mouse_processing.is_moved_while_pressed = false;
|
||||
std::cout << "mouse press" << std::endl;
|
||||
}
|
||||
|
||||
void Canvas::mouseMoveEvent(QMouseEvent *event) {
|
||||
if (this->_mouse_processing.is_pressed) {
|
||||
this->_mouse_processing.is_moved_while_pressed = true;
|
||||
emit this->pressed_mouse_moved(event->pos());
|
||||
} else {
|
||||
emit this->pressed_mouse_moved(event->pos());
|
||||
}
|
||||
std::cout << "mouse move" << std::endl;
|
||||
}
|
||||
|
||||
void Canvas::mouseReleaseEvent(QMouseEvent *event) {
|
||||
this->_mouse_processing.is_pressed = false;
|
||||
if (this->_mouse_processing.is_moved_while_pressed) {
|
||||
emit this->mouse_dragged(this->_mouse_processing.pressed_at, event->pos());
|
||||
} else {
|
||||
emit this->mouse_clicked(event->pos());
|
||||
}
|
||||
std::cout << "mouse release" << std::endl;
|
||||
}
|
||||
|
107
src/ui.hpp
107
src/ui.hpp
@ -1,107 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QSize>
|
||||
#include <QResizeEvent>
|
||||
#include <QMutex>
|
||||
#include <QMainWindow>
|
||||
|
||||
|
||||
#include "frame.hpp"
|
||||
|
||||
class StatusBar : public QWidget {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QGridLayout *_layout;
|
||||
|
||||
QLabel *_scale_label;
|
||||
static const QString _scale_label_template;
|
||||
|
||||
QLabel *_painter_label;
|
||||
static const QString _painter_label_template;
|
||||
|
||||
struct {
|
||||
QLabel *title;
|
||||
QLabel *x;
|
||||
QLabel *y;
|
||||
} _screen_coordinates, _scaled_coordinates;
|
||||
static const QString _x_template, _y_template;
|
||||
|
||||
|
||||
public:
|
||||
explicit StatusBar(QWidget *parent);
|
||||
|
||||
public slots:
|
||||
|
||||
void set_coordinates(unsigned screen_x, unsigned screen_y, unsigned scaled_x, unsigned scaled_y);
|
||||
|
||||
void set_scale(unsigned current_scale);
|
||||
|
||||
void set_painter_index(unsigned index, unsigned painters_count);
|
||||
};
|
||||
|
||||
class Canvas : public QWidget {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QMutex _sync;
|
||||
QImage _current_frame;
|
||||
|
||||
public:
|
||||
explicit Canvas(QWidget *parent);
|
||||
|
||||
public slots:
|
||||
|
||||
void set_frame(QImage &f);
|
||||
|
||||
public:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
signals:
|
||||
|
||||
void resized(QSize new_size);
|
||||
|
||||
|
||||
private:
|
||||
struct {
|
||||
bool is_pressed;
|
||||
QPoint pressed_at;
|
||||
bool is_moved_while_pressed;
|
||||
} _mouse_processing;
|
||||
public:
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
signals:
|
||||
|
||||
void key_pressed(Qt::Key key);
|
||||
|
||||
void released_mouse_moved(QPoint to);
|
||||
|
||||
void pressed_mouse_moved(QPoint to);
|
||||
|
||||
void mouse_clicked(QPoint where);
|
||||
|
||||
void mouse_dragged(QPoint from, QPoint to);
|
||||
|
||||
};
|
||||
|
||||
class MainWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QGridLayout *_layout;
|
||||
public:
|
||||
StatusBar *_status_bar;
|
||||
Canvas *_canvas;
|
||||
|
||||
MainWindow();
|
||||
};
|
Loading…
Reference in New Issue
Block a user