diff --git a/CMakeLists.txt b/CMakeLists.txt index c52ae66..9eb2612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(cg1) set(CMAKE_CXX_STANDARD 20) -find_package (Qt5Widgets REQUIRED) +find_package(Qt5Widgets REQUIRED) set(CMAKE_AUTOMOC ON) add_executable( @@ -23,4 +23,7 @@ add_executable( src/ui.cpp ) -qt5_use_modules(cg1 Widgets) \ No newline at end of file +qt5_use_modules(cg1 Widgets) + +add_subdirectory(renderer-api) +add_subdirectory(utilities) \ No newline at end of file diff --git a/renderer-api/CMakeLists.txt b/renderer-api/CMakeLists.txt new file mode 100644 index 0000000..a81e12e --- /dev/null +++ b/renderer-api/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(renderer_api INTERFACE) +target_include_directories(renderer_api INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/color.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/color.hpp new file mode 100644 index 0000000..bc00996 --- /dev/null +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/color.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace BGTU::ComputerGraphicsLabWork::RendererApi { + class Color { + public: + using component_fast_t = std::uint_fast8_t; + using component_compact_t = std::uint_least8_t; + + static constexpr component_fast_t component_min_value = 0; + static constexpr component_fast_t component_max_value = 255; + + component_compact_t red; + component_compact_t green; + component_compact_t blue; + + inline Color() : red{0}, green{0}, blue{0} {} + + inline Color(component_fast_t red, component_fast_t green, component_fast_t blue) : red{red}, green{green}, blue{blue} {} + + class Transparent { + public: + component_compact_t red; + component_compact_t green; + component_compact_t blue; + component_compact_t alpha; + + inline Transparent() : red{component_min_value}, green{component_min_value}, blue{component_min_value}, alpha{component_max_value} {} + + inline Transparent(component_fast_t red, component_fast_t green, component_fast_t blue) : red{red}, green{green}, blue{blue}, alpha{component_max_value} {} + + inline Transparent(component_fast_t red, component_fast_t green, component_fast_t blue, component_fast_t alpha) : red{red}, green{green}, blue{blue}, alpha{alpha} {} + + inline Transparent(Color c) : red{c.red}, green{c.green}, blue{c.blue}, alpha{component_max_value} {} + }; + }; +} \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/point.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/point.hpp new file mode 100644 index 0000000..ba5d136 --- /dev/null +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/point.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace BGTU::ComputerGraphicsLabWork::RendererApi { + template + class Point { + static_assert(DIMENSIONS == 2 || DIMENSIONS == 3); + }; + + template + class Point<2, _component_t> { + public: + using component_t = _component_t; + + component_t x; + component_t y; + + inline Point(component_t x, component_t y) : x{x}, y{y} {} + }; + + template + class Point<3, _component_t> { + public: + using component_t = _component_t; + + component_t x; + component_t y; + component_t z; + + inline Point(component_t x, component_t y, component_t z) : x{x}, y{y}, z{z} {} + }; + + template + using PointI = Point; + + template + using PointF = Point; +} \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/projection.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/projection.hpp new file mode 100644 index 0000000..b443503 --- /dev/null +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/projection.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "point.hpp" + +namespace BGTU::ComputerGraphicsLabWork::RendererApi { + class Projection { + public: + virtual PointI<2> project(PointF<3> point) = 0; + }; +} \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp new file mode 100644 index 0000000..81a5859 --- /dev/null +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "voxel_drawer.hpp" +#include "projection.hpp" + +namespace BGTU::ComputerGraphicsLabWork::RendererApi { + template + class Sprite { + public: + virtual void draw(VoxelDrawer *frame, Projection *projection, data_t *data) const = 0; + + virtual void clicked() {}; + }; +} \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp new file mode 100644 index 0000000..9aa453c --- /dev/null +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "color.hpp" +#include "point.hpp" + +namespace BGTU::ComputerGraphicsLabWork::RendererApi { + class VoxelDrawer { + public: + using visible_pixel_coordinate_fast_t = std::uint_fast16_t; + using visible_pixel_coordinate_compact_t = std::uint_least16_t; + + static constexpr visible_pixel_coordinate_fast_t visible_pixel_min_x = 0; + static constexpr visible_pixel_coordinate_fast_t visible_pixel_min_y = 0; + static constexpr visible_pixel_coordinate_fast_t visible_pixel_max_x = std::numeric_limits::max(); + static constexpr visible_pixel_coordinate_fast_t visible_pixel_max_y = std::numeric_limits::max(); + + + [[nodiscard]] virtual visible_pixel_coordinate_fast_t width() const = 0; + + [[nodiscard]] virtual visible_pixel_coordinate_fast_t height() const = 0; + + virtual void update_pixel(PointI<2>::component_t x, PointI<2>::component_t y, double z, Color::Transparent c) = 0; + + inline void update_pixel(PointI<2> p, double z, Color::Transparent c) { + return this->update_pixel(p.x, p.y, z, c); + } + }; +} \ No newline at end of file diff --git a/utilities/CMakeLists.txt b/utilities/CMakeLists.txt new file mode 100644 index 0000000..c4e6e18 --- /dev/null +++ b/utilities/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(utilities OBJECT src/shader.cpp) +target_include_directories(utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_link_libraries(utilities PUBLIC renderer_api) \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/brezenham.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/brezenham.hpp new file mode 100644 index 0000000..470adb2 --- /dev/null +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/brezenham.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include + +namespace BGTU::ComputerGraphicsLabWork::Utilities { + class brezenham_line_iterable { + private: + RendererApi::PointI<2>::component_t start_arg, start_ret, end_arg; + RendererApi::PointI<2>::component_t delta_ret; + RendererApi::PointI<2>::component_t delta_error, error_threshold; + bool swap_flag; + public: + inline brezenham_line_iterable(RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2) { + RendererApi::PointI<2>::component_t delta_x = (x1 > x2) ? (x1 - x2) : (x2 - x1); + RendererApi::PointI<2>::component_t delta_y = (y1 > y2) ? (y1 - y2) : (y2 - y1); + if (delta_x > delta_y) { + this->start_arg = x1; + this->start_ret = y1; + this->end_arg = x2; + this->delta_error = (RendererApi::PointI<2>::component_t) (delta_y + 1); + this->error_threshold = (RendererApi::PointI<2>::component_t) (delta_x + 1); + this->delta_ret = (y2 > y1) ? 1 : -1; + this->swap_flag = false; + } else { + this->start_arg = y1; + this->start_ret = x1; + this->end_arg = y2; + this->delta_error = (RendererApi::PointI<2>::component_t) (delta_x + 1); + this->error_threshold = (RendererApi::PointI<2>::component_t) (delta_y + 1); + this->delta_ret = (x2 > x1) ? 1 : -1; + this->swap_flag = true; + } + } + + struct point { + public: + RendererApi::PointI<2>::component_t x, y; + + inline point(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) : x{x}, y{y} {} + }; + + class iterator { + private: + RendererApi::PointI<2>::component_t arg, ret, end_arg; + RendererApi::PointI<2>::component_t delta_ret; + RendererApi::PointI<2>::component_t error, delta_error, error_threshold; + bool swap_flag; + + inline iterator( + RendererApi::PointI<2>::component_t arg, RendererApi::PointI<2>::component_t ret, RendererApi::PointI<2>::component_t end_arg, + RendererApi::PointI<2>::component_t delta_ret, + RendererApi::PointI<2>::component_t delta_error, RendererApi::PointI<2>::component_t error_threshold, + bool swap_flag + ) : arg{arg}, ret{ret}, end_arg{end_arg}, delta_ret{delta_ret}, error{0}, delta_error{delta_error}, swap_flag{swap_flag}, error_threshold{error_threshold} {} + + friend class brezenham_line_iterable; + + public: + inline iterator &operator++() { + this->arg++; + this->error += this->delta_error; + if (this->error >= this->error_threshold) { + this->ret += this->delta_ret; + this->error -= this->error_threshold; + } + return *this; + } + + inline iterator operator++(int) { + iterator next = *this; + ++(*this); + return next; + } + + inline point operator*() const { + if (this->swap_flag) + return point{this->ret, this->arg}; + else + return point{this->arg, this->ret}; + } + + inline bool operator==(std::nullptr_t) const { + return this->arg > this->end_arg; + } + + inline bool operator!=(std::nullptr_t) const { + return this->arg <= this->end_arg; + } + }; + + [[nodiscard]] inline iterator begin() const { + return iterator{ + this->start_arg, this->start_ret, this->end_arg, + this->delta_ret, + this->delta_error, this->error_threshold, + this->swap_flag + }; + } + + [[nodiscard]] inline std::nullptr_t end() const { + return nullptr; + } + }; +} \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/matrix.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/matrix.hpp new file mode 100644 index 0000000..bf911c7 --- /dev/null +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/matrix.hpp @@ -0,0 +1,273 @@ +#pragma once + +#include +#include +#include + +namespace BGTU::ComputerGraphicsLabWork::Utilities { + + template + class Matrix3 { + private: + elem_t data[3][3]; + public: + inline Matrix3( + elem_t e00, elem_t e01, elem_t e02, + elem_t e10, elem_t e11, elem_t e12, + elem_t e20, elem_t e21, elem_t e22 + ) : data{e00, e01, e02, e10, e11, e12, e20, e21, e22} {} + + static inline const Matrix3 I{1, 0, 0, + 0, 1, 0, + 0, 0, 1}; + private: + static inline const Matrix3 _tmp{}; + + + template + Matrix3 _zipmap_matrix(Matrix3 const *other, operator_t op) const { + Matrix3 dst; + auto _map_row = [&](std::size_t row_index) { + dst.data[row_index][0] = op(row_index, 0, this->data[row_index][0], other->data[row_index][0]); + dst.data[row_index][1] = op(row_index, 1, this->data[row_index][1], other->data[row_index][1]); + dst.data[row_index][2] = op(row_index, 2, this->data[row_index][2], other->data[row_index][2]); + }; + _map_row(0); + _map_row(1); + _map_row(2); + + return dst; + } + + public: + inline Matrix3 operator+(Matrix3 const &other) const { + return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s + o; }); + } + + inline Matrix3 operator-(Matrix3 const &other) const { + return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s - o; }); + } + + inline Matrix3 operator*(int other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix3 operator*(long other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix3 operator*(float other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix3 operator*(double other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix3 operator/(int other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix3 operator/(long other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix3 operator/(float other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix3 operator/(double other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix3 operator*(Matrix3 const &other) const { + return this->_zipmap_matrix(&Matrix3::_tmp, [&](auto y, auto x, auto, auto) { + return this->data[y][0] * other.data[0][x] + this->data[y][1] * other.data[1][x] + this->data[y][2] * other.data[2][x]; + }); + } + + static Matrix3 scale(elem_t x, elem_t y) { + return Matrix3{x, 0, 0, + 0, y, 0, + 0, 0, 1}; + } + + static Matrix3 rotate(elem_t radians) { + auto s = std::sin(radians); + auto c = std::cos(radians); + return Matrix3{c, -s, 0, + s, c, 0, + 0, 0, 1}; + } + + static Matrix3 shift(elem_t x, elem_t y) { + return Matrix3{1, 0, x, + 0, 1, y, + 0, 0, 1}; + } + + RendererApi::Point<2, elem_t> operator*(RendererApi::Point<2, elem_t> other) const { + return RendererApi::Point<2, elem_t>{ + this->data[0][0] * other.x + this->data[0][1] * other.y + this->data[0][2], + this->data[1][0] * other.x + this->data[1][1] * other.y + this->data[1][2], + }; + } + }; + + using Matrix3i = Matrix3; + using Matrix3l = Matrix3; + using Matrix3f = Matrix3; + using Matrix3d = Matrix3; + + template + class Matrix4 { + private: + elem_t data[4][4]; + + Matrix4() = default; + + public: +#if 0 + inline Matrix4( + std::initializer_list r0, + std::initializer_list r1, + std::initializer_list r2, + std::initializer_list r3 + ) : data{r0, r1, r2, r3} {} +#endif + + inline Matrix4( + elem_t e00, elem_t e01, elem_t e02, elem_t e03, + elem_t e10, elem_t e11, elem_t e12, elem_t e13, + elem_t e20, elem_t e21, elem_t e22, elem_t e23, + elem_t e30, elem_t e31, elem_t e32, elem_t e33 + ) : data{e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33} {} + + static inline const Matrix4 I{1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1}; + + private: + static inline const Matrix4 _tmp{}; + + template + Matrix4 _zipmap_matrix(Matrix4 const *other, operator_t op) const { + Matrix4 dst; + auto _map_row = [&](std::size_t row_index) { + dst.data[row_index][0] = op(row_index, 0, this->data[row_index][0], other->data[row_index][0]); + dst.data[row_index][1] = op(row_index, 1, this->data[row_index][1], other->data[row_index][1]); + dst.data[row_index][2] = op(row_index, 2, this->data[row_index][2], other->data[row_index][2]); + dst.data[row_index][3] = op(row_index, 3, this->data[row_index][3], other->data[row_index][3]); + }; + _map_row(0); + _map_row(1); + _map_row(2); + _map_row(3); + + return dst; + } + + public: + inline Matrix4 operator+(Matrix4 const &other) const { + return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s + o; }); + } + + inline Matrix4 operator-(Matrix4 const &other) const { + return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s - o; }); + } + + inline Matrix4 operator*(int other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix4 operator*(long other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix4 operator*(float other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix4 operator*(double other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; }); + } + + inline Matrix4 operator/(int other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix4 operator/(long other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix4 operator/(float other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix4 operator/(double other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; }); + } + + inline Matrix4 operator*(Matrix4 const &other) const { + return this->_zipmap_matrix(&Matrix4::_tmp, [&](auto y, auto x, auto, auto) { + return this->data[y][0] * other.data[0][x] + this->data[y][1] * other.data[1][x] + this->data[y][2] * other.data[2][x] + this->data[y][3] * other.data[3][x]; + }); + } + + static Matrix4 scale(elem_t x, elem_t y, elem_t z) { + return Matrix4{x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1}; + } + + + static Matrix4 rotate_x(elem_t radians) { + auto s = std::sin(radians); + auto c = std::cos(radians); + return Matrix4{1, 0, 0, 0, + 0, c, -s, 0, + 0, s, c, 0, + 0, 0, 0, 1}; + } + + static Matrix4 rotate_y(elem_t radians) { + auto s = std::sin(radians); + auto c = std::cos(radians); + return Matrix4{c, 0, s, 0, + 0, 1, 0, 0, + -s, 0, c, 0, + 0, 0, 0, 1}; + } + + static Matrix4 rotate_z(elem_t radians) { + auto s = std::sin(radians); + auto c = std::cos(radians); + return Matrix4{c, -s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1}; + } + + static Matrix4 shift(elem_t x, elem_t y, elem_t z) { + return Matrix4{1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1}; + } + + RendererApi::Point<3, elem_t> operator*(RendererApi::Point<3, elem_t> other) const { + return RendererApi::Point<3, elem_t>{ + this->data[0][0] * other.x + this->data[0][1] * other.y + this->data[0][2] * other.z + this->data[0][3], + this->data[1][0] * other.x + this->data[1][1] * other.y + this->data[1][2] * other.z + this->data[1][3], + this->data[2][0] * other.x + this->data[2][1] * other.y + this->data[2][2] * other.z + this->data[2][3], + }; + } + }; + + using Matrix4i = Matrix4; + using Matrix4l = Matrix4; + using Matrix4f = Matrix4; + using Matrix4d = Matrix4; +} \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp new file mode 100644 index 0000000..01a0806 --- /dev/null +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/shader.hpp @@ -0,0 +1,42 @@ +#pragma once + + +#include +#include "matrix.hpp" + + +namespace BGTU::ComputerGraphicsLabWork::Utilities { + class Shader { + public: + [[nodiscard]] virtual RendererApi::Color::Transparent get_color(double x, double y) const = 0; + + static Shader const *empty_shader; + }; + + class MonoShader : public Shader { + private: + RendererApi::Color::Transparent c; + + public: + inline explicit MonoShader(RendererApi::Color::Transparent c) : c{c} {} + + [[nodiscard]] inline RendererApi::Color::Transparent get_color(double x, double y) const override { + return this->c; + }; + }; + + class TransformedShader : public Shader { + private: + Shader const *shader; + Matrix4d transform; + + public: + inline TransformedShader(Shader const *s, Matrix4d t) : shader{s}, transform{t} {} + + [[nodiscard]] inline RendererApi::Color::Transparent get_color(double x, double y) const override { + RendererApi::PointF<3> in{x, y, 0}; + RendererApi::PointF<3> out = this->transform * in; + return this->shader->get_color(out.x, out.y); + } + }; +} \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/triangle_fill_iterable.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/triangle_fill_iterable.hpp new file mode 100644 index 0000000..23c58e9 --- /dev/null +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/triangle_fill_iterable.hpp @@ -0,0 +1,214 @@ +#pragma once + +#include +#include +#include +#include +#include "brezenham.hpp" + +namespace BGTU::ComputerGraphicsLabWork::Utilities { + + template + void fill_triangle( + RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, + RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, + RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2, + receiver_t receiver + ) noexcept(receiver(static_cast(false), static_cast::component_t>(0), static_cast::component_t>(0))); + class triangle_fill_iterable { + private: + brezenham_line_iterable upper_left; + brezenham_line_iterable lower_left; + brezenham_line_iterable right; + + template + friend + void fill_triangle( + RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, + RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, + RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2, + receiver_t + ) noexcept(std::declval()(static_cast(false), static_cast::component_t>(0), static_cast::component_t>(0))); + + + inline triangle_fill_iterable( + brezenham_line_iterable upper_left, + brezenham_line_iterable lower_left, + brezenham_line_iterable right + ) : upper_left{upper_left}, lower_left{lower_left}, right{right} {} + + struct _pre_constructor { + private: + inline static void sort_points(RendererApi::PointI<2>::component_t *x0, RendererApi::PointI<2>::component_t *y0, RendererApi::PointI<2>::component_t *x1,RendererApi::PointI<2>::component_t *y1, RendererApi::PointI<2>::component_t *x2, RendererApi::PointI<2>::component_t *y2) { + auto _swap = [](RendererApi::PointI<2>::component_t *sx0, RendererApi::PointI<2>::component_t *sy0, RendererApi::PointI<2>::component_t *sx1, RendererApi::PointI<2>::component_t *sy1) { + RendererApi::PointI<2>::component_t tmp; + + tmp = *sx0; + *sx0 = *sx1; + *sx1 = tmp; + + tmp = *sy0; + *sy0 = *sy1; + *sy1 = tmp; + }; + + if (*y0 < *y1) + _swap(x0, y0, x1, y1); + if (*y1 < *y2) + _swap(x1, y1, x2, y2); + if (*y0 < *y1) + _swap(x0, y0, x1, y1); + if (*y0 == *y1 && *x0 < *x1) + _swap(x0, y0, x1, y1); + if (*y1 == *y2 && *x2 < *x1) + _swap(x1, y1, x2, y2); + } + + public: + + static inline triangle_fill_iterable create( + RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, + RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, + RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2 + ) { + _pre_constructor::sort_points(&x0, &y0, &x1, &y1, &x2, &y2); + return triangle_fill_iterable{brezenham_line_iterable{x0, y0, x1, y1}, brezenham_line_iterable{x1, y1, x2, y2}, brezenham_line_iterable{x0, y0, x2, y2}}; + } + }; + + public: + inline triangle_fill_iterable( + RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, + RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, + RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2 + ) : triangle_fill_iterable{_pre_constructor::create(x0, y0, x1, y1, x2, y2)} { + } + +#if 0 + class iterator { + private: + brezenham_line_iterable::iterator upper_left; + brezenham_line_iterable::iterator lower_left; + brezenham_line_iterable::iterator right; + RendererApi::PointI<2>::component_t cx, ex, cy; + + friend class triangle_fill; + + inline iterator( + brezenham_line_iterable const &upper_left, + brezenham_line_iterable const &lower_left, + brezenham_line_iterable const &right + ) : upper_left{upper_left.begin()}, lower_left{lower_left.begin()}, right{right.begin()}, cx{(*this->upper_left).x}, ex{(*this->right).x}, cy{(*this->upper_left).y} {} + + + brezenham_line_iterable::iterator &_left() { + if (this->upper_left == nullptr) + return this->lower_left; + else + return this->upper_left; + } + + public: + inline iterator &operator++() { + if (this->cx < this->ex) { + this->cx++; + return *this; + } + if (this->upper_left != nullptr) { + RendererApi::PointI<2>::component_t sx = (*(this->upper_left)).x; + while (true) { + this->upper_left++; + if (this->upper_left == nullptr) + goto LOWER; + if ((*(this->upper_left)).y < this->cy) + { + this->cy--; + return *this; + + (*++(this->upper_left)).y >= this->cy + if ((*(this->upper_left)).x < sx) + return *this; + } + } else { + LOWER: + RendererApi::PointI<2>::component_t sx = (*(this->upper_left)).x; + } + + while ((*++(this->right)).y >= this->cy) { + if ((*(this->right)).x > this->ex) + return *this; + } + + this->cy--; + + + } + + inline iterator operator++(int) { + iterator next = *this; + ++(*this); + return next; + } + + inline point operator*() const { + if (this->swap_flag) + return point{this->ret, this->arg}; + else + return point{this->arg, this->ret}; + } + + inline bool operator==(std::nullptr_t) const { + return this->arg >= this->end_arg; + } + + inline bool operator!=(std::nullptr_t) const { + return this->arg < this->end_arg; + } + }; +#endif + }; + + + template + void fill_triangle( + RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, + RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, + RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2, + receiver_t receiver + ) noexcept(receiver(static_cast(false), static_cast::component_t>(0), static_cast::component_t>(0))) { + triangle_fill_iterable init{x0, y0, x1, y1, x2, y2}; + auto right = init.right.begin(); + RendererApi::PointI<2>::component_t cy = (*right).y; + RendererApi::PointI<2>::component_t sx = std::numeric_limits::component_t>::min(); + RendererApi::PointI<2>::component_t ex = std::numeric_limits::component_t>::max(); + + auto loop = [&](brezenham_line_iterable left) { + + for (auto lp: left) { + if (lp.y == cy) { + receiver(true, lp.x, lp.y); + sx = (lp.x > sx) ? (lp.x) : sx; + continue; + } + + for (; (*right).y > lp.y; right++) { + if ((*right).x > sx) + receiver(true, (*right).x, (*right).y); + ex = ((*right).x < ex) ? ((*right).x) : ex; + } + for (RendererApi::PointI<2>::component_t x = sx + 1; x < ex; x++) + receiver(false, x, cy); + + cy--; + receiver(true, lp.x, lp.y); + } + }; + + loop(init.upper_left); + loop(init.lower_left); + for (; right != nullptr; right++) { + if ((*right).x > sx) + receiver(true, (*right).x, (*right).y); + } + } +} \ No newline at end of file diff --git a/utilities/src/shader.cpp b/utilities/src/shader.cpp new file mode 100644 index 0000000..8b27ca7 --- /dev/null +++ b/utilities/src/shader.cpp @@ -0,0 +1,19 @@ +#include +#include + +namespace BGTU::ComputerGraphicsLabWork::Utilities { + + class EmptyShader : public Shader { + + public: + EmptyShader() = default; + + [[nodiscard]] RendererApi::Color::Transparent get_color(double x, double y) const override { + return RendererApi::Color::Transparent{0, 0, 0, 0}; + } + }; + + static const EmptyShader empty_shader_instance; + + Shader const *Shader::empty_shader = &empty_shader_instance; +} \ No newline at end of file