computer-graphics-0/src/drawing_assets.hpp

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);