#include "renderer.h" #include #include #include #include #include "math/vector.h" #include "o3d/vertex.h" #include "o3d/deriv_vertex.h" #include "o3d/tri_vertex.h" #include "o3d/tri_deriv_vertex.h" #include "o3d/vertex_data.h" using namespace engine; Renderer::Renderer(std::unique_ptr 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(); } unsigned int Renderer::height() const { return fb->height(); } void Renderer::clear() { std::fill(depth_buf.begin(), depth_buf.end(), 1.f); fb->clear(); } void Renderer::_draw_cropped_triangle(o3d::TriangleVertex4 root, o3d::TriangleDerivedVertex4 triangle) { std::array sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 }; #define SWAP_IF_LT(X,Y) ({ \ if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) { \ auto temp = sorted_vs[X]; \ sorted_vs[X] = sorted_vs[Y]; \ sorted_vs[Y] = temp; \ } \ }) SWAP_IF_LT(1, 0); SWAP_IF_LT(2, 1); SWAP_IF_LT(1, 0); #undef SWAP_IF_LT auto middle_vl = *sorted_vs[1]; const float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y); const float fac_b0 = (1.f - fac) / sorted_vs[0]->point.w / ((1.f - fac) / sorted_vs[0]->point.w + fac / sorted_vs[2]->point.w); o3d::DerivedVertex4 middle_vr{ { sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x), sorted_vs[1]->point.y, fac_b0 * sorted_vs[0]->point.z + (1.f - fac_b0) * sorted_vs[2]->point.z, 1.f / (1.f / sorted_vs[0]->point.w + fac * (1.f / sorted_vs[2]->point.w - 1.f / sorted_vs[0]->point.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 }; if (middle_vr.point.x < middle_vl.point.x) { auto temp = middle_vr; middle_vr = middle_vl; middle_vl = temp; } // top triangle { if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) { int top_y = static_cast(std::floor(sorted_vs[0]->point.y + 1.f)); int bottom_y = static_cast(std::ceil(sorted_vs[1]->point.y - 1.f)); for (int y = top_y; y <= bottom_y; y++) { float iy = static_cast(y); float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y); float sub_bb0 = 1.f - s; float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x); float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x); int left_x = static_cast(std::ceil(xl)); int right_x = static_cast(std::ceil(xr - 1.f)); for (int x = left_x; x <= right_x; x++) { float ix = static_cast(x); float t = (ix - xl) / (xr - xl); float sub_bb1 = s * (1.f - t); float b_fac = 1.f / (sub_bb0 / sorted_vs[0]->point.w + sub_bb1 / middle_vl.point.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.point.w); float sub_b0 = b_fac * sub_bb0 / sorted_vs[0]->point.w; float sub_b1 = b_fac * sub_bb1 / middle_vl.point.w; float b0 = sub_b0 * sorted_vs[0]->b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; float b1 = sub_b0 * sorted_vs[0]->b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; math::Vector3 loc{ b0 * root.vertex1.point.x + b1 * root.vertex2.point.x + (1.f - b0 - b1) * root.vertex3.point.x, b0 * root.vertex1.point.y + b1 * root.vertex2.point.y + (1.f - b0 - b1) * root.vertex3.point.y, b0 * root.vertex1.point.z + b1 * root.vertex2.point.z + (1.f - b0 - b1) * root.vertex3.point.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)); } } } } } // bottom triangle { if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) { int bottom_y = static_cast(std::floor(sorted_vs[2]->point.y)); int top_y = static_cast(std::ceil(sorted_vs[1]->point.y)); for (int y = top_y; y <= bottom_y; y++) { float iy = static_cast(y); float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y); float sub_bb0 = 1.f - s; float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x); float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x); int left_x = static_cast(std::ceil(xl)); int right_x = static_cast(std::ceil(xr - 1.f)); for (int x = left_x; x <= right_x; x++) { float ix = static_cast(x); float t = (ix - xl) / (xr - xl); float sub_bb1 = s * (1.f - t); float b_fac = 1.f / (sub_bb0 / sorted_vs[2]->point.w + sub_bb1 / middle_vl.point.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.point.w); float sub_b0 = b_fac * sub_bb0 / sorted_vs[2]->point.w; float sub_b1 = b_fac * sub_bb1 / middle_vl.point.w; float b0 = sub_b0 * sorted_vs[2]->b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; float b1 = sub_b0 * sorted_vs[2]->b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; math::Vector3 loc{ b0 * root.vertex1.point.x + b1 * root.vertex2.point.x + (1.f - b0 - b1) * root.vertex3.point.x, b0 * root.vertex1.point.y + b1 * root.vertex2.point.y + (1.f - b0 - b1) * root.vertex3.point.y, b0 * root.vertex1.point.z + b1 * root.vertex2.point.z + (1.f - b0 - b1) * root.vertex3.point.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)); } } } } } } void Renderer::draw_triangle(o3d::TriangleVertex4 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.point.xy(); auto pp2 = t2.derived_vertex2.point.xy(); auto pp3 = t2.derived_vertex3.point.xy(); if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue; float fw_over_2 = static_cast(fb->width()) / 2.f, fh_over_2 = static_cast(fb->height()) / 2.f; t2.derived_vertex1.point.x = (t2.derived_vertex1.point.x + 1.f) * fw_over_2 - .5f; t2.derived_vertex1.point.y = (t2.derived_vertex1.point.y + 1.f) * fh_over_2 - .5f; t2.derived_vertex2.point.x = (t2.derived_vertex2.point.x + 1.f) * fw_over_2 - .5f; t2.derived_vertex2.point.y = (t2.derived_vertex2.point.y + 1.f) * fh_over_2 - .5f; t2.derived_vertex3.point.x = (t2.derived_vertex3.point.x + 1.f) * fw_over_2 - .5f; t2.derived_vertex3.point.y = (t2.derived_vertex3.point.y + 1.f) * fh_over_2 - .5f; _draw_cropped_triangle(triangle, t2); } } }