diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b2eb66..e4d5a07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,4 +12,5 @@ add_executable( src/Frame.h src/main.cpp src/Painter.h + src/shaders.cpp ) \ No newline at end of file diff --git a/src/shaders.cpp b/src/shaders.cpp new file mode 100644 index 0000000..b767303 --- /dev/null +++ b/src/shaders.cpp @@ -0,0 +1,160 @@ +#include "Painter.h" + +template +void Triangle(float x0, float y0, float x1, float y1, float x2, float y2, COLOR color, ShaderClass &shader) +{ +// Отсортируем точки таким образом, чтобы выполнилось условие: y0 < y1 < y2 + if (y1 < y0) + { + swap(y1, y0); + swap(x1, x0); + } + if (y2 < y1) + { + swap(y2, y1); + swap(x2, x1); + } + if (y1 < y0) + { + swap(y1, y0); + swap(x1, x0); + } +// Определяем номера строк пикселей, в которых располагаются точки треугольника + int Y0 = (int) (y0 + 0.5f); + int Y1 = (int) (y1 + 0.5f); + int Y2 = (int) (y2 + 0.5f); +// Отсечение невидимой части треугольника + if (Y0 < 0) Y0 = 0; + else if (Y0 >= height) Y0 = height; + if (Y1 < 0) Y1 = 0; + else if (Y1 >= height) Y1 = height; + if (Y2 < 0) Y2 = 0; + else if (Y2 >= height) Y2 = height; +// Рисование верхней части треугольника + for (float y = Y0 + 0.5f; y < Y1; y++) + { + int X0 = (int) ((y - y0) / (y1 - y0) * (x1 - x0) + x0 + 0.5f); + int X1 = (int) ((y - y0) / (y2 - y0) * (x2 - x0) + x0 + 0.5f); + if (X0 > X1) swap(X0, X1); + if (X0 < 0) X0 = 0; + if (X1 > width) X1 = width; + for (int x = X0; x < X1; x++) + { +// f(x + 0.5, y) + SetPixel(x, y, shader.getColor(x + 0.5f, y)); + } + } +// Рисование нижней части треугольника + for (float y = Y1 + 0.5f; y < Y2; y++) + { + int X0 = (int)((y - y1) / (y2 - y1) * (x2 - x1) + x1 + 0.5f); + int X1 = (int)((y - y0) / (y2 - y0) * (x2 - x0) + x0 + 0.5f); + if (X0 > X1) swap(X0, X1); + if (X0 < 0) X0 = 0; + if (X1 > width) X1 = width; + for (int x = X0; x < X1; x++) + { +// f(x + 0.5, y) + SetPixel(x, y, shader.getColor(x + 0.5f, y)); + } + } +} + +class BarycentricInterpolator +{ + float x0, y0, x1, y1, x2, y2, S; + COLOR C0, C1, C2; +public: + BarycentricInterpolator(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 getColor(float x, float y) + { +// Барицентрическая интерполяция + 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); + } +}; + + +class RadialBrush +{ + float cx, cy; // Центр прямоугольника + COLOR C0, C1; // Цвета радиальной заливки + float angle; // Начальный угол заливки +public: + RadialBrush (float _x0, float _y0, float _x1, float _y1, COLOR A0, COLOR A1, float + _angle) : + cx((_x0 + _x1) / 2.0f), cy((_y0 + _y1)/ 2.0f), + C0(A0), C1(A1), angle(_angle) + { + } + COLOR getColor(float x, float y) + { + double dx = (double)x - cx, dy = (double)y - cy; + double radius = sqrt(dx*dx + dy*dy); + float h0 = (sin(radius / 10 + angle) + 1.0f) / 2; + float h1 = 1 - h0; + float r = h0 * C0.RED + h1 * C1.RED; + float g = h0 * C0.GREEN + h1 * C1.GREEN; + float b = h0 * C0.BLUE + h1 * C1.BLUE; + return COLOR(r, g, b); + } +}; + +void ColorFromHSV(double hue, double saturation, double value, GLint *color) +{ + int hi = int(floor(hue / 60)) % 6; + double f = hue / 60 - floor(hue / 60); + value = value * 255; + int v = (int)(value); + int p = (int)(value * (1 - saturation)); + int q = (int)(value * (1 - f * saturation)); + int t = (int)(value * (1 - (1 - f) * saturation)); + if (hi == 0) + { + color[0] = v; + color[1] = t; + color[2] = p; + } + else if (hi == 1) + { + color[0] = q; + color[1] = v; + color[2] = p; + } + else if (hi == 2) + { + color[0] = p; + color[1] = v; + color[2] = t; + } + else if (hi == 3) + { + color[0] = p; + color[1] = q; + color[2] = v; + } + else if (hi == 4) + { + color[0] = t; + color[1] = p; + color[2] = v; + } + else + { + color[0] = v; + color[1] = p; + color[2] = q; + } +}