diff options
Diffstat (limited to 'src/renderer.cpp')
-rw-r--r-- | src/renderer.cpp | 122 |
1 files changed, 68 insertions, 54 deletions
diff --git a/src/renderer.cpp b/src/renderer.cpp index 1fa8799..ad67ecc 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,42 +1,64 @@ #include "renderer.h" -#include <array> -#include <cmath> -#include <algorithm> #include <memory> +#include <array> #include "math/vector.h" -#include "o3d/vertex.h" -#include "o3d/deriv_vertex.h" #include "o3d/tri.h" #include "o3d/tri_deriv.h" -#include "o3d/vertex_data.h" +#include "fb/chfb.h" +#include "fb/pixfb.h" using namespace engine; +using + engine::math::Vector2, + engine::math::Vector4, + engine::o3d::Triangle, + engine::o3d::TriangleDerived, + engine::o3d::VertexData, + engine::fb::CharacterFrameBuffer, + engine::fb::PixelFrameBuffer; -Renderer::Renderer(std::unique_ptr<fb::FrameBuffer> fb) : fb{std::move(fb)} { - depth_buf.resize(this->fb->width() * this->fb->height()); -} - -void Renderer::resize(unsigned int w, unsigned int h) { - fb->resize(w, h); - depth_buf.resize(fb->width() * fb->height()); -} - -unsigned int Renderer::width() const { - return fb->width(); +template<typename FrameBuffer> +template<typename FBArg> +Renderer<FrameBuffer>::Renderer(FBArg&& fb) : fb{std::forward<FBArg>(fb)} { + depth_buf.resize(this->fb.width() * this->fb.height()); } -unsigned int Renderer::height() const { - return fb->height(); +template<typename FrameBuffer> +void Renderer<FrameBuffer>::resize(unsigned int w, unsigned int h) { + fb.resize(w, h); + depth_buf.resize(fb.width() * fb.height()); } -void Renderer::clear() { +template<typename FrameBuffer> +void Renderer<FrameBuffer>::clear() { std::fill(depth_buf.begin(), depth_buf.end(), 1.f); - fb->clear(); + fb.clear(); } enum TriangleSide { top, bottom }; -void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::TriangleDerived& triangle) { +template<typename FrameBuffer> +void Renderer<FrameBuffer>::draw_triangle(const Triangle& triangle) { + Vector2 fdim_over_2 = Vector2{static_cast<float>(fb.width()), static_cast<float>(fb.height())} / 2.f; + for (const auto& t1 : triangle.to_derived().crop_z_out(-1.f, 1.f)) { + for (auto t2 : t1.div_by_w().perspective_crop_xy_out(-1.f, 1.f, -1.f, 1.f)) { + auto& v1 = t2.derived_vertex1.vertex; + auto& v2 = t2.derived_vertex2.vertex; + auto& v3 = t2.derived_vertex3.vertex; + auto pp1 = v1.xy(); + auto pp2 = v2.xy(); + auto pp3 = v3.xy(); + if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue; + v1 = Vector4{(pp1 + 1.f).mul_term(fdim_over_2) - .5f, v1.z, v1.w}; + v2 = Vector4{(pp2 + 1.f).mul_term(fdim_over_2) - .5f, v2.z, v2.w}; + v3 = Vector4{(pp3 + 1.f).mul_term(fdim_over_2) - .5f, v3.z, v3.w}; + _draw_cropped_triangle(triangle, t2); + } + } +} + +template<typename FrameBuffer> +void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const TriangleDerived& triangle) { std::array<const o3d::DerivedVertex*, 3> sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 }; { @@ -55,13 +77,14 @@ void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::Tria auto middle_vl = *sorted_vs[1]; const float fac = (sorted_vs[1]->vertex.y - sorted_vs[0]->vertex.y) / (sorted_vs[2]->vertex.y - sorted_vs[0]->vertex.y); - const float fac_b0 = (1.f - fac) / sorted_vs[0]->vertex.w / ((1.f - fac) / sorted_vs[0]->vertex.w + fac / sorted_vs[2]->vertex.w); + const float middle_vr_vertex_w = 1.f / (1.f / sorted_vs[0]->vertex.w + fac * (1.f / sorted_vs[2]->vertex.w - 1.f / sorted_vs[0]->vertex.w)); + const float fac_b0 = middle_vr_vertex_w * (1.f - fac) / sorted_vs[0]->vertex.w; o3d::DerivedVertex middle_vr{ { sorted_vs[0]->vertex.x + fac * (sorted_vs[2]->vertex.x - sorted_vs[0]->vertex.x), sorted_vs[1]->vertex.y, fac_b0 * sorted_vs[0]->vertex.z + (1.f - fac_b0) * sorted_vs[2]->vertex.z, - 1.f / (1.f / sorted_vs[0]->vertex.w + fac * (1.f / sorted_vs[2]->vertex.w - 1.f / sorted_vs[0]->vertex.w)) + middle_vr_vertex_w }, fac_b0 * sorted_vs[0]->b0 + (1.f - fac_b0) * sorted_vs[2]->b0, fac_b0 * sorted_vs[0]->b1 + (1.f - fac_b0) * sorted_vs[2]->b1 @@ -101,39 +124,30 @@ void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::Tria float b_fac = 1.f / (sub_bb0 / vertex_end.vertex.w + sub_bb1 / middle_vl.vertex.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.vertex.w); float sub_b0 = b_fac * sub_bb0 / vertex_end.vertex.w; float sub_b1 = b_fac * sub_bb1 / middle_vl.vertex.w; - float b0 = sub_b0 * vertex_end.b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; - float b1 = sub_b0 * vertex_end.b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; - math::Vector3 loc{ - b0 * root.vertex1.vertex.x + b1 * root.vertex2.vertex.x + (1.f - b0 - b1) * root.vertex3.vertex.x, - b0 * root.vertex1.vertex.y + b1 * root.vertex2.vertex.y + (1.f - b0 - b1) * root.vertex3.vertex.y, - b0 * root.vertex1.vertex.z + b1 * root.vertex2.vertex.z + (1.f - b0 - b1) * root.vertex3.vertex.z - }; - if (loc.z < depth_buf[x + y * fb->width()]) { - depth_buf[x + y * fb->width()] = loc.z; - fb->draw_point(x, y, loc, o3d::VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1)); + float loc_z = sub_b0 * vertex_end.vertex.z + sub_b1 * middle_vl.vertex.z + (1.f - sub_b0 - sub_b1) * middle_vr.vertex.z; + if (loc_z < depth_buf[x + y * fb.width()]) { + depth_buf[x + y * fb.width()] = loc_z; + float b0 = sub_b0 * vertex_end.b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; + float b1 = sub_b0 * vertex_end.b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; + Vector3 loc{ + b0 * root.vertex1.vertex.x + b1 * root.vertex2.vertex.x + (1.f - b0 - b1) * root.vertex3.vertex.x, + b0 * root.vertex1.vertex.y + b1 * root.vertex2.vertex.y + (1.f - b0 - b1) * root.vertex3.vertex.y, + loc_z + }; + fb.draw_point(x, y, loc, + VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1), + Vector3::bilerp(root.vertex1.normal, root.vertex2.normal, root.vertex3.normal, b0, b1).normalize()); } } } }; - _draw_cropped_triangle_side.operator()<TriangleSide::top>(); - _draw_cropped_triangle_side.operator()<TriangleSide::bottom>(); + _draw_cropped_triangle_side.template operator()<TriangleSide::top>(); + _draw_cropped_triangle_side.template operator()<TriangleSide::bottom>(); } -void Renderer::draw_triangle(o3d::Triangle triangle) { - for (auto t1 : triangle.to_derived().crop_z_out(-1.f, 1.f)) { - for (auto t2 : t1.div_by_w().perspective_crop_xy_out(-1.f, 1.f, -1.f, 1.f)) { - auto pp1 = t2.derived_vertex1.vertex.xy(); - auto pp2 = t2.derived_vertex2.vertex.xy(); - auto pp3 = t2.derived_vertex3.vertex.xy(); - if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue; - float fw_over_2 = static_cast<float>(fb->width()) / 2.f, fh_over_2 = static_cast<float>(fb->height()) / 2.f; - t2.derived_vertex1.vertex.x = (t2.derived_vertex1.vertex.x + 1.f) * fw_over_2 - .5f; - t2.derived_vertex1.vertex.y = (t2.derived_vertex1.vertex.y + 1.f) * fh_over_2 - .5f; - t2.derived_vertex2.vertex.x = (t2.derived_vertex2.vertex.x + 1.f) * fw_over_2 - .5f; - t2.derived_vertex2.vertex.y = (t2.derived_vertex2.vertex.y + 1.f) * fh_over_2 - .5f; - t2.derived_vertex3.vertex.x = (t2.derived_vertex3.vertex.x + 1.f) * fw_over_2 - .5f; - t2.derived_vertex3.vertex.y = (t2.derived_vertex3.vertex.y + 1.f) * fh_over_2 - .5f; - _draw_cropped_triangle(triangle, t2); - } - } -} +template class Renderer<CharacterFrameBuffer>; +template Renderer<CharacterFrameBuffer>::Renderer(CharacterFrameBuffer&&); +template Renderer<CharacterFrameBuffer>::Renderer(const CharacterFrameBuffer&); +template class Renderer<PixelFrameBuffer>; +template Renderer<PixelFrameBuffer>::Renderer(PixelFrameBuffer&&); +template Renderer<PixelFrameBuffer>::Renderer(const PixelFrameBuffer&); |