Utility classes and functions for comfortable drawing

This commit is contained in:
Andrew Golovashevich 2024-10-09 16:07:39 +03:00
parent e9da9c920f
commit 282ad80e46
4 changed files with 148 additions and 34 deletions

View File

@ -1,3 +1,4 @@
#include <varargs.h>
#include "frame.hpp"
#include "drawing_assets.hpp"

View File

@ -1,8 +1,117 @@
#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);
}
}

View File

@ -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 {
COLOR *pixels;
public:
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;
this->pixels = new COLOR[size];
}
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];
}
[[nodiscard]] COLOR &_get_pixel(int x, int y) {
[[nodiscard]] inline COLOR &_get_pixel(int x, int y) {
return this->pixels[y * this->width + x];
}
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;
}
[[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);
}
~Frame() {
inline ~Frame() {
delete[]this->pixels;
}
};

View File

@ -5,9 +5,8 @@
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);
@ -15,36 +14,19 @@ class DemoPainter : public Painter {
float angle = state->angle; // Угол поворота
a = a / 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}};
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)
);
// Поворачиваем все вершины квадрата вокруг точки 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 &&