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 "drawing_assets.hpp"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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 &&
|
||||
|
Loading…
Reference in New Issue
Block a user