179 lines
4.8 KiB
C++
179 lines
4.8 KiB
C++
#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); |