diff --git a/programs/lab4/src/variant4.cpp b/programs/lab4/src/variant4.cpp index c8ca4a7..0ab4217 100644 --- a/programs/lab4/src/variant4.cpp +++ b/programs/lab4/src/variant4.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -24,10 +25,9 @@ namespace BGTU::ComputerGraphicsLabWork::Impl { RendererApi::PointF<3> tc = data->transform * this->c; Utilities::Shapes::triangle_barycentric_interpolator z_interpolator{ - {ta.x, ta.y}, - {tb.x, tb.y}, - {tc.x, tc.y}, - ta.z, tb.z, tc.z + {ta.x, ta.y}, ta.z, + {tb.x, tb.y}, tb.z, + {tc.x, tc.y}, tc.z }; Utilities::Shapes::iterate_triangle_fill( @@ -48,25 +48,25 @@ namespace BGTU::ComputerGraphicsLabWork::Impl { Triangle triangles[] = { - {{0.0, 0.0, 1.0}, angle5(0, 2), angle5(1, 1)}, + {{0.0, 0.0, 1.0}, angle5(0, 2), angle5(1, 1)}, {{0.0, 0.0, -1.0}, angle5(0, 2), angle5(1, 1)}, - {{0.0, 0.0, 1.0}, angle5(2, 2), angle5(1, 1)}, + {{0.0, 0.0, 1.0}, angle5(2, 2), angle5(1, 1)}, {{0.0, 0.0, -1.0}, angle5(2, 2), angle5(1, 1)}, - {{0.0, 0.0, 1.0}, angle5(2, 2), angle5(3, 1)}, + {{0.0, 0.0, 1.0}, angle5(2, 2), angle5(3, 1)}, {{0.0, 0.0, -1.0}, angle5(2, 2), angle5(3, 1)}, - {{0.0, 0.0, 1.0}, angle5(4, 2), angle5(3, 1)}, + {{0.0, 0.0, 1.0}, angle5(4, 2), angle5(3, 1)}, {{0.0, 0.0, -1.0}, angle5(4, 2), angle5(3, 1)}, - {{0.0, 0.0, 1.0}, angle5(4, 2), angle5(5, 1)}, + {{0.0, 0.0, 1.0}, angle5(4, 2), angle5(5, 1)}, {{0.0, 0.0, -1.0}, angle5(4, 2), angle5(5, 1)}, - {{0.0, 0.0, 1.0}, angle5(6, 2), angle5(5, 1)}, + {{0.0, 0.0, 1.0}, angle5(6, 2), angle5(5, 1)}, {{0.0, 0.0, -1.0}, angle5(6, 2), angle5(5, 1)}, - {{0.0, 0.0, 1.0}, angle5(6, 2), angle5(7, 1)}, + {{0.0, 0.0, 1.0}, angle5(6, 2), angle5(7, 1)}, {{0.0, 0.0, -1.0}, angle5(6, 2), angle5(7, 1)}, - {{0.0, 0.0, 1.0}, angle5(8, 2), angle5(7, 1)}, + {{0.0, 0.0, 1.0}, angle5(8, 2), angle5(7, 1)}, {{0.0, 0.0, -1.0}, angle5(8, 2), angle5(7, 1)}, - {{0.0, 0.0, 1.0}, angle5(8, 2), angle5(9, 1)}, + {{0.0, 0.0, 1.0}, angle5(8, 2), angle5(9, 1)}, {{0.0, 0.0, -1.0}, angle5(8, 2), angle5(9, 1)}, - {{0.0, 0.0, 1.0}, angle5(0, 2), angle5(9, 1)}, + {{0.0, 0.0, 1.0}, angle5(0, 2), angle5(9, 1)}, {{0.0, 0.0, -1.0}, angle5(0, 2), angle5(9, 1)}, }; 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 index 5429355..0f959af 100644 --- 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 @@ -27,6 +27,9 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { return !(*this == other); } + class Transparent; + + [[nodiscard]] constexpr Transparent with_alpha(component_fast_t alpha) const noexcept; class Transparent { public: @@ -43,6 +46,8 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { constexpr Transparent(Color c) noexcept: red{c.red}, green{c.green}, blue{c.blue}, alpha{component_max_value} {} + constexpr Transparent(Color c, component_fast_t alpha) noexcept: red{c.red}, green{c.green}, blue{c.blue}, alpha{alpha} {} + constexpr bool operator==(Color::Transparent const &other) const noexcept { return this->red == other.red && this->green == other.green && this->blue == other.blue && this->alpha == other.alpha; } @@ -56,4 +61,8 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { }; }; }; + + constexpr Color::Transparent Color::with_alpha(Color::component_fast_t alpha) const noexcept { + return Color::Transparent{*this, alpha}; + }; } \ No newline at end of file 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 3f98307..b0fae93 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 @@ -248,8 +248,8 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { ); } - template - struct triangle_barycentric_interpolator { + template + struct _triangle_barycentric_interpolator { private: long double full_square; RendererApi::PointF<2> p0; @@ -259,11 +259,6 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { variable_t v1; variable_t v2; - struct _empty { - }; - - std::conditional_t, bool, _empty> skip_alpha; - static long double calculate_square_2( RendererApi::PointF<2> p0, RendererApi::PointF<2> p1, @@ -272,53 +267,161 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y); } - public: - triangle_barycentric_interpolator( - RendererApi::PointF<2> p0, RendererApi::PointF<2> p1, RendererApi::PointF<2> p2, - variable_t v0, variable_t v1, variable_t v2 + _triangle_barycentric_interpolator( + RendererApi::PointF<2> p0, variable_t v0, + RendererApi::PointF<2> p1, variable_t v1, + RendererApi::PointF<2> p2, variable_t v2 ) : p0{p0}, p1{p1}, p2{p2}, v0{v0}, v1{v1}, v2{v2}, full_square{calculate_square_2(p0, p1, p2)} { - if constexpr (std::is_same_v) { - this->skip_alpha = v0.alpha == v1.alpha && v0.alpha == v2.alpha; - } } - variable_t interpolate_point(RendererApi::PointF<2> p) const { + [[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2> p) const { const double k0 = calculate_square_2(p, this->p1, this->p2) / this->full_square; const double k1 = calculate_square_2(p, this->p2, this->p0) / this->full_square; const double k2 = calculate_square_2(p, this->p0, this->p1) / this->full_square; - if constexpr (std::is_same_v || std::is_same_v) { - auto f = [&](intermediate_t (variable_t::*offset)) -> intermediate_t { - return static_cast((this->v0.*offset) * k0 + (this->v1.*offset) * k1 + (this->v2.*offset) * k2); - }; - if constexpr (std::is_same_v) { - RendererApi::Color base{ - f(&RendererApi::Color::Transparent::red), - f(&RendererApi::Color::Transparent::green), - f(&RendererApi::Color::Transparent::blue), - }; - return RendererApi::Color::Transparent{ - base.red, base.green, base.blue, - (this->skip_alpha ? this->v0.alpha : f(&RendererApi::Color::Transparent::alpha)) - }; - } else { - return RendererApi::Color{ - f(&RendererApi::Color::red), - f(&RendererApi::Color::green), - f(&RendererApi::Color::blue) - }; - } - } else { - return static_cast((this->v0) * k0 + (this->v1) * k1 + (this->v2) * k2); - } + return transform([=, this](property_getter_t pg) -> auto { return pg(this->v0) * k0 + pg(this->v1) * k1 + pg(this->v2) * k2; }); } - variable_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { + [[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { return this->interpolate_point(RendererApi::PointF<2>{x, y}); } }; + + template + struct triangle_barycentric_interpolator { + private: + _triangle_barycentric_interpolator(interpolator_t interpolator) { + return static_cast(interpolator([](variable_t v) { return v; })); + }> impl; + public: + triangle_barycentric_interpolator( + RendererApi::PointF<2> p0, variable_t v0, + RendererApi::PointF<2> p1, variable_t v1, + RendererApi::PointF<2> p2, variable_t v2 + ) : impl{p0, v0, p1, v1, p2, v2} {}; + + [[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2> p) const { + return this->impl.interpolate_point(p); + } + + [[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { + return this->impl.interpolate_point(x, y); + } + }; + + template<> + struct triangle_barycentric_interpolator { + private: + _triangle_barycentric_interpolator(interpolator_t interpolator) { + return RendererApi::Color{ + static_cast(interpolator([](RendererApi::Color const &c) { return c.red; })), + static_cast(interpolator([](RendererApi::Color const &c) { return c.green; })), + static_cast(interpolator([](RendererApi::Color const &c) { return c.blue; })) + }; + }> impl; + public: + inline triangle_barycentric_interpolator( + RendererApi::PointF<2> p0, RendererApi::Color v0, + RendererApi::PointF<2> p1, RendererApi::Color v1, + RendererApi::PointF<2> p2, RendererApi::Color v2 + ) : impl{p0, v0, p1, v1, p2, v2} { + } + + + [[nodiscard]] inline RendererApi::Color interpolate_point(RendererApi::PointF<2> p) const { + return this->impl.interpolate_point(p); + } + + [[nodiscard]] inline RendererApi::Color interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { + return this->impl.interpolate_point(x, y); + } + }; + + template<> + struct triangle_barycentric_interpolator { + private: + union _interpolators_t { + triangle_barycentric_interpolator ignore_alpha; + _triangle_barycentric_interpolator(interpolator_t interpolator) { + return RendererApi::Color::Transparent{ + static_cast(interpolator([](RendererApi::Color::Transparent const &c) { return c.red; })), + static_cast(interpolator([](RendererApi::Color::Transparent const &c) { return c.green; })), + static_cast(interpolator([](RendererApi::Color::Transparent const &c) { return c.blue; })), + static_cast(interpolator([](RendererApi::Color::Transparent const &c) { return c.alpha; })) + }; + }> transparent; + } interpolators; + bool is_alpha_const; + RendererApi::Color::component_fast_t const_alpha_value; + + inline triangle_barycentric_interpolator( + bool is_alpha_const, + RendererApi::PointF<2> p0, RendererApi::Color::Transparent v0, + RendererApi::PointF<2> p1, RendererApi::Color::Transparent v1, + RendererApi::PointF<2> p2, RendererApi::Color::Transparent v2 + ) : interpolators{is_alpha_const ? _interpolators_t{.ignore_alpha{p0, v0.without_alpha(), p1, v1.without_alpha(), p2, v2.without_alpha()}} : _interpolators_t{.transparent{p0, v0, p1, v1, p2, v2}}}, + is_alpha_const{is_alpha_const}, const_alpha_value{v0.alpha} {} + + public: + inline triangle_barycentric_interpolator( + RendererApi::PointF<2> p0, RendererApi::Color::Transparent v0, + RendererApi::PointF<2> p1, RendererApi::Color::Transparent v1, + RendererApi::PointF<2> p2, RendererApi::Color::Transparent v2 + ) : triangle_barycentric_interpolator{ + v0.alpha == v1.alpha && v0.alpha == v2.alpha, + p0, v0, p1, v1, p2, v2 + } {} + + [[nodiscard]] inline RendererApi::Color::Transparent interpolate_point(RendererApi::PointF<2> p) const { + if (this->is_alpha_const) + return this->interpolators.ignore_alpha.interpolate_point(p).with_alpha(this->const_alpha_value); + else + return this->interpolators.transparent.interpolate_point(p); + } + + [[nodiscard]] inline RendererApi::Color::Transparent interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const { + return this->interpolate_point(RendererApi::PointF<2>{x, y}); + } + }; + + template + struct triangle_barycentric_interpolator> { + private: + using point_t = RendererApi::Point; + + _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; })) + }; + 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; })) + }; + }> impl; + public: + triangle_barycentric_interpolator( + RendererApi::PointF<2> p0, point_t v0, + RendererApi::PointF<2> p1, point_t v1, + RendererApi::PointF<2> p2, point_t v2 + ) : impl{p0, v0, p1, v1, p2, v2} { + } + + + [[nodiscard]] RendererApi::Color 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 { + return this->impl.interpolate_point(x, y); + } + }; + class triangle_barycentric_shader : public Shader { private: triangle_barycentric_interpolator interpolator; @@ -326,7 +429,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { 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 - ) noexcept: interpolator{p0, p1, p2, c0, c1, c2} {} + ) noexcept: interpolator{p0, c0, p1, c1, p2, c2} {} [[nodiscard]] inline RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {