#pragma once #include #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 struct draw_polyline_ { template friend void draw_polyline(Frame *frame, COLOR color, point_t ...points); template friend struct draw_polyline_; private: }; template struct draw_polyline_ { template friend void draw_polyline(Frame *frame, COLOR color, point_t ...points); template friend struct draw_polyline_; private: static_assert(std::is_same_v); static_assert(std::is_same_v); static void draw(Frame *frame, COLOR color, p0_t p0, p1_t p1, pp_t ...points) { draw_line(frame, p0, p1, color); draw_polyline_::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_::last(p1, points...); } }; template struct draw_polyline_ { template friend void draw_polyline(Frame *frame, COLOR color, point_t ...points); template friend struct draw_polyline_; private: static_assert(std::is_same_v); 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 friend void draw_polyline(Frame *frame, COLOR color, point_t ...points); template 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 void draw_polyline(Frame *frame, COLOR color, point_t ...points) { if constexpr (!draw_polyline_::HAS_ANY) {} else { draw_polyline_::draw(frame, color, points...); draw_line(frame, draw_polyline_::last(points...), draw_polyline_::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);