Utility classes and functions for comfortable drawing
This commit is contained in:
parent
e9da9c920f
commit
282ad80e46
@ -1,3 +1,4 @@
|
|||||||
|
#include <varargs.h>
|
||||||
#include "frame.hpp"
|
#include "frame.hpp"
|
||||||
#include "drawing_assets.hpp"
|
#include "drawing_assets.hpp"
|
||||||
|
|
||||||
|
@ -1,8 +1,117 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "frame.hpp"
|
#include "frame.hpp"
|
||||||
|
|
||||||
void draw_circle(Frame *frame, int cx, int cy, int radius, COLOR outline);
|
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -15,38 +15,60 @@ struct COLOR {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 {
|
class Frame {
|
||||||
COLOR *pixels;
|
COLOR *pixels;
|
||||||
public:
|
public:
|
||||||
const int width, height;
|
const int width, height;
|
||||||
|
|
||||||
Frame(int _width, int _height) : width{_width}, height{_height} {
|
inline Frame(int _width, int _height) : width{_width}, height{_height} {
|
||||||
int size = width * height;
|
int size = width * height;
|
||||||
|
|
||||||
this->pixels = new COLOR[size];
|
this->pixels = new COLOR[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] COLOR _get_pixel(int x, int y) const {
|
[[nodiscard]]inline COLOR _get_pixel(int x, int y) const {
|
||||||
return this->pixels[y * this->width + x];
|
return this->pixels[y * this->width + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] COLOR &_get_pixel(int x, int y) {
|
[[nodiscard]] inline COLOR &_get_pixel(int x, int y) {
|
||||||
return this->pixels[y * this->width + x];
|
return this->pixels[y * this->width + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_pixel(int x, int y, COLOR color) {
|
inline void set_pixel(int x, int y, COLOR color) {
|
||||||
this->_get_pixel(x, y) = color;
|
this->_get_pixel(x, y) = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] COLOR get_pixel(int x, int y) const {
|
[[nodiscard]] inline COLOR get_pixel(int x, int y) const {
|
||||||
return this->_get_pixel(x, y);
|
return this->_get_pixel(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
~Frame() {
|
inline ~Frame() {
|
||||||
delete[]this->pixels;
|
delete[]this->pixels;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,9 +5,8 @@
|
|||||||
|
|
||||||
|
|
||||||
class DemoPainter : public Painter {
|
class DemoPainter : public Painter {
|
||||||
|
public:
|
||||||
void draw(PainterState *state, Frame *frame) const override {
|
void draw(PainterState *state, Frame *frame) const override {
|
||||||
|
|
||||||
int W = frame->width, H = frame->height;
|
int W = frame->width, H = frame->height;
|
||||||
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
|
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
|
||||||
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1) / sqrt(2);
|
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1) / sqrt(2);
|
||||||
@ -15,36 +14,19 @@ class DemoPainter : public Painter {
|
|||||||
float angle = state->angle; // Угол поворота
|
float angle = state->angle; // Угол поворота
|
||||||
a = a / 2;
|
a = a / 2;
|
||||||
|
|
||||||
// Инициализируем исходные координаты центра и вершин квадрата
|
Point center{W / 2, H / 2};
|
||||||
struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
} C = {(float) W / 2, (float) H / 2}, A[4] = {{C.x + a, C.y + a},
|
|
||||||
{C.x + a, C.y - a},
|
|
||||||
{C.x - a, C.y - a},
|
|
||||||
{C.x - a, C.y + a}};
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
// Поворачиваем все вершины квадрата вокруг точки C на угол angle
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
float xi = A[i].x, yi = A[i].y;
|
|
||||||
A[i].x = (xi - C.x) * cos(angle) - (yi - C.y) * sin(angle) + C.x;
|
|
||||||
A[i].y = (xi - C.x) * sin(angle) + (yi - C.y) * cos(angle) + C.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Рисуем стороны квадрата
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
int i2 = (i + 1) % 4;
|
|
||||||
draw_line(
|
|
||||||
frame,
|
|
||||||
int(A[i].x + 0.5f),
|
|
||||||
int(A[i].y + 0.5f),
|
|
||||||
int(A[i2].x + 0.5f),
|
|
||||||
int(A[i2].y + 0.5f), COLOR(200, 30, 45));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Рисуем описанную окружность
|
// Рисуем описанную окружность
|
||||||
draw_circle(frame, (int) C.x, (int) C.y, int(a * sqrt(2) + 0.5f), COLOR(100, 100, 250));
|
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 &&
|
if (state->clicked_pixel.x >= 0 && state->clicked_pixel.x < W &&
|
||||||
|
Loading…
Reference in New Issue
Block a user