diff --git a/programs/labs1_5/src/main.cpp b/programs/labs1_5/src/main.cpp index 6ade92b..6b76317 100644 --- a/programs/labs1_5/src/main.cpp +++ b/programs/labs1_5/src/main.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -77,12 +78,19 @@ namespace BGTU::ComputerGraphicsLabWork::Impl { return 0; #else + for (int y = 3; y >= -3; y--) { + for (int x = -3; x <= 3; x++) { +// if (x != 0) { + std::cout /*<< '(' << y << ',' << x << '|' << (double)y / (double)x << '|'*/ << std::atan2((double) y , (double) x) / std::numbers::pi_v * 360 << "\t "; +// } + } + std::cout << std::endl; + } +// auto c = Utilities::apply_transparent_color(*(RendererApi::Color *) &bg, fg); +// std::cout << c.red << c.green << c.blue << std::endl; - auto c = Utilities::apply_transparent_color(*(RendererApi::Color*)&bg, fg); - std::cout << c.red << c.green << c.blue << std::endl; - - return 0; + return 0; #endif } } diff --git a/programs/labs1_5/src/variants/lab2/variant3.cpp b/programs/labs1_5/src/variants/lab2/variant3.cpp index 15e28d2..a58c6e3 100644 --- a/programs/labs1_5/src/variants/lab2/variant3.cpp +++ b/programs/labs1_5/src/variants/lab2/variant3.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -9,7 +11,51 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { template class Circle : public RendererApi::Sprite> { private: - QMutex sync; + template + class RadialShader : public Utilities::Shader { + private: + RendererApi::PointF<2>::component_t cx, cy; + RendererApi::PointF<2>::component_t radius; + public: + RadialShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, RendererApi::PointF<2>::component_t radius) : cx{cx}, cy{cy}, radius{radius} {} + + RadialShader(RendererApi::PointF<2> c, RendererApi::PointF<2>::component_t radius) : cx{c.x}, cy{c.y}, radius{radius} {} + + RadialShader(RendererApi::PointI<2> c, RendererApi::PointF<2>::component_t radius) : cx{(double) c.x}, cy{(double) c.y}, radius{radius} {} + + [[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final { + RendererApi::PointF<2>::component_t distance = std::hypot(x - this->cx, y - this->cy); + double ratio = distance / this->radius; + float c1v; + + if (ratio < 0.5) { + c1v = (float) (std::fabs(ratio - 0.25) * 4); + } else if (ratio < 1.0) { + c1v = (float) (std::fabs(ratio - 0.75) * 4); + } else { + return c1; + } + + return Utilities::colors_gradient(c1, c1v, c2); + } + }; + + class HsvSectorShader : public Utilities::Shader { + private: + RendererApi::PointF<2>::component_t cx, cy; + double angle_offset_radians; + public: + HsvSectorShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, double angle_offset_radians) : cx{cx}, cy{cy}, angle_offset_radians{angle_offset_radians} {} + + HsvSectorShader(RendererApi::PointF<2> c, double angle_offset_radians) : cx{c.x}, cy{c.y}, angle_offset_radians{angle_offset_radians} {} + + HsvSectorShader(RendererApi::PointI<2> c, double angle_offset_radians) : cx{(double) c.x}, cy{(double) c.y}, angle_offset_radians{angle_offset_radians} {} + + [[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final { + double angle = std::atan2(static_cast(y - this->cy), static_cast(x - this->cx)) + this->angle_offset_radians; + return Utilities::hsv_to_rgb_360_1_1(std::fmod(std::fmod(angle / std::numbers::pi_v * 180, 360.0) + 360, 360.0), 1.0, 1.0); + } + }; enum class ShaderType : unsigned { SOLID_RED, @@ -29,8 +75,31 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { SECTOR_ROTATED_NEG, }; + static inline ShaderType const next_shader_type[] = { + ShaderType::SOLID_GREEN, + ShaderType::SOLID_BLUE, + ShaderType::RADIAL_DARK_RED, + ShaderType::RADIAL_DARK_GREEN, + ShaderType::RADIAL_DARK_BLUE, + ShaderType::RADIAL_LIGHT_RED, + ShaderType::RADIAL_LIGHT_GREEN, + ShaderType::RADIAL_LIGHT_BLUE, + ShaderType::RADIAL_TRANSPARENT_RED, + ShaderType::RADIAL_TRANSPARENT_GREEN, + ShaderType::RADIAL_TRANSPARENT_BLUE, + ShaderType::SECTOR_STATIC, + ShaderType::SECTOR_ROTATED_POS, + ShaderType::SECTOR_ROTATED_NEG, + ShaderType::SOLID_RED + }; + + QMutex sync; ShaderType current_shader; + RendererApi::PointI<2> center(SpriteData::ShapeData const *data) const { + return data->pos_rotated(data->radius * center_distance_multiplier, center_angle_degrees); + } + template void _select_shader(SpriteData::ShapeData const *data, receiver_t receiver) const { const_cast(&(this->sync))->lock(); @@ -52,45 +121,73 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { receiver(s); return; } - case ShaderType::RADIAL_DARK_RED: - case ShaderType::RADIAL_DARK_GREEN: - case ShaderType::RADIAL_DARK_BLUE: - case ShaderType::RADIAL_LIGHT_RED: - case ShaderType::RADIAL_LIGHT_GREEN: - case ShaderType::RADIAL_LIGHT_BLUE: - case ShaderType::RADIAL_TRANSPARENT_RED: - case ShaderType::RADIAL_TRANSPARENT_GREEN: - case ShaderType::RADIAL_TRANSPARENT_BLUE: - case ShaderType::SECTOR_STATIC: - case ShaderType::SECTOR_ROTATED_POS: - case ShaderType::SECTOR_ROTATED_NEG:; + case ShaderType::RADIAL_DARK_RED: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_DARK_GREEN: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_DARK_BLUE: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_LIGHT_RED: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_LIGHT_GREEN: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_LIGHT_BLUE: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_TRANSPARENT_RED: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_TRANSPARENT_GREEN: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::RADIAL_TRANSPARENT_BLUE: { + RadialShader s{this->center(data), data->radius * radius_multiplier - 1}; + receiver(s); + return; + } + case ShaderType::SECTOR_STATIC: { + HsvSectorShader s{this->center(data), 0}; + receiver(s); + return; + } + case ShaderType::SECTOR_ROTATED_POS: { + HsvSectorShader s{this->center(data), data->rotation_radians}; + receiver(s); + return; + } + case ShaderType::SECTOR_ROTATED_NEG: { + HsvSectorShader s{this->center(data), -data->rotation_radians}; + receiver(s); + return; + } } }; - - - static inline ShaderType const next_shader_type[] = { - ShaderType::SOLID_GREEN, - ShaderType::SOLID_BLUE, - ShaderType::RADIAL_DARK_RED, - ShaderType::RADIAL_DARK_GREEN, - ShaderType::RADIAL_DARK_BLUE, - ShaderType::RADIAL_LIGHT_RED, - ShaderType::RADIAL_LIGHT_GREEN, - ShaderType::RADIAL_LIGHT_BLUE, - ShaderType::RADIAL_TRANSPARENT_RED, - ShaderType::RADIAL_TRANSPARENT_GREEN, - ShaderType::RADIAL_TRANSPARENT_BLUE, - ShaderType::SECTOR_STATIC, - ShaderType::SECTOR_ROTATED_POS, - ShaderType::SECTOR_ROTATED_NEG, - ShaderType::SOLID_RED - }; - public: Circle() : sync{}, current_shader{ShaderType::SOLID_RED} {} - Circle(Circle &&other) : sync{}, current_shader{other.current_shader} { + Circle(Circle &&other) noexcept: sync{}, current_shader{other.current_shader} { } @@ -99,7 +196,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { data, [&](shader_t const &shader) { Utilities::Shapes::iterate_circle_fill( - data->pos_rotated(data->radius * center_distance_multiplier, center_angle_degrees), + this->center(data), data->radius * radius_multiplier, [&](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) { if (is_edge) { @@ -115,7 +212,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { void clicked() final { this->sync.lock(); - this->current_shader = next_shader_type[(unsigned)this->current_shader]; + this->current_shader = next_shader_type[(unsigned) this->current_shader]; this->sync.unlock(); } }; diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp index 3cb33a1..ff7f3be 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -24,8 +25,8 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { const float neg_alpha_f = 255.f - alpha_f; // mulps - const float bg_alpha[4]{bg_f[0] * neg_alpha_f, bg_f[1] * neg_alpha_f, bg_f[1] * neg_alpha_f}; - const float fg_alpha[4]{fg_f[0] * alpha_f, fg_f[1] * alpha_f, fg_f[1] * alpha_f}; + const float bg_alpha[4]{bg_f[0] * neg_alpha_f, bg_f[1] * neg_alpha_f, bg_f[2] * neg_alpha_f}; + const float fg_alpha[4]{fg_f[0] * alpha_f, fg_f[1] * alpha_f, fg_f[2] * alpha_f}; // addps const float sum_f[4]{bg_alpha[0] + fg_alpha[0], bg_alpha[1] + fg_alpha[1], bg_alpha[2] + fg_alpha[2]}; @@ -185,4 +186,88 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { buffer[offset + 2] = color.red; } } + + constexpr RendererApi::Color::Transparent colors_gradient(RendererApi::Color::Transparent c1, float c1v, RendererApi::Color::Transparent c2) { + // pmovzxbd + const std::uint_fast32_t c1_i32[4]{c1.red, c1.green, c1.blue, c1.alpha}; + const std::uint_fast32_t c2_i32[4]{c2.red, c2.green, c2.blue, c2.alpha}; + + // cvtdq2pd + const float c1_f[4]{(float) c1_i32[0], (float) c1_i32[1], (float) c1_i32[2], (float) c1_i32[3]}; + const float c2_f[4]{(float) c2_i32[0], (float) c2_i32[1], (float) c2_i32[2], (float) c2_i32[3]}; + + float c2v = 1 - c1v; + + // mulps + const float c1_part[4]{c1_f[0] * c1v, c1_f[1] * c1v, c1_f[2] * c1v, c1_f[3] * c1v}; + const float c2_part[4]{c2_f[0] * c2v, c2_f[1] * c2v, c2_f[2] * c2v, c2_f[3] * c2v}; + + // addps + const float sum_f[4]{c1_part[0] + c2_part[0], c1_part[1] + c2_part[1], c1_part[2] + c2_part[2], c1_part[3] + c2_part[3]}; + + return { + (RendererApi::Color::component_compact_t) sum_f[0], + (RendererApi::Color::component_compact_t) sum_f[1], + (RendererApi::Color::component_compact_t) sum_f[2], + (RendererApi::Color::component_compact_t) sum_f[3], + }; + } + + constexpr RendererApi::Color::Transparent colors_gradient(RendererApi::Color::Transparent c1, float c1v, RendererApi::Color::Transparent c2, float c2v, RendererApi::Color::Transparent c3) { + // pmovzxbd + const std::uint_fast32_t c1_i32[4]{c1.red, c1.green, c1.blue, c1.alpha}; + const std::uint_fast32_t c2_i32[4]{c2.red, c2.green, c2.blue, c2.alpha}; + const std::uint_fast32_t c3_i32[4]{c3.red, c3.green, c3.blue, c3.alpha}; + + // cvtdq2pd + const float c1_f[4]{(float) c1_i32[0], (float) c1_i32[1], (float) c1_i32[2], (float) c1_i32[3]}; + const float c2_f[4]{(float) c2_i32[0], (float) c2_i32[1], (float) c2_i32[2], (float) c2_i32[3]}; + const float c3_f[4]{(float) c3_i32[0], (float) c3_i32[1], (float) c3_i32[2], (float) c3_i32[3]}; + + float c3v = 1 - c1v - c2v; + + // mulps + const float c1_part[4]{c1_f[0] * c1v, c1_f[1] * c1v, c1_f[2] * c1v, c1_f[3] * c1v}; + const float c2_part[4]{c2_f[0] * c2v, c2_f[1] * c2v, c2_f[2] * c2v, c2_f[3] * c2v}; + const float c3_part[4]{c3_f[0] * c3v, c3_f[1] * c3v, c3_f[2] * c3v, c3_f[3] * c3v}; + + // addps + const float sum_f[4]{ + c1_part[0] + c2_part[0] + c3_part[0], + c1_part[1] + c2_part[1] + c3_part[1], + c1_part[2] + c2_part[2] + c3_part[2], + c1_part[3] + c2_part[3] + c3_part[3] + }; + + return { + (RendererApi::Color::component_compact_t) sum_f[0], + (RendererApi::Color::component_compact_t) sum_f[1], + (RendererApi::Color::component_compact_t) sum_f[2], + (RendererApi::Color::component_compact_t) sum_f[3], + }; + } + + [[deprecated]] inline RendererApi::Color hsv_to_rgb_360_1_1(double hue, double saturation, double value) { + int hi = int(std::floor(hue / 60)) % 6; + double f = hue / 60 - std::floor(hue / 60); + value = value * 255; + const auto v = (RendererApi::Color::component_fast_t) (value); + const auto p = (RendererApi::Color::component_fast_t) (value * (1 - saturation)); + const auto q = (RendererApi::Color::component_fast_t) (value * (1 - f * saturation)); + const auto t = (RendererApi::Color::component_fast_t) (value * (1 - (1 - f) * saturation)); + switch (hi) { + case 0: + return {v, t, p}; + case 1: + return {q, v, p}; + case 2: + return {p, v, t}; + case 3: + return {p, q, v}; + case 4: + return {t, p, v}; + default: + return {v, p, q}; + } + } } \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp index 931335f..29961c9 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp @@ -20,7 +20,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { RendererApi::PointI<2>::component_t x = 0, y = r; RendererApi::PointI<2>::component_t last_y = r + 1; RendererApi::PointI<2>::component_t _r2 = r * r; - while (x < y) { + while (true) { RendererApi::PointI<2>::component_t _x2 = x * x; RendererApi::PointI<2>::component_t _y_1 = y - 1; RendererApi::PointI<2>::component_t D1 = _x2 + y * y - _r2; @@ -29,6 +29,19 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { if (D1 > -D2) y--; + if (x == y) { + edge_point_receiver(cx - x, cy + y); + fill_line_receiver(cy + y, cx - x + 1, cx + x); + edge_point_receiver(cx + x, cy + y); + + edge_point_receiver(cx - x, cy - y); + fill_line_receiver(cy - y, cx - x + 1, cx + x); + edge_point_receiver(cx + x, cy - y); + break; + } else if (x > y) { + break; + } + if (y < last_y) { edge_point_receiver(cx - x, cy + y); fill_line_receiver(cy + y, cx - x + 1, cx + x);