#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))); } ); } } }; }