From 737cb2a23cd146d563b4958de90f47fb9b1de9c3 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Mon, 10 Mar 2025 17:53:08 +0300 Subject: [PATCH] Lab5 impl without sorting --- CMakeLists.txt | 3 +- programs/lab3/src/sprite_data.hpp | 8 +- programs/lab5/CMakeLists.txt | 10 ++ programs/lab5/src/main.cpp | 82 +++++++++++ programs/lab5/src/model.cpp | 95 +++++++++++++ programs/lab5/src/model.hpp | 11 ++ programs/lab5/src/sprite_data.hpp | 127 ++++++++++++++++++ programs/lab5/src/triangle.hpp | 83 ++++++++++++ .../labs1_2/src/variants/lab2/variant3.cpp | 18 +-- .../qt_utilities/keyboard_catcher_widget.hpp | 4 + .../utilities/color.hpp | 2 +- .../utilities/shader.hpp | 46 +++++++ .../utilities/shapes/triangle.hpp | 23 ++-- 13 files changed, 483 insertions(+), 29 deletions(-) create mode 100644 programs/lab5/CMakeLists.txt create mode 100644 programs/lab5/src/main.cpp create mode 100644 programs/lab5/src/model.cpp create mode 100644 programs/lab5/src/model.hpp create mode 100644 programs/lab5/src/sprite_data.hpp create mode 100644 programs/lab5/src/triangle.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bb7050..bd63b30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,4 +21,5 @@ add_subdirectory(utilities) add_subdirectory(qt-utilities) add_subdirectory(programs/labs1_2) add_subdirectory(programs/lab3) -add_subdirectory(programs/lab4) \ No newline at end of file +add_subdirectory(programs/lab4) +add_subdirectory(programs/lab5) \ No newline at end of file diff --git a/programs/lab3/src/sprite_data.hpp b/programs/lab3/src/sprite_data.hpp index d7ca829..b18cddf 100644 --- a/programs/lab3/src/sprite_data.hpp +++ b/programs/lab3/src/sprite_data.hpp @@ -15,7 +15,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl { - class _Lab3SpriteData_Provider; + class _Lab5SpriteData_Provider; struct SpriteData { @@ -25,11 +25,11 @@ namespace BGTU::ComputerGraphicsLabWork::Impl { Utilities::Matrix3d planets_transform[9]; Utilities::Matrix3d stars_transform; double time_ms; - using Provider = _Lab3SpriteData_Provider; + using Provider = _Lab5SpriteData_Provider; }; - class _Lab3SpriteData_Provider : public QObject, public RendererApi::Sprite::SpriteDataProvider { + class _Lab5SpriteData_Provider : public QObject, public RendererApi::Sprite::SpriteDataProvider { Q_OBJECT private: QMutex sync; @@ -37,7 +37,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl { RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t w, h; public: - explicit _Lab3SpriteData_Provider(double radians_per_second) : + explicit _Lab5SpriteData_Provider(double radians_per_second) : sync{}, time{}, w{0}, h{0} {} diff --git a/programs/lab5/CMakeLists.txt b/programs/lab5/CMakeLists.txt new file mode 100644 index 0000000..6ffdf65 --- /dev/null +++ b/programs/lab5/CMakeLists.txt @@ -0,0 +1,10 @@ +add_executable( + lab5 + + src/main.cpp + src/sprite_data.hpp + src/model.cpp + src/triangle.hpp + +) +target_link_libraries(lab5 PRIVATE Qt5::Core Qt5::Widgets renderer_api utilities qt_utilities) \ No newline at end of file diff --git a/programs/lab5/src/main.cpp b/programs/lab5/src/main.cpp new file mode 100644 index 0000000..a49c247 --- /dev/null +++ b/programs/lab5/src/main.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sprite_data.hpp" +#include "model.hpp" + +namespace BGTU::ComputerGraphicsLabWork::Impl { + int main(int argc, char **argv) { +#if 1 + QApplication qApplication{argc, argv}; + + SpriteData::Provider sprites_data_custom{0.1, 0.1, 10}; + + QMainWindow w{}; + + + QtUtilities::KeyboardCatcherWidget kbd{&w}; + + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_Left, &sprites_data_custom, &SpriteData::Provider::dec_y_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_Right, &sprites_data_custom, &SpriteData::Provider::inc_y_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_Down, &sprites_data_custom, &SpriteData::Provider::dec_x_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_Up, &sprites_data_custom, &SpriteData::Provider::inc_x_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_A, &sprites_data_custom, &SpriteData::Provider::dec_y_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_D, &sprites_data_custom, &SpriteData::Provider::inc_y_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_S, &sprites_data_custom, &SpriteData::Provider::dec_x_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_W, &sprites_data_custom, &SpriteData::Provider::inc_x_angle); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_PageDown, &sprites_data_custom, &SpriteData::Provider::dec_scale); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_PageUp, &sprites_data_custom, &SpriteData::Provider::inc_scale); + QObject::connect(&kbd, &QtUtilities::KeyboardCatcherWidget::key_pressed_P, &sprites_data_custom, &SpriteData::Provider::switch_projection); + + + + QtUtilities::SeparateThreadedDefaultRendererLinear renderer_custom{}; + renderer_custom.set_sprite_data_provider(&sprites_data_custom); + renderer_custom.set_sprites(reinterpret_cast *const *>(sprites), sprites_count); + renderer_custom.set_background(BGTU::ComputerGraphicsLabWork::RendererApi::Color{0, 0, 0}); + + + QGridLayout layout{&kbd}; + kbd.setLayout(&layout); + QtUtilities::RendererWidget canvas_custom{&renderer_custom, &kbd}; + layout.addWidget(&canvas_custom, 0, 0); + QObject::connect(&canvas_custom, &QtUtilities::_RendererWidget_SignalSlots::resized, &sprites_data_custom, &SpriteData::Provider::set_frame_size); + + + w.setCentralWidget(&kbd); + w.show(); + + QApplication::exec(); + + return 0; +#else + auto x = Utilities::Matrix4d{5, 0, 0, 0, + 0, 5, 0, 0, + 0, 0, 0, 1, + 0, 0, -1, 0}; + + RendererApi::PointF<3> a{1, 1, 6}; + RendererApi::PointF<3> b = x * a; + + + return 0; +#endif + } +} + + +int main(int argc, char **argv) { + return BGTU::ComputerGraphicsLabWork::Impl::main(argc, argv); +} \ No newline at end of file diff --git a/programs/lab5/src/model.cpp b/programs/lab5/src/model.cpp new file mode 100644 index 0000000..3aa8a1f --- /dev/null +++ b/programs/lab5/src/model.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +#include "triangle.hpp" +#include "sprite_data.hpp" +#include "model.hpp" + +namespace BGTU::ComputerGraphicsLabWork::Impl { + namespace { + + Utilities::hsv_sector_shader hsv_shader{0, 0, 0}; + Utilities::MonoShader transparent_shader{{255, 255, 255, 127}}; + + class ChessBoardShader : public Utilities::Shader { + private: + double w, h; + + public: + ChessBoardShader(double w, double h) : w{w}, h{h} {} + + [[nodiscard]] RendererApi::Color::Transparent get_color(double x, double y) const override { + if (static_cast(std::floor(x / this->w) + std::floor(y / this->h)) % 2 == 0) + return {0, 0, 0, 255}; + else + return {255, 255, 255, 255}; + } + } chess_board_shader{0.125000000000, 0.125000000000}; + + + RendererApi::PointF<2> rot_n(double degrees, unsigned len) { + auto radians = degrees * std::numbers::pi_v / 180; + return {std::cos(radians) * len, std::sin(radians) * len}; + } + + Utilities::Shapes::triangle_barycentric_shader tri_shader_1{ + {0, 0}, RendererApi::Color{0, 0, 255}, + {1, 0}, RendererApi::Color{0, 255, 255}, + {0, 1}, RendererApi::Color{0, 255, 0} + }; + Utilities::Shapes::triangle_barycentric_shader tri_shader_2{ + {1, 1}, RendererApi::Color{255, 255, 0}, + {1, 0}, RendererApi::Color{0, 255, 255}, + {0, 1}, RendererApi::Color{0, 255, 0} + }; + + Triangle triangles[] = { + {{0, 1, 1}, {1, 1, 0}, {1, 0, 1}, rot_n(0, 1), rot_n(240, 1), rot_n(120, 1), &hsv_shader}, + {{-1, -1, 1}, {-1, 1, 1}, {0, 1, 1}, rot_n(60, 2), rot_n(0, 2), rot_n(0, 1), &hsv_shader}, + {{-1, -1, 1}, {1, 0, 1}, {0, 1, 1}, rot_n(60, 2), rot_n(120, 1), rot_n(0, 1), &hsv_shader}, + {{-1, -1, 1}, {1, 0, 1}, {1, -1, 1}, rot_n(60, 2), rot_n(120, 1), rot_n(120, 1), &hsv_shader}, + {{1, -1, -1}, {1, 1, -1}, {1, 1, 0}, rot_n(180, 2), rot_n(240, 2), rot_n(240, 1), &hsv_shader}, + {{1, -1, -1}, {1, 0, 1}, {1, 1, 0}, rot_n(180, 2), rot_n(120, 1), rot_n(240, 1), &hsv_shader}, + {{1, -1, -1}, {1, 0, 1}, {1, -1, 1}, rot_n(180, 2), rot_n(120, 1), rot_n(120, 2), &hsv_shader}, + {{-1, 1, -1}, {1, 1, -1}, {1, 1, 0}, rot_n(300, 2), rot_n(240, 2), rot_n(240, 1), &hsv_shader}, + {{-1, 1, -1}, {0, 1, 1}, {1, 1, 0}, rot_n(300, 2), rot_n(0, 1), rot_n(240, 1), &hsv_shader}, + {{-1, 1, -1}, {0, 1, 1}, {-1, 1, 1}, rot_n(300, 2), rot_n(0, 1), rot_n(0, 2), &hsv_shader}, + {{-1, -1, 1}, {-1, -1, -1}, {-1, 1, 1}, {0, 0}, {0, 1}, {1, 0}, &chess_board_shader, false}, + {{-1, 1, -1}, {-1, -1, -1}, {-1, 1, 1}, {1, 1}, {0, 1}, {1, 0}, &chess_board_shader, false}, + {{-1, -1, -1}, {-1, 1, -1}, {1, 1, -1}, {0, 0}, {0, 1}, {1, 1}, &transparent_shader}, + {{-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {0, 0}, {1, 0}, {1, 1}, &transparent_shader}, + {{1, -1, 1}, {-1, -1, 1}, {1, -1, -1}, {0, 0}, {0, 1}, {1, 0}, &tri_shader_1}, + {{-1, -1, -1}, {-1, -1, 1}, {1, -1, -1}, {1, 1}, {0, 1}, {1, 0}, &tri_shader_2}, + }; + + Triangle *const _sprites[]{ + &triangles[0], + &triangles[1], + &triangles[2], + &triangles[3], + &triangles[4], + &triangles[5], + &triangles[6], + &triangles[7], + &triangles[8], + &triangles[9], + &triangles[10], + &triangles[11], + &triangles[12], + &triangles[13], + &triangles[14], + &triangles[15], + &triangles[16], + &triangles[17], + &triangles[18], + &triangles[19], + }; + } + + + Triangle *const *const sprites = _sprites; + std::size_t sprites_count = 16; +} diff --git a/programs/lab5/src/model.hpp b/programs/lab5/src/model.hpp new file mode 100644 index 0000000..ea6573b --- /dev/null +++ b/programs/lab5/src/model.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include "sprite_data.hpp" +#include "triangle.hpp" + +namespace BGTU::ComputerGraphicsLabWork::Impl { + extern Triangle *const *const sprites; + extern std::size_t sprites_count; +} \ No newline at end of file diff --git a/programs/lab5/src/sprite_data.hpp b/programs/lab5/src/sprite_data.hpp new file mode 100644 index 0000000..c8d4c46 --- /dev/null +++ b/programs/lab5/src/sprite_data.hpp @@ -0,0 +1,127 @@ +#pragma once + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace BGTU::ComputerGraphicsLabWork::Impl { + class _Lab5SpriteData_Provider; + + + struct SpriteData { + public: + using Provider = _Lab5SpriteData_Provider; + + Utilities::Matrix4d transform; + bool is_projection_enabled; + double x_radius; + double y_radius; + + explicit SpriteData(Utilities::Matrix4d transform, bool is_projection_enabled, double x_radius, double y_radius) : + transform{transform}, is_projection_enabled{is_projection_enabled}, x_radius{x_radius}, y_radius{y_radius} {} + + [[nodiscard]] inline RendererApi::PointI<2> project_point(RendererApi::PointF<3> p) const { + if (this->is_projection_enabled) + return {static_cast::component_t>((p.x - this->x_radius) / (p.z * (1 / this->x_radius) + 1) + this->x_radius), static_cast::component_t>((p.y - this->y_radius) / (p.z * (1 / this->y_radius) + 1) + this->y_radius)}; + else + return RendererApi::PointI<2>{static_cast::component_t>(p.x), static_cast::component_t>(p.y)}; + }; + }; + + + class _Lab5SpriteData_Provider : public QObject, public RendererApi::Sprite::SpriteDataProvider { + Q_OBJECT + private: + QMutex sync; + double x_angle; + double y_angle; + double scale; + + double x_angle_step; + double y_angle_step; + double scale_step; + bool is_projection_enabled; + + RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t w, h; + + public: + explicit _Lab5SpriteData_Provider( + double x_angle_step, + double y_angle_step, + double scale_step + ) : x_angle{0}, y_angle{0}, scale{1}, x_angle_step{x_angle_step}, y_angle_step{y_angle_step}, scale_step{scale_step}, + w{0}, h{0}, is_projection_enabled{false} {} + + SpriteData get_sprite_data() override { + this->sync.lock(); + double radius = (((this->w < this->h) ? this->w : this->h) * 7 / 16.0); + SpriteData cached{ + Utilities::Matrix4d::shift(0, 0, this->scale) * Utilities::Matrix4d::shift(this->w / 2, this->h / 2, radius * 2) * Utilities::Matrix4d::rotate_x(this->x_angle) * Utilities::Matrix4d::rotate_y(this->y_angle) * Utilities::Matrix4d::scale(radius), + this->is_projection_enabled, this->w * 7 / 16.0, this->h * 7 / 16.0, + }; + this->sync.unlock(); + return cached; + } + + public slots: + + void set_frame_size(RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t ww, RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t hh) { + this->sync.lock(); + this->w = ww; + this->h = hh; + this->sync.unlock(); + } + + void inc_x_angle() { + this->sync.lock(); + this->x_angle += this->x_angle_step; + this->sync.unlock(); + } + + void dec_x_angle() { + this->sync.lock(); + this->x_angle -= this->x_angle_step; + this->sync.unlock(); + } + + void inc_y_angle() { + this->sync.lock(); + this->y_angle += this->y_angle_step; + this->sync.unlock(); + } + + void dec_y_angle() { + this->sync.lock(); + this->y_angle -= this->y_angle_step; + this->sync.unlock(); + } + + void inc_scale() { + this->sync.lock(); + this->scale += this->scale_step; + this->sync.unlock(); + } + + void dec_scale() { + this->sync.lock(); + this->scale -= this->scale_step; + this->sync.unlock(); + } + + void switch_projection() { + this->sync.lock(); + this->is_projection_enabled = !this->is_projection_enabled; + this->sync.unlock(); + } + }; +} \ No newline at end of file diff --git a/programs/lab5/src/triangle.hpp b/programs/lab5/src/triangle.hpp new file mode 100644 index 0000000..31e1672 --- /dev/null +++ b/programs/lab5/src/triangle.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "sprite_data.hpp" + + +namespace BGTU::ComputerGraphicsLabWork::Impl { + class Triangle : public RendererApi::Sprite { + public: + const RendererApi::PointF<3> triangle_p0; + const RendererApi::PointF<3> triangle_p1; + const RendererApi::PointF<3> triangle_p2; + + private: + const RendererApi::PointF<2> shader_p0; + const RendererApi::PointF<2> shader_p1; + const RendererApi::PointF<2> shader_p2; + Utilities::Shader const *const shader; + bool apply_projection_to_shader; + + public: + Triangle( + RendererApi::PointF<3> triangle_p0, + RendererApi::PointF<3> triangle_p1, + RendererApi::PointF<3> triangle_p2, + RendererApi::PointF<2> shader_p0, + RendererApi::PointF<2> shader_p1, + RendererApi::PointF<2> shader_p2, + Utilities::Shader const *shader, + bool apply_projection_to_shader = true + ) : triangle_p0{triangle_p0}, triangle_p1{triangle_p1}, triangle_p2{triangle_p2}, + shader_p0{shader_p0}, shader_p1{shader_p1}, shader_p2{shader_p2}, shader{shader}, apply_projection_to_shader{apply_projection_to_shader} {} + + void draw(BGTU::ComputerGraphicsLabWork::RendererApi::VirtualVoxelPainter *frame, SpriteData const *data) const override { + auto ta = data->transform * this->triangle_p0; + auto tb = data->transform * this->triangle_p1; + auto tc = data->transform * this->triangle_p2; + + RendererApi::PointI<2> pa = data->project_point(ta); + RendererApi::PointI<2> pb = data->project_point(tb); + RendererApi::PointI<2> pc = data->project_point(tc); + + + if (this->apply_projection_to_shader) { + Utilities::Shapes::triangle_barycentric_interpolator> interpolator{ + static_cast>(pa), {this->shader_p0.x, this->shader_p0.y, ta.z}, + static_cast>(pb), {this->shader_p1.x, this->shader_p1.y, tb.z}, + static_cast>(pc), {this->shader_p2.x, this->shader_p2.y, tc.z}, + }; + + Utilities::Shapes::iterate_triangle_fill( + pa, pb, pc, + [&, this](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) { + RendererApi::PointF<3> _tmp = interpolator.interpolate_point(x, y); + frame->add_voxel(x, y, _tmp.z, this->shader->get_color(_tmp.x, _tmp.y)); + } + ); + } else { + Utilities::Shapes::triangle_barycentric_interpolator z_interpolator{ + static_cast>(pa), ta.z, + static_cast>(pb), tb.z, + static_cast>(pc), tc.z, + }; + Utilities::Shapes::triangle_barycentric_interpolator> shader_interpolator{ + {ta.x, ta.y}, this->shader_p0, + {tb.x, tb.y}, this->shader_p1, + {tc.x, tc.y}, this->shader_p2, + }; + Utilities::Shapes::iterate_triangle_fill( + pa, pb, pc, + [&, this](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) { + frame->add_voxel(x, y, z_interpolator.interpolate_point(x, y), this->shader->get_color(shader_interpolator.interpolate_point(x, y))); + } + ); + } + } + }; +} \ No newline at end of file diff --git a/programs/labs1_2/src/variants/lab2/variant3.cpp b/programs/labs1_2/src/variants/lab2/variant3.cpp index 6b4db6b..4107727 100644 --- a/programs/labs1_2/src/variants/lab2/variant3.cpp +++ b/programs/labs1_2/src/variants/lab2/variant3.cpp @@ -286,24 +286,18 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { } case ShaderType::BARYCENTRIC: { Utilities::Shapes::triangle_barycentric_shader s{ - data->pos_rotated_f(data->radius * radius_multiplier, -120.0), - data->pos_rotated_f(data->radius * radius_multiplier, 0.0), - data->pos_rotated_f(data->radius * radius_multiplier, 120.0), - RendererApi::Color{255, 0, 0}, - RendererApi::Color{0, 255, 0}, - RendererApi::Color{0, 0, 255} + data->pos_rotated_f(data->radius * radius_multiplier, -120.0), RendererApi::Color{255, 0, 0}, + data->pos_rotated_f(data->radius * radius_multiplier, 0.0), RendererApi::Color{0, 255, 0}, + data->pos_rotated_f(data->radius * radius_multiplier, 120.0), RendererApi::Color{0, 0, 255} }; receiver(s); return; } case ShaderType::BARYCENTRIC_SEMI_TRANSPARENT: { Utilities::Shapes::triangle_barycentric_shader s{ - data->pos_rotated_f(data->radius * radius_multiplier, -120.0), - data->pos_rotated_f(data->radius * radius_multiplier, 0.0), - data->pos_rotated_f(data->radius * radius_multiplier, 120.0), - RendererApi::Color::Transparent{255, 0, 0, 127}, - RendererApi::Color::Transparent{0, 255, 0, 127}, - RendererApi::Color::Transparent{0, 0, 255, 127} + data->pos_rotated_f(data->radius * radius_multiplier, -120.0), RendererApi::Color::Transparent{255, 0, 0, 127}, + data->pos_rotated_f(data->radius * radius_multiplier, 0.0), RendererApi::Color::Transparent{0, 255, 0, 127}, + data->pos_rotated_f(data->radius * radius_multiplier, 120.0), RendererApi::Color::Transparent{0, 0, 255, 127} }; receiver(s); return; diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/keyboard_catcher_widget.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/keyboard_catcher_widget.hpp index 7246993..27ed06e 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/keyboard_catcher_widget.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/keyboard_catcher_widget.hpp @@ -83,6 +83,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { void key_pressed_S(); void key_pressed_D(); + void key_pressed_P(); protected: void keyPressEvent(QKeyEvent *event) override { @@ -186,6 +187,9 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { case Qt::Key_S: emit this->key_pressed_S(); return; + case Qt::Key_P: + emit this->key_pressed_P(); + return; } } 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 c0b7084..026b319 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp @@ -32,7 +32,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { const float sum_f[4]{bg_alpha[0] + fg_alpha[0], bg_alpha[1] + fg_alpha[1], bg_alpha[2] + fg_alpha[2]}; // divps - const float sum_fixed_f[4]{sum_f[0] / 255.f, sum_f[2] / 255.f, sum_f[2] / 255.f}; + const float sum_fixed_f[4]{sum_f[0] / 255.f, sum_f[1] / 255.f, sum_f[2] / 255.f}; return { (RendererApi::Color::component_compact_t) sum_fixed_f[0], diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp index 0fa0b6b..aaffe25 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp @@ -3,6 +3,7 @@ #include #include +#include "color.hpp" #include "matrix.hpp" @@ -134,6 +135,51 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { template constexpr MonoShader::Static const MonoShader::static_{}; + 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 hsv_sector_shader : public Utilities::Shader { + private: + RendererApi::PointF<2>::component_t cx, cy; + double angle_offset_radians; + public: + hsv_sector_shader(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} {} + + hsv_sector_shader(RendererApi::PointF<2> c, double angle_offset_radians) : cx{c.x}, cy{c.y}, angle_offset_radians{angle_offset_radians} {} + + hsv_sector_shader(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); + } + }; class TransformedShader : public Shader { private: diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp index b0fae93..06e6e9c 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp @@ -391,17 +391,17 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { private: using point_t = RendererApi::Point; - _triangle_barycentric_interpolator(interpolator_t interpolator) { + _triangle_barycentric_interpolator(interpolator_t interpolator) { if constexpr (DIMENSIONS == 2) return point_t{ - static_cast(interpolator([](point_t const &p) { return p.x; })), - static_cast(interpolator([](point_t const &p) { return p.y; })) + static_cast(interpolator([](point_t const &p) { return p.x; })), + static_cast(interpolator([](point_t const &p) { return p.y; })) }; else - return RendererApi::Point<3, component_t>{ - static_cast(interpolator([](point_t const &p) { return p.x; })), - static_cast(interpolator([](point_t const &p) { return p.y; })), - static_cast(interpolator([](point_t const &p) { return p.z; })) + return point_t{ + static_cast(interpolator([](point_t const &p) { return p.x; })), + static_cast(interpolator([](point_t const &p) { return p.y; })), + static_cast(interpolator([](point_t const &p) { return p.z; })) }; }> impl; public: @@ -413,11 +413,11 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { } - [[nodiscard]] RendererApi::Color interpolate_point(RendererApi::PointF<2> p) const { + [[nodiscard]] point_t interpolate_point(RendererApi::PointF<2> p) const { return this->impl.interpolate_point(p); } - [[nodiscard]] RendererApi::Color interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { + [[nodiscard]] point_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { return this->impl.interpolate_point(x, y); } }; @@ -427,8 +427,9 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { triangle_barycentric_interpolator interpolator; public: inline triangle_barycentric_shader( - RendererApi::PointF<2> p0, RendererApi::PointF<2> p1, RendererApi::PointF<2> p2, - RendererApi::Color::Transparent c0, RendererApi::Color::Transparent c1, RendererApi::Color::Transparent c2 + RendererApi::PointF<2> p0, RendererApi::Color::Transparent c0, + RendererApi::PointF<2> p1, RendererApi::Color::Transparent c1, + RendererApi::PointF<2> p2, RendererApi::Color::Transparent c2 ) noexcept: interpolator{p0, c0, p1, c1, p2, c2} {}