forked from BGTU/computer-graphics-0
83 lines
3.4 KiB
C++
83 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
|
|
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
|
|
#include <bgtu/computer_graphics_lab_work/utilities/matrix.hpp>
|
|
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
|
|
#include <bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp>
|
|
|
|
#include "sprite_data.hpp"
|
|
|
|
|
|
namespace BGTU::ComputerGraphicsLabWork::Impl {
|
|
class Triangle : public RendererApi::Sprite<SpriteData> {
|
|
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<RendererApi::PointF<3>> interpolator{
|
|
static_cast<RendererApi::PointF<2>>(pa), {this->shader_p0.x, this->shader_p0.y, ta.z},
|
|
static_cast<RendererApi::PointF<2>>(pb), {this->shader_p1.x, this->shader_p1.y, tb.z},
|
|
static_cast<RendererApi::PointF<2>>(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<double> z_interpolator{
|
|
static_cast<RendererApi::PointF<2>>(pa), ta.z,
|
|
static_cast<RendererApi::PointF<2>>(pb), tb.z,
|
|
static_cast<RendererApi::PointF<2>>(pc), tc.z,
|
|
};
|
|
Utilities::Shapes::triangle_barycentric_interpolator<RendererApi::PointF<2>> 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)));
|
|
}
|
|
);
|
|
}
|
|
}
|
|
};
|
|
} |