aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am3
-rw-r--r--src/math/utils.hpp16
-rw-r--r--src/math/vector.hpp205
-rw-r--r--src/o3d/deriv_vertex.hpp19
-rw-r--r--src/o3d/polygon.hpp158
-rw-r--r--src/o3d/tri.hpp4
-rw-r--r--src/o3d/tri_deriv.cpp313
-rw-r--r--src/o3d/tri_deriv.hpp15
-rw-r--r--src/renderer.cpp74
-rw-r--r--src/renderer.hpp2
10 files changed, 436 insertions, 373 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e8f98a1..f7741a6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,7 +22,8 @@ engine_SOURCES = \
o3d/vertex.hpp \
o3d/deriv_vertex.hpp \
o3d/tri.hpp \
- o3d/tri_deriv.hpp o3d/tri_deriv.cpp \
+ o3d/tri_deriv.hpp \
+ o3d/polygon.hpp \
o3d/camera.hpp \
o3d/scene.hpp \
ctrl/keyboard.hpp \
diff --git a/src/math/utils.hpp b/src/math/utils.hpp
index 5ec5959..5c8c62d 100644
--- a/src/math/utils.hpp
+++ b/src/math/utils.hpp
@@ -5,6 +5,14 @@
#include <utility>
#include "math/vector.hpp"
+namespace engine::math {
+
+struct Vector2;
+struct Vector3;
+struct Vector4;
+
+}
+
namespace engine::math::utils {
template<size_t size> struct Vector;
@@ -19,6 +27,14 @@ constexpr Vector<vector_size>::type array_to_vec(const std::array<float, vector_
}(std::make_index_sequence<vector_size>());
}
+constexpr float lerp(float a, float b, float t) {
+ return a + t * (b - a);
+}
+
+constexpr float map(float x, float from1, float from2, float to1, float to2) {
+ return to1 + (x - from1) * (to2 - to1) / (from2 - from1);
+}
+
}
#endif // MATH_UTILS_HPP
diff --git a/src/math/vector.hpp b/src/math/vector.hpp
index 471f30d..def469b 100644
--- a/src/math/vector.hpp
+++ b/src/math/vector.hpp
@@ -5,7 +5,122 @@
namespace engine::math {
+namespace vector_coords {
+
+enum class VectorCoord { x, y, z, w };
+
+template<VectorCoord id1, VectorCoord id2>
+struct transpose { template<VectorCoord input> static constexpr VectorCoord id(); };
+
+template<> struct transpose<VectorCoord::x, VectorCoord::x> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::x, VectorCoord::y> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::x, VectorCoord::z> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::x, VectorCoord::w> { template<VectorCoord input> static constexpr VectorCoord id(); };
+
+template<> struct transpose<VectorCoord::y, VectorCoord::x> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::y, VectorCoord::y> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::y, VectorCoord::z> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::y, VectorCoord::w> { template<VectorCoord input> static constexpr VectorCoord id(); };
+
+template<> struct transpose<VectorCoord::z, VectorCoord::x> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::z, VectorCoord::y> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::z, VectorCoord::z> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::z, VectorCoord::w> { template<VectorCoord input> static constexpr VectorCoord id(); };
+
+template<> struct transpose<VectorCoord::w, VectorCoord::x> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::w, VectorCoord::y> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::w, VectorCoord::z> { template<VectorCoord input> static constexpr VectorCoord id(); };
+template<> struct transpose<VectorCoord::w, VectorCoord::w> { template<VectorCoord input> static constexpr VectorCoord id(); };
+
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::x>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::x>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::x>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::x>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::y>::id<VectorCoord::x>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::y>::id<VectorCoord::y>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::y>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::y>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::z>::id<VectorCoord::x>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::z>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::z>::id<VectorCoord::z>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::z>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::w>::id<VectorCoord::x>() { return VectorCoord::w; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::w>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::w>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::x, VectorCoord::w>::id<VectorCoord::w>() { return VectorCoord::x; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::x>::id<VectorCoord::x>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::x>::id<VectorCoord::y>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::x>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::x>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::y>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::y>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::y>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::y>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::z>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::z>::id<VectorCoord::y>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::z>::id<VectorCoord::z>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::z>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::w>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::w>::id<VectorCoord::y>() { return VectorCoord::w; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::w>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::y, VectorCoord::w>::id<VectorCoord::w>() { return VectorCoord::y; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::x>::id<VectorCoord::x>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::x>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::x>::id<VectorCoord::z>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::x>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::y>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::y>::id<VectorCoord::y>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::y>::id<VectorCoord::z>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::y>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::z>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::z>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::z>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::z>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::w>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::w>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::w>::id<VectorCoord::z>() { return VectorCoord::w; }
+template<> constexpr VectorCoord transpose<VectorCoord::z, VectorCoord::w>::id<VectorCoord::w>() { return VectorCoord::z; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::x>::id<VectorCoord::x>() { return VectorCoord::w; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::x>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::x>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::x>::id<VectorCoord::w>() { return VectorCoord::x; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::y>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::y>::id<VectorCoord::y>() { return VectorCoord::w; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::y>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::y>::id<VectorCoord::w>() { return VectorCoord::y; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::z>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::z>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::z>::id<VectorCoord::z>() { return VectorCoord::w; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::z>::id<VectorCoord::w>() { return VectorCoord::z; }
+
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::w>::id<VectorCoord::x>() { return VectorCoord::x; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::w>::id<VectorCoord::y>() { return VectorCoord::y; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::w>::id<VectorCoord::z>() { return VectorCoord::z; }
+template<> constexpr VectorCoord transpose<VectorCoord::w, VectorCoord::w>::id<VectorCoord::w>() { return VectorCoord::w; }
+
+}
+
struct Vector2;
+struct Vector3;
+struct Vector4;
+
+template<typename T>
+concept VectorTypeConcept = std::is_same_v<T, Vector2> || std::is_same_v<T, Vector3> || std::is_same_v<T, Vector4>;
+
constexpr Vector2 operator*(float n, const Vector2& other);
constexpr Vector2 operator/(const Vector2& other, float n);
@@ -18,6 +133,25 @@ struct Vector2 {
float x, y;
+ constexpr Vector2() {}
+ constexpr Vector2(float x, float y) : x { x }, y { y } {}
+
+ template<vector_coords::VectorCoord id>
+ constexpr float& v() &
+ requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y)
+ {
+ if constexpr (id == vector_coords::VectorCoord::x) return x;
+ else return y;
+ }
+
+ template<vector_coords::VectorCoord id>
+ constexpr const float& v() const &
+ requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y)
+ {
+ if constexpr (id == vector_coords::VectorCoord::x) return x;
+ else return y;
+ }
+
constexpr bool operator==(const Vector2& other) const & {
return x == other.x && y == other.y;
}
@@ -59,6 +193,13 @@ struct Vector2 {
constexpr Vector2 mul_term(const Vector2& other) const & {
return { x * other.x, y * other.y };
}
+
+ constexpr Vector2 map(const Vector2& from1, const Vector2& from2, const Vector2& to1, const Vector2& to2) {
+ return {
+ to1.x + (x - from1.x) * (to2.x - to1.x) / (from2.x - from1.x),
+ to1.y + (y - from1.y) * (to2.y - to1.y) / (from2.y - from1.y),
+ };
+ }
};
constexpr Vector2 operator*(float n, const Vector2& other) {
@@ -81,7 +222,6 @@ constexpr Vector2 operator-(const Vector2& other, float n) {
return { other.x - n, other.y - n };
}
-struct Vector3;
constexpr Vector3 operator*(float n, const Vector3& other);
constexpr Vector3 operator/(const Vector3& other, float n);
@@ -94,6 +234,28 @@ struct Vector3 {
float x, y, z;
+ constexpr Vector3() {}
+ constexpr Vector3(float x, float y, float z) : x { x }, y { y }, z { z } {}
+ constexpr Vector3(const Vector2& v, float z) : x { v.x }, y { v.y }, z { z } {}
+
+ template<vector_coords::VectorCoord id>
+ constexpr float& v() &
+ requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y || id == vector_coords::VectorCoord::z)
+ {
+ if constexpr (id == vector_coords::VectorCoord::x) return x;
+ else if constexpr (id == vector_coords::VectorCoord::y) return y;
+ else return z;
+ }
+
+ template<vector_coords::VectorCoord id>
+ constexpr const float& v() const &
+ requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y || id == vector_coords::VectorCoord::z)
+ {
+ if constexpr (id == vector_coords::VectorCoord::x) return x;
+ else if constexpr (id == vector_coords::VectorCoord::y) return y;
+ else return z;
+ }
+
constexpr bool operator==(const Vector3& other) const & {
return x == other.x && y == other.y && z == other.z;
}
@@ -125,6 +287,10 @@ struct Vector3 {
return *this;
}
+ constexpr Vector2 xy() const & {
+ return { x, y };
+ }
+
constexpr Vector3 round() {
return { std::round(x), std::round(y), std::round(z) };
}
@@ -152,6 +318,14 @@ struct Vector3 {
constexpr Vector3 normalize() const & {
return *this / length();
}
+
+ constexpr Vector3 map(const Vector3& from1, const Vector3& from2, const Vector3& to1, const Vector3& to2) {
+ return {
+ to1.x + (x - from1.x) * (to2.x - to1.x) / (from2.x - from1.x),
+ to1.y + (y - from1.y) * (to2.y - to1.y) / (from2.y - from1.y),
+ to1.z + (z - from1.z) * (to2.z - to1.z) / (from2.z - from1.z),
+ };
+ }
};
constexpr Vector3 operator*(float n, const Vector3& other) {
@@ -175,6 +349,22 @@ struct Vector4 {
float x, y, z, w;
+ template<vector_coords::VectorCoord id>
+ constexpr float& v() & {
+ if constexpr (id == vector_coords::VectorCoord::x) return x;
+ else if constexpr (id == vector_coords::VectorCoord::y) return y;
+ else if constexpr (id == vector_coords::VectorCoord::z) return z;
+ else return w;
+ }
+
+ template<vector_coords::VectorCoord id>
+ constexpr const float& v() const & {
+ if constexpr (id == vector_coords::VectorCoord::x) return x;
+ else if constexpr (id == vector_coords::VectorCoord::y) return y;
+ else if constexpr (id == vector_coords::VectorCoord::z) return z;
+ else return w;
+ }
+
constexpr Vector4() {}
constexpr Vector4(float x, float y, float z, float w) : x{x}, y{y}, z{z}, w{w} {}
constexpr Vector4(const Vector2& v, float z, float w) : x{v.x}, y{v.y}, z{z}, w{w} {}
@@ -216,8 +406,17 @@ struct Vector4 {
return { x, y, z };
}
- constexpr Vector4 div_by_w() const & {
- return {x / w, y / w, z / w, w};
+ constexpr Vector3 div_by_w() const & {
+ return { x / w, y / w, w };
+ }
+
+ constexpr Vector4 map(const Vector4& from1, const Vector4& from2, const Vector4& to1, const Vector4& to2) {
+ return {
+ to1.x + (x - from1.x) * (to2.x - to1.x) / (from2.x - from1.x),
+ to1.y + (y - from1.y) * (to2.y - to1.y) / (from2.y - from1.y),
+ to1.z + (z - from1.z) * (to2.z - to1.z) / (from2.z - from1.z),
+ to1.w + (w - from1.w) * (to2.w - to1.w) / (from2.w - from1.w),
+ };
}
};
diff --git a/src/o3d/deriv_vertex.hpp b/src/o3d/deriv_vertex.hpp
index 5e8dc22..48e5912 100644
--- a/src/o3d/deriv_vertex.hpp
+++ b/src/o3d/deriv_vertex.hpp
@@ -5,12 +5,27 @@
namespace engine::o3d {
+template<engine::math::VectorTypeConcept VectorType>
struct DerivedVertex {
+ VectorType vertex;
+ float b0, b1;
+
+ constexpr DerivedVertex() {}
+
+ constexpr DerivedVertex(const VectorType& vertex, float b0, float b1) : vertex { vertex }, b0 { b0 }, b1 { b1 } {}
+};
+
+template<>
+struct DerivedVertex<engine::math::Vector4> {
engine::math::Vector4 vertex;
float b0, b1;
- constexpr DerivedVertex div_by_w() const & {
- return {vertex.div_by_w(), b0, b1};
+ constexpr DerivedVertex() {}
+
+ constexpr DerivedVertex(const engine::math::Vector4& vertex, float b0, float b1) : vertex { vertex }, b0 { b0 }, b1 { b1 } {}
+
+ constexpr DerivedVertex<engine::math::Vector3> div_by_w() const & {
+ return { vertex.div_by_w(), b0, b1 };
}
};
diff --git a/src/o3d/polygon.hpp b/src/o3d/polygon.hpp
new file mode 100644
index 0000000..5ede910
--- /dev/null
+++ b/src/o3d/polygon.hpp
@@ -0,0 +1,158 @@
+#ifndef O3D_POLYGON_HPP
+#define O3D_POLYGON_HPP
+
+#include <cstddef>
+#include <array>
+#include <type_traits>
+#include <tuple>
+#include "math/vector.hpp"
+#include "math/utils.hpp"
+#include "o3d/deriv_vertex.hpp"
+#include "o3d/tri_deriv.hpp"
+
+namespace engine::o3d::polygon {
+
+template<typename T>
+concept PolygonVectorTypeConcept = engine::math::VectorTypeConcept<T> && (std::is_same_v<T, engine::math::Vector3> || std::is_same_v<T, engine::math::Vector4>);
+
+template<PolygonVectorTypeConcept VectorType, std::size_t max_points_count> struct Polygon;
+
+template<engine::math::VectorTypeConcept VectorType>
+constexpr Polygon<VectorType, 3> from_triangle_derived(const engine::o3d::TriangleDerived<VectorType>& triangle_derived);
+
+template<PolygonVectorTypeConcept VectorType, std::size_t max_points_count, engine::math::vector_coords::VectorCoord coord_id, bool keep_geq>
+constexpr Polygon<VectorType, max_points_count + 1> clip_aligned(float boundary, const Polygon<VectorType, max_points_count>& polygon);
+
+template<PolygonVectorTypeConcept VectorType, std::size_t max_points_count>
+struct Polygon {
+ std::size_t points_count;
+ std::array<engine::o3d::DerivedVertex<VectorType>, max_points_count> points;
+
+ constexpr Polygon() : points_count { 0 } {}
+ constexpr Polygon(std::size_t points_count, std::array<engine::o3d::DerivedVertex<VectorType>, max_points_count> points)
+ : points_count { points_count }, points { points } {}
+
+ constexpr Polygon<VectorType, max_points_count + 2> clip_z(float z1, float z2) const & {
+ return
+ clip_aligned<VectorType, max_points_count + 1, engine::math::vector_coords::VectorCoord::z, false>(z2,
+ clip_aligned<VectorType, max_points_count + 0, engine::math::vector_coords::VectorCoord::z, true >(z1,
+ *this));
+ }
+
+ constexpr Polygon<VectorType, max_points_count + 4> clip_xy(float x1, float y1, float x2, float y2) const & {
+ return
+ clip_aligned<VectorType, max_points_count + 3, engine::math::vector_coords::VectorCoord::y, false>(y2,
+ clip_aligned<VectorType, max_points_count + 2, engine::math::vector_coords::VectorCoord::x, false>(x2,
+ clip_aligned<VectorType, max_points_count + 1, engine::math::vector_coords::VectorCoord::y, true >(y1,
+ clip_aligned<VectorType, max_points_count + 0, engine::math::vector_coords::VectorCoord::x, true >(x1,
+ *this))));
+ }
+
+ constexpr Polygon<VectorType, max_points_count> map_xy(
+ const engine::math::Vector2& from1, const engine::math::Vector2& from2,
+ const engine::math::Vector2& to1, const engine::math::Vector2& to2) const & {
+ Polygon<VectorType, max_points_count> polygon;
+ polygon.points_count = points_count;
+ for (std::size_t i = 0; i < points_count; i++) {
+ auto& p = polygon.points[i];
+ if constexpr (std::is_same_v<VectorType, engine::math::Vector3>) {
+ p.vertex = {
+ points[i].vertex.xy().map(from1, from2, to1, to2),
+ points[i].vertex.z,
+ };
+ } else {
+ p.vertex = {
+ points[i].vertex.xy().map(from1, from2, to1, to2),
+ points[i].vertex.z,
+ points[i].vertex.w,
+ };
+ }
+ p.b0 = points[i].b0;
+ p.b1 = points[i].b1;
+ }
+ return polygon;
+ }
+
+ constexpr std::tuple<std::size_t, std::array<engine::o3d::TriangleDerived<engine::math::Vector3>, max_points_count - 2>> to_triangles() const &
+ requires (max_points_count >= 3)
+ {
+ std::array<engine::o3d::TriangleDerived<VectorType>, max_points_count - 2> triangles;
+ if (points_count < 3) return { 0, triangles };
+ for (std::size_t i = 0; i < points_count - 2; i++)
+ triangles[i] = { points[0], points[i + 1], points[i + 2] };
+ return { points_count - 2, triangles };
+ }
+
+ constexpr std::tuple<std::size_t, std::array<engine::o3d::TriangleDerived<engine::math::Vector3>, 0>> to_triangles() const & {
+ return { 0, {} };
+ }
+};
+
+template<engine::math::VectorTypeConcept VectorType>
+constexpr Polygon<VectorType, 3> from_triangle_derived(const engine::o3d::TriangleDerived<VectorType>& triangle_derived) {
+ return { 3, { triangle_derived.derived_vertex1, triangle_derived.derived_vertex2, triangle_derived.derived_vertex3 } };
+}
+
+template<PolygonVectorTypeConcept VectorType, std::size_t max_points_count, engine::math::vector_coords::VectorCoord coord_id, bool keep_geq>
+constexpr Polygon<VectorType, max_points_count + 1> clip_aligned(float boundary, const Polygon<VectorType, max_points_count>& polygon)
+{
+ using transposition = engine::math::vector_coords::transpose<engine::math::vector_coords::VectorCoord::x, coord_id>;
+ constexpr auto y_coord_id = transposition::template id<engine::math::vector_coords::VectorCoord::y>();
+ constexpr auto z_coord_id = transposition::template id<engine::math::vector_coords::VectorCoord::z>();
+ constexpr auto is_in = [](const engine::o3d::DerivedVertex<VectorType>& p, float boundary) constexpr {
+ if constexpr (keep_geq) return p.vertex.template v<coord_id>() >= boundary;
+ else return p.vertex.template v<coord_id>() <= boundary;
+ };
+ Polygon<VectorType, max_points_count + 1> new_polygon;
+ for (size_t i = 0; i < polygon.points_count; i++) {
+ const auto& prev = polygon.points[(i + polygon.points_count - 1) % polygon.points_count];
+ const auto& cur = polygon.points[i];
+ if (is_in(prev, boundary) != is_in(cur, boundary)) {
+ float fac = (boundary - prev.vertex.template v<coord_id>()) / (cur.vertex.template v<coord_id>() - prev.vertex.template v<coord_id>());
+ auto& new_point = new_polygon.points[new_polygon.points_count++];
+ new_point.vertex.template v<coord_id>() = boundary;
+ new_point.vertex.template v<y_coord_id>() = engine::math::utils::lerp(prev.vertex.template v<y_coord_id>(), cur.vertex.template v<y_coord_id>(), fac);
+ if constexpr (std::is_same_v<VectorType, engine::math::Vector3>) {
+ // called new_w because it represents w, but because we only need x, y and w, we use
+ // Vector3, and therefore the vector coordinate's name is z
+ float new_w = 1.f / ((1.f - fac) / prev.vertex.z + fac / cur.vertex.z);
+ new_point.vertex.template v<z_coord_id>() = new_w;
+ new_point.b0 = new_w * engine::math::utils::lerp(prev.b0 / prev.vertex.z, cur.b0 / cur.vertex.z, fac);
+ new_point.b1 = new_w * engine::math::utils::lerp(prev.b1 / prev.vertex.z, cur.b1 / cur.vertex.z, fac);
+ } else { // Vector4
+ constexpr auto w_coord_id = transposition::template id<engine::math::vector_coords::VectorCoord::w>();
+ new_point.vertex.template v<z_coord_id>() = engine::math::utils::lerp(prev.vertex.template v<z_coord_id>(), cur.vertex.template v<z_coord_id>(), fac);
+ new_point.vertex.template v<w_coord_id>() = engine::math::utils::lerp(prev.vertex.template v<w_coord_id>(), cur.vertex.template v<w_coord_id>(), fac);
+ new_point.b0 = engine::math::utils::lerp(prev.b0, cur.b0, fac);
+ new_point.b1 = engine::math::utils::lerp(prev.b1, cur.b1, fac);
+ }
+ }
+ if (is_in(cur, boundary))
+ new_polygon.points[new_polygon.points_count++] = cur;
+ }
+ return new_polygon;
+}
+
+template<std::size_t max_points_count>
+constexpr Polygon<engine::math::Vector3, max_points_count> div_by_w(const Polygon<engine::math::Vector4, max_points_count>& polygon) {
+ Polygon<engine::math::Vector3, max_points_count> new_polygon;
+ new_polygon.points_count = polygon.points_count;
+ for (std::size_t i = 0; i < polygon.points_count; i++)
+ new_polygon.points[i] = polygon.points[i].div_by_w();
+ return new_polygon;
+}
+
+template<std::size_t max_points_count>
+constexpr float signed_area_xy(const Polygon<engine::math::Vector3, max_points_count>& polygon) {
+ float res = 0.f;
+ if (polygon.points_count > 0) {
+ for (std::size_t i = 0; i < polygon.points_count - 1; i++)
+ res += polygon.points[i].vertex.xy().det(polygon.points[i + 1].vertex.xy());
+ res += polygon.points[polygon.points_count - 1].vertex.xy().det(polygon.points[0].vertex.xy());
+ }
+ return .5f * res;
+}
+
+}
+
+#endif // O3D_POLYGON_HPP
diff --git a/src/o3d/tri.hpp b/src/o3d/tri.hpp
index 712c135..56ff1dd 100644
--- a/src/o3d/tri.hpp
+++ b/src/o3d/tri.hpp
@@ -12,8 +12,8 @@ struct Triangle {
Vertex vertex2;
Vertex vertex3;
- constexpr TriangleDerived to_derived() const & {
- return {{vertex1.vertex, 1.f, 0.f}, {vertex2.vertex, 0.f, 1.f}, {vertex3.vertex, 0.f, 0.f}};
+ constexpr TriangleDerived<engine::math::Vector4> to_derived() const & {
+ return { { vertex1.vertex, 1.f, 0.f }, { vertex2.vertex, 0.f, 1.f }, { vertex3.vertex, 0.f, 0.f } };
}
};
diff --git a/src/o3d/tri_deriv.cpp b/src/o3d/tri_deriv.cpp
deleted file mode 100644
index 79e3fb4..0000000
--- a/src/o3d/tri_deriv.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-#include "o3d/tri_deriv.hpp"
-#include <vector>
-#include "math/vector.hpp"
-#include "o3d/deriv_vertex.hpp"
-
-using namespace engine::o3d;
-
-#define P1_OUT 1
-#define P2_OUT 2
-#define P3_OUT 4
-static void _perspective_crop_x(std::vector<TriangleDerived>& tris, TriangleDerived t, int n, float x) {
- switch (n) {
- case 0:
- tris.push_back(t);
- break;
- case P1_OUT:
- case P2_OUT:
- case P3_OUT:
- case P2_OUT | P3_OUT:
- case P1_OUT | P3_OUT:
- case P1_OUT | P2_OUT:
- {
- DerivedVertex* q1;
- DerivedVertex* q2;
- DerivedVertex* q3;
- switch (n) {
- case P1_OUT:
- case P2_OUT | P3_OUT:
- q1 = &t.derived_vertex1;
- q2 = &t.derived_vertex2;
- q3 = &t.derived_vertex3;
- break;
- case P2_OUT:
- case P1_OUT | P3_OUT:
- q1 = &t.derived_vertex2;
- q2 = &t.derived_vertex1;
- q3 = &t.derived_vertex3;
- break;
- case P3_OUT:
- case P1_OUT | P2_OUT:
- q1 = &t.derived_vertex3;
- q2 = &t.derived_vertex2;
- q3 = &t.derived_vertex1;
- break;
- }
- engine::math::Vector4 dq2 = q1->vertex - q2->vertex;
- float fac2 = (x - q2->vertex.x) / dq2.x;
- float r2w = 1.f / (fac2 / q1->vertex.w + (1.f - fac2) / q2->vertex.w);
- float fac2_b = r2w * fac2 / q1->vertex.w;
- DerivedVertex r2{
- {
- x,
- q2->vertex.y + fac2 * dq2.y,
- (fac2_b * q1->vertex.w * q1->vertex.z + (1.f - fac2_b) * q2->vertex.w * q2->vertex.z) / r2w,
- r2w
- },
- fac2_b * q1->b0 + (1.f - fac2_b) * q2->b0,
- fac2_b * q1->b1 + (1.f - fac2_b) * q2->b1
- };
- engine::math::Vector4 dq3 = q1->vertex - q3->vertex;
- float fac3 = (x - q3->vertex.x) / dq3.x;
- float r3w = 1.f / (fac3 / q1->vertex.w + (1.f - fac3) / q3->vertex.w);
- float fac3_b = r3w * fac3 / q1->vertex.w;
- DerivedVertex r3{
- {
- x,
- q3->vertex.y + fac3 * dq3.y,
- (fac3_b * q1->vertex.w * q1->vertex.z + (1.f - fac3_b) * q3->vertex.w * q3->vertex.z) / r3w,
- r3w
- },
- fac3_b * q1->b0 + (1.f - fac3_b) * q3->b0,
- fac3_b * q1->b1 + (1.f - fac3_b) * q3->b1
- };
- switch (n) {
- case P1_OUT:
- tris.push_back({r3, *q2, *q3});
- tris.push_back({r3, r2, *q2});
- break;
- case P2_OUT:
- tris.push_back({r2, *q3, *q2});
- tris.push_back({r2, r3, *q3});
- break;
- case P3_OUT:
- tris.push_back({r2, *q3, *q2});
- tris.push_back({r2, r3, *q3});
- break;
- case P2_OUT | P3_OUT:
- tris.push_back({*q1, r2, r3});
- break;
- case P1_OUT | P3_OUT:
- tris.push_back({*q1, r3, r2});
- break;
- case P1_OUT | P2_OUT:
- tris.push_back({*q1, r3, r2});
- break;
- }
- }
- break;
- case P1_OUT | P2_OUT | P3_OUT:
- break;
- }
-}
-
-static void _perspective_crop_y(std::vector<TriangleDerived>& tris, TriangleDerived t, int n, float y) {
- switch (n) {
- case 0:
- tris.push_back(t);
- break;
- case P1_OUT:
- case P2_OUT:
- case P3_OUT:
- case P2_OUT | P3_OUT:
- case P1_OUT | P3_OUT:
- case P1_OUT | P2_OUT:
- {
- DerivedVertex* q1;
- DerivedVertex* q2;
- DerivedVertex* q3;
- switch (n) {
- case P1_OUT:
- case P2_OUT | P3_OUT:
- q1 = &t.derived_vertex1;
- q2 = &t.derived_vertex2;
- q3 = &t.derived_vertex3;
- break;
- case P2_OUT:
- case P1_OUT | P3_OUT:
- q1 = &t.derived_vertex2;
- q2 = &t.derived_vertex1;
- q3 = &t.derived_vertex3;
- break;
- case P3_OUT:
- case P1_OUT | P2_OUT:
- q1 = &t.derived_vertex3;
- q2 = &t.derived_vertex2;
- q3 = &t.derived_vertex1;
- break;
- }
- engine::math::Vector4 dq2 = q1->vertex - q2->vertex;
- float fac2 = (y - q2->vertex.y) / dq2.y;
- float r2w = 1.f / (fac2 / q1->vertex.w + (1.f - fac2) / q2->vertex.w);
- float fac2_b = r2w * fac2 / q1->vertex.w;
- DerivedVertex r2{
- {
- q2->vertex.x + fac2 * dq2.x,
- y,
- (fac2_b * q1->vertex.w * q1->vertex.z + (1.f - fac2_b) * q2->vertex.w * q2->vertex.z) / r2w,
- r2w
- },
- fac2_b * q1->b0 + (1.f - fac2_b) * q2->b0,
- fac2_b * q1->b1 + (1.f - fac2_b) * q2->b1
- };
- engine::math::Vector4 dq3 = q1->vertex - q3->vertex;
- float fac3 = (y - q3->vertex.y) / dq3.y;
- float r3w = 1.f / (fac3 / q1->vertex.w + (1.f - fac3) / q3->vertex.w);
- float fac3_b = r3w * fac3 / q1->vertex.w;
- DerivedVertex r3{
- {
- q3->vertex.x + fac3 * dq3.x,
- y,
- (fac3_b * q1->vertex.w * q1->vertex.z + (1.f - fac3_b) * q3->vertex.w * q3->vertex.z) / r3w,
- r3w
- },
- fac3_b * q1->b0 + (1.f - fac3_b) * q3->b0,
- fac3_b * q1->b1 + (1.f - fac3_b) * q3->b1
- };
- switch (n) {
- case P1_OUT:
- tris.push_back({r3, *q2, *q3});
- tris.push_back({r3, r2, *q2});
- break;
- case P2_OUT:
- tris.push_back({r2, *q3, *q2});
- tris.push_back({r2, r3, *q3});
- break;
- case P3_OUT:
- tris.push_back({r2, *q3, *q2});
- tris.push_back({r2, r3, *q3});
- break;
- case P2_OUT | P3_OUT:
- tris.push_back({*q1, r2, r3});
- break;
- case P1_OUT | P3_OUT:
- tris.push_back({*q1, r3, r2});
- break;
- case P1_OUT | P2_OUT:
- tris.push_back({*q1, r3, r2});
- break;
- }
- }
- break;
- case P1_OUT | P2_OUT | P3_OUT:
- break;
- }
-}
-
-std::vector<TriangleDerived> TriangleDerived::perspective_crop_xy_out(float x1, float x2, float y1, float y2) const {
- std::vector<TriangleDerived> tris_final;
- std::vector<TriangleDerived> tris1;
- _perspective_crop_x(tris1, *this, (derived_vertex1.vertex.x < x1) | ((derived_vertex2.vertex.x < x1) << 1) | ((derived_vertex3.vertex.x < x1) << 2), x1);
- for (auto t1 : tris1) {
- std::vector<TriangleDerived> tris2;
- _perspective_crop_x(tris2, t1, (t1.derived_vertex1.vertex.x > x2) | ((t1.derived_vertex2.vertex.x > x2) << 1) | ((t1.derived_vertex3.vertex.x > x2) << 2), x2);
- for (auto t2 : tris2) {
- std::vector<TriangleDerived> tris3;
- _perspective_crop_y(tris3, t2, (t2.derived_vertex1.vertex.y < y1) | ((t2.derived_vertex2.vertex.y < y1) << 1) | ((t2.derived_vertex3.vertex.y < y1) << 2), y1);
- for (auto t3 : tris3)
- _perspective_crop_y(tris_final, t3, (t3.derived_vertex1.vertex.y > y2) | ((t3.derived_vertex2.vertex.y > y2) << 1) | ((t3.derived_vertex3.vertex.y > y2) << 2), y2);
- }
- }
- return tris_final;
-}
-
-static void _crop_z(std::vector<TriangleDerived>& tris, TriangleDerived t, int n, float z) {
- switch (n) {
- case 0:
- tris.push_back(t);
- break;
- case P1_OUT:
- case P2_OUT:
- case P3_OUT:
- case P2_OUT | P3_OUT:
- case P1_OUT | P3_OUT:
- case P1_OUT | P2_OUT:
- {
- DerivedVertex* q1;
- DerivedVertex* q2;
- DerivedVertex* q3;
- switch (n) {
- case P1_OUT:
- case P2_OUT | P3_OUT:
- q1 = &t.derived_vertex1;
- q2 = &t.derived_vertex2;
- q3 = &t.derived_vertex3;
- break;
- case P2_OUT:
- case P1_OUT | P3_OUT:
- q1 = &t.derived_vertex2;
- q2 = &t.derived_vertex1;
- q3 = &t.derived_vertex3;
- break;
- case P3_OUT:
- case P1_OUT | P2_OUT:
- q1 = &t.derived_vertex3;
- q2 = &t.derived_vertex2;
- q3 = &t.derived_vertex1;
- break;
- }
- engine::math::Vector4 dq2 = q1->vertex - q2->vertex;
- float fac2 = (z - q2->vertex.z) / dq2.z;
- DerivedVertex r2{
- {
- q2->vertex.x + fac2 * dq2.x,
- q2->vertex.y + fac2 * dq2.y,
- z,
- q2->vertex.w + fac2 * dq2.w
- },
- fac2 * q1->b0 + (1.f - fac2) * q2->b0,
- fac2 * q1->b1 + (1.f - fac2) * q2->b1
- };
- engine::math::Vector4 dq3 = q1->vertex - q3->vertex;
- float fac3 = (z - q3->vertex.z) / dq3.z;
- DerivedVertex r3{
- {
- q3->vertex.x + fac3 * dq3.x,
- q3->vertex.y + fac3 * dq3.y,
- z,
- q3->vertex.w + fac3 * dq3.w
- },
- fac3 * q1->b0 + (1.f - fac3) * q3->b0,
- fac3 * q1->b1 + (1.f - fac3) * q3->b1
- };
- switch (n) {
- case P1_OUT:
- tris.push_back({r3, *q2, *q3});
- tris.push_back({r3, r2, *q2});
- break;
- case P2_OUT:
- tris.push_back({r2, *q3, *q2});
- tris.push_back({r2, r3, *q3});
- break;
- case P3_OUT:
- tris.push_back({r2, *q3, *q2});
- tris.push_back({r2, r3, *q3});
- break;
- case P2_OUT | P3_OUT:
- tris.push_back({*q1, r2, r3});
- break;
- case P1_OUT | P3_OUT:
- tris.push_back({*q1, r3, r2});
- break;
- case P1_OUT | P2_OUT:
- tris.push_back({*q1, r3, r2});
- break;
- }
- }
- break;
- case P1_OUT | P2_OUT | P3_OUT:
- break;
- }
-}
-
-std::vector<TriangleDerived> TriangleDerived::crop_z_out(float z1, float z2) const {
- std::vector<TriangleDerived> tris;
- _crop_z(tris, *this, (derived_vertex1.vertex.z < z1) | ((derived_vertex2.vertex.z < z1) << 1) | ((derived_vertex3.vertex.z < z1) << 2), z1);
- std::vector<TriangleDerived> tris2;
- for (auto t : tris)
- _crop_z(tris2, t, (t.derived_vertex1.vertex.z > z2) | ((t.derived_vertex2.vertex.z > z2) << 1) | ((t.derived_vertex3.vertex.z > z2) << 2), z2);
- return tris2;
-}
-#undef P1_OUT
-#undef P2_OUT
-#undef P3_OUT
diff --git a/src/o3d/tri_deriv.hpp b/src/o3d/tri_deriv.hpp
index 65713ed..64369fc 100644
--- a/src/o3d/tri_deriv.hpp
+++ b/src/o3d/tri_deriv.hpp
@@ -1,23 +1,16 @@
#ifndef O3D_TRI_VERTEX_HPP
#define O3D_TRI_VERTEX_HPP
-#include <vector>
#include "o3d/vertex.hpp"
#include "o3d/deriv_vertex.hpp"
namespace engine::o3d {
+template<engine::math::VectorTypeConcept VectorType>
struct TriangleDerived {
- DerivedVertex derived_vertex1;
- DerivedVertex derived_vertex2;
- DerivedVertex derived_vertex3;
-
- std::vector<TriangleDerived> perspective_crop_xy_out(float x1, float x2, float y1, float y2) const;
- std::vector<TriangleDerived> crop_z_out(float z1, float z2) const;
-
- constexpr TriangleDerived div_by_w() const & {
- return {derived_vertex1.div_by_w(), derived_vertex2.div_by_w(), derived_vertex3.div_by_w()};
- }
+ DerivedVertex<VectorType> derived_vertex1;
+ DerivedVertex<VectorType> derived_vertex2;
+ DerivedVertex<VectorType> derived_vertex3;
};
}
diff --git a/src/renderer.cpp b/src/renderer.cpp
index cf97af8..35e3ab3 100644
--- a/src/renderer.cpp
+++ b/src/renderer.cpp
@@ -1,9 +1,12 @@
#include "renderer.hpp"
+#include <cstddef>
#include <memory>
#include <array>
+#include <tuple>
#include "math/vector.hpp"
#include "o3d/tri.hpp"
#include "o3d/tri_deriv.hpp"
+#include "o3d/polygon.hpp"
#include "fb/chfb.hpp"
#include "fb/pixfb.hpp"
@@ -36,31 +39,26 @@ void Renderer<FrameBuffer>::clear() {
fb.clear();
}
-enum TriangleSide { top, bottom };
+enum class TriangleSide { top, bottom };
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(0.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);
- }
- }
+ const auto& polygon = engine::o3d::polygon::div_by_w(engine::o3d::polygon::from_triangle_derived(triangle.to_derived()).clip_z(0.f, 1.f));
+ if (engine::o3d::polygon::signed_area_xy(polygon) >= 0) return;
+ const auto& [final_triangles_count, final_triangles]
+ = polygon.clip_xy(-1.f, -1.f, 1.f, 1.f)
+ .map_xy({ -1.f, -1.f }, { 1.f, 1.f }, { -.5f, -.5f }, { static_cast<float>(fb.width()) - .5f, static_cast<float>(fb.height()) - .5f })
+ .to_triangles();
+ for (std::size_t i = 0; i < final_triangles_count; i++)
+ _draw_cropped_triangle(triangle, final_triangles[i]);
}
+// TODO: the renaming of w to z or the inverse is very confusing. The reason why it happens is
+// because we use Vector3 to store x, y and w, which therefore gets renamed to w. We should find
+// another way of doing this
template<typename FrameBuffer>
-void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const TriangleDerived& triangle) {
- std::array<const DerivedVertex*, 3> sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 };
+void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const TriangleDerived<Vector3>& triangle) {
+ std::array<const DerivedVertex<Vector3>*, 3> sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 };
{
const auto swap_if_gt = [&](auto x, auto y) {
@@ -78,13 +76,12 @@ void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const T
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 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;
- DerivedVertex middle_vr{
+ const float middle_vr_vertex_w = 1.f / (1.f / sorted_vs[0]->vertex.z + fac * (1.f / sorted_vs[2]->vertex.z - 1.f / sorted_vs[0]->vertex.z));
+ const float fac_b0 = middle_vr_vertex_w * (1.f - fac) / sorted_vs[0]->vertex.z;
+ DerivedVertex<Vector3> 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.w * sorted_vs[0]->vertex.z + (1.f - fac_b0) * sorted_vs[2]->vertex.w * sorted_vs[2]->vertex.z) / middle_vr_vertex_w,
middle_vr_vertex_w
},
fac_b0 * sorted_vs[0]->b0 + (1.f - fac_b0) * sorted_vs[2]->b0,
@@ -98,7 +95,7 @@ void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const T
const auto _draw_cropped_triangle_side = [&]<TriangleSide side>() {
const int vertex_end_index = ([&]() { if constexpr (side == TriangleSide::top) return 0; else return 2; })();
- const DerivedVertex& vertex_end = *sorted_vs[vertex_end_index];
+ const DerivedVertex<Vector3>& vertex_end = *sorted_vs[vertex_end_index];
if (vertex_end.vertex.y == sorted_vs[1]->vertex.y)
return;
int top_y;
@@ -124,26 +121,23 @@ void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const T
float projected_relative_b1 = s * (1.f - t);
float point_w = 1.f /
(
- projected_relative_b0 / vertex_end.vertex.w
- + projected_relative_b1 / middle_vl.vertex.w
- + (1.f - projected_relative_b0 - projected_relative_b1) / middle_vr.vertex.w
+ projected_relative_b0 / vertex_end.vertex.z
+ + projected_relative_b1 / middle_vl.vertex.z
+ + (1.f - projected_relative_b0 - projected_relative_b1) / middle_vr.vertex.z
);
- float relative_b0 = point_w * projected_relative_b0 / vertex_end.vertex.w;
- float relative_b1 = point_w * projected_relative_b1 / middle_vl.vertex.w;
- float loc_z = relative_b0 * vertex_end.vertex.w * vertex_end.vertex.z
- + relative_b1 * middle_vl.vertex.w * middle_vl.vertex.z
- + (1.f - relative_b0 - relative_b1) * middle_vr.vertex.w * middle_vr.vertex.z;
+ float relative_b0 = point_w * projected_relative_b0 / vertex_end.vertex.z;
+ float relative_b1 = point_w * projected_relative_b1 / middle_vl.vertex.z;
- if (loc_z >= depth_buf[x + y * fb.width()]) continue;
-
- depth_buf[x + y * fb.width()] = loc_z;
float b0 = relative_b0 * vertex_end.b0 + relative_b1 * middle_vl.b0 + (1.f - relative_b0 - relative_b1) * middle_vr.b0;
float b1 = relative_b0 * vertex_end.b1 + relative_b1 * middle_vl.b1 + (1.f - relative_b0 - relative_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
- };
+
+ auto loc = Vector3::bilerp(root.vertex1.vertex.xyz(), root.vertex2.vertex.xyz(), root.vertex3.vertex.xyz(), b0, b1);
+ loc.z /= point_w;
+
+ if (loc.z >= depth_buf[x + y * fb.width()]) continue;
+
+ depth_buf[x + y * fb.width()] = loc.z;
+
fb.draw_point(x, y, loc,
Vector3 ::bilerp(root.vertex1.normal, root.vertex2.normal, root.vertex3.normal, b0, b1),
Vector2 ::bilerp(root.vertex1.uv, root.vertex2.uv, root.vertex3.uv, b0, b1),
diff --git a/src/renderer.hpp b/src/renderer.hpp
index ea79fce..6725f70 100644
--- a/src/renderer.hpp
+++ b/src/renderer.hpp
@@ -30,7 +30,7 @@ class Renderer {
private:
std::vector<float> depth_buf;
- void _draw_cropped_triangle(const o3d::Triangle& root, const o3d::TriangleDerived& triangle);
+ void _draw_cropped_triangle(const o3d::Triangle& root, const o3d::TriangleDerived<engine::math::Vector3>& triangle);
};
}