summaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/test_3d.cc80
-rw-r--r--src/tests/test_maths.cc55
2 files changed, 114 insertions, 21 deletions
diff --git a/src/tests/test_3d.cc b/src/tests/test_3d.cc
index 88b8db9..90869bf 100644
--- a/src/tests/test_3d.cc
+++ b/src/tests/test_3d.cc
@@ -22,11 +22,29 @@ void test_camera() {
// Camera at (0,0,10) looking at (0,0,0). World (0,0,0) -> View (0,0,-10)
assert(near(view.m[14], -10.0f));
+ // Test Camera::set_look_at
+ cam.set_look_at({5, 0, 0}, {0, 0, 0}, {0, 1, 0}); // Look at origin from (5,0,0)
+ mat4 view_shifted = cam.get_view_matrix();
+ // The camera's forward vector (0,0,-1) should now point towards (-1,0,0) in world space.
+ // The translation part of the view matrix should be based on -dot(s, eye), -dot(u, eye), dot(f, eye)
+ // s = (0,0,-1), u = (0,1,0), f = (-1,0,0)
+ // m[12] = -dot({0,0,-1}, {5,0,0}) = 0
+ // m[13] = -dot({0,1,0}, {5,0,0}) = 0
+ // m[14] = dot({-1,0,0}, {5,0,0}) = -5
+ assert(near(view_shifted.m[12], 0.0f));
+ assert(near(view_shifted.m[13], 0.0f));
+ assert(near(view_shifted.m[14], -5.0f));
+
+ // Test Camera::get_projection_matrix with varied parameters
+ // Change FOV and aspect ratio
mat4 proj = cam.get_projection_matrix();
- // Check aspect ratio influence (m[0] = 1/(tan(fov/2)*asp))
- // fov ~0.785 (45deg), tan(22.5) ~0.414. asp=1.777.
- // m[0] should be around 1.35
- assert(proj.m[0] > 1.0f);
+ cam.fov_y_rad = 1.0472f; // 60 degrees
+ cam.aspect_ratio = 0.5f; // Narrower aspect ratio
+ mat4 proj_varied = cam.get_projection_matrix();
+ // m[0] should increase due to narrower aspect ratio (1/tan(30deg)/0.5)
+ assert(proj_varied.m[0] > proj.m[0]);
+ // m[5] should increase due to larger FOV (1/tan(30deg))
+ assert(proj_varied.m[5] < proj.m[5]);
}
void test_object_transform() {
@@ -36,21 +54,44 @@ void test_object_transform() {
// Model matrix should translate by (10,0,0)
mat4 m = obj.get_model_matrix();
- assert(near(m.m[12], 10.0f)); // Col 3, Row 0 is x translation in Col-Major?
- // Wait, my mat4 struct:
- // r.m[12] = t.x; // Index 12 is translation X
assert(near(m.m[12], 10.0f));
- // Rotate 90 deg Y
- obj.rotation = quat::from_axis(vec3(0, 1, 0), 1.570796f);
+ // Test composed transformations (translate then rotate)
+ obj.position = vec3(5, 0, 0);
+ obj.rotation = quat::from_axis({0, 1, 0}, 1.570796f); // 90 deg Y rotation
m = obj.get_model_matrix();
- // Transform point (1,0,0) -> Rot(0,0,-1) -> Trans(10,0,-1)
- vec4 p(1, 0, 0, 1);
- vec4 res = m * p;
- assert(near(res.x, 10.0f)); // Rotated vector is (0,0,-1). + (10,0,0)
- // translation -> (10,0,-1)
- assert(near(res.z, -1.0f));
+ // Transform point (1,0,0). Rotation around Y maps (1,0,0) to (0,0,-1).
+ // Translation moves it by (5,0,0). Final world pos: (5,0,-1).
+ vec4 p_comp(1, 0, 0, 1);
+ vec4 res_comp = m * p_comp;
+ assert(near(res_comp.x, 5.0f));
+ assert(near(res_comp.z, -1.0f));
+
+ // Test Object3D::inv_model calculation
+ // Model matrix for translation (5,0,0) is just translation
+ obj.position = vec3(5, 0, 0);
+ obj.rotation = quat(); // Identity rotation
+ mat4 model_t = obj.get_model_matrix();
+ mat4 inv_model_t = model_t.inverse();
+ // Applying inv_model to a translated point should undo the translation.
+ // Point (5,0,0) should go to (0,0,0)
+ vec4 translated_point(5,0,0,1);
+ vec4 original_space_t = inv_model_t * vec4(translated_point.x, translated_point.y, translated_point.z, 1.0);
+ assert(near(original_space_t.x, 0.0f) && near(original_space_t.y, 0.0f) && near(original_space_t.z, 0.0f));
+
+ // Model matrix with rotation (90 deg Y) and translation (5,0,0)
+ obj.position = vec3(5, 0, 0);
+ obj.rotation = quat::from_axis({0, 1, 0}, 1.570796f);
+ mat4 model_trs = obj.get_model_matrix();
+ mat4 inv_model_trs = model_trs.inverse();
+ // Transform point (1,0,0) (local right) via TRS: Rotates to (0,0,-1), Translates to (5,0,-1)
+ vec4 p_trs(1,0,0,1);
+ vec4 transformed_p = model_trs * p_trs;
+ assert(near(transformed_p.x, 5.0f) && near(transformed_p.z, -1.0f));
+ // Apply inverse to transformed point to get back original point
+ vec4 original_space_trs = inv_model_trs * transformed_p;
+ assert(near(original_space_trs.x, 1.0f) && near(original_space_trs.y, 0.0f) && near(original_space_trs.z, 0.0f));
}
void test_scene() {
@@ -60,6 +101,15 @@ void test_scene() {
assert(scene.objects.size() == 1);
scene.clear();
assert(scene.objects.empty());
+
+ // Add multiple objects and check count
+ scene.add_object(Object3D());
+ scene.add_object(Object3D());
+ assert(scene.objects.size() == 2);
+
+ // Test clearing the scene
+ scene.clear();
+ assert(scene.objects.empty());
}
int main() {
diff --git a/src/tests/test_maths.cc b/src/tests/test_maths.cc
index 0a3b9e6..ffc56f2 100644
--- a/src/tests/test_maths.cc
+++ b/src/tests/test_maths.cc
@@ -46,6 +46,11 @@ template <typename T> void test_vector_ops(int n) {
T n_vec = a.normalize();
assert(near(n_vec.norm(), 1.0f));
+ // Normalize zero vector
+ T zero_vec = T(); // Default construct to zero
+ T norm_zero = zero_vec.normalize();
+ for(int i = 0; i < n; ++i) assert(near(norm_zero[i], 0.0f));
+
// Lerp
T l = lerp(a, b, 0.3f);
for (int i = 0; i < n; ++i)
@@ -76,6 +81,19 @@ void test_quat() {
vec3 r = q.rotate(v);
assert(near(r.x, 0) && near(r.z, -1));
+ // Rotation edge cases: 0 deg, 180 deg, zero vector
+ quat zero_rot = quat::from_axis({1,0,0}, 0.0f);
+ vec3 rotated_zero = zero_rot.rotate(v);
+ assert(near(rotated_zero.x, 1.0f)); // Original vector
+
+ quat half_pi_rot = quat::from_axis({0,1,0}, 3.14159f); // 180 deg Y
+ vec3 rotated_half_pi = half_pi_rot.rotate(v);
+ assert(near(rotated_half_pi.x, -1.0f)); // Rotated 180 deg around Y
+
+ vec3 zero_vec(0,0,0);
+ vec3 rotated_zero_vec = q.rotate(zero_vec);
+ assert(near(rotated_zero_vec.x, 0.0f) && near(rotated_zero_vec.y, 0.0f) && near(rotated_zero_vec.z, 0.0f));
+
// Look At
// Looking from origin to +X, with +Y as up.
// The local forward vector (0,0,-1) should be transformed to (1,0,0)
@@ -88,6 +106,17 @@ void test_quat() {
quat q2 = quat::from_axis({0, 1, 0}, 1.5708f); // 90 deg
quat mid = slerp(q1, q2, 0.5f); // 45 deg
assert(near(mid.y, 0.3826f)); // sin(pi/8)
+
+ // Slerp edge cases
+ quat slerp_mid_edge = slerp(q1, q2, 0.0f);
+ assert(near(slerp_mid_edge.w, q1.w) && near(slerp_mid_edge.x, q1.x) && near(slerp_mid_edge.y, q1.y) && near(slerp_mid_edge.z, q1.z));
+ slerp_mid_edge = slerp(q1, q2, 1.0f);
+ assert(near(slerp_mid_edge.w, q2.w) && near(slerp_mid_edge.x, q2.x) && near(slerp_mid_edge.y, q2.y) && near(slerp_mid_edge.z, q2.z));
+
+ // FromTo
+ quat from_to_test = quat::from_to({1,0,0}, {0,1,0}); // 90 deg rotation around Z
+ vec3 rotated = from_to_test.rotate({1,0,0});
+ assert(near(rotated.y, 1.0f));
}
// Tests WebGPU specific matrices
@@ -139,12 +168,13 @@ void test_ease() {
assert(near(ease::out_cubic(1.0f), 1.0f));
assert(near(ease::in_out_quad(0.0f), 0.0f));
assert(near(ease::in_out_quad(1.0f), 1.0f));
+ assert(near(ease::out_expo(0.0f), 0.0f));
+ assert(near(ease::out_expo(1.0f), 1.0f));
// Midpoint/Logic tests
- assert(ease::out_cubic(0.5f) >
- 0.5f); // Out curves should exceed linear value early
- assert(
- near(ease::in_out_quad(0.5f), 0.5f)); // Symmetric curves hit 0.5 at 0.5
+ assert(ease::out_cubic(0.5f) > 0.5f); // Out curves should exceed linear value early
+ assert(near(ease::in_out_quad(0.5f), 0.5f)); // Symmetric curves hit 0.5 at 0.5
+ assert(ease::out_expo(0.5f) > 0.5f); // Exponential out should be above linear
}
// Tests spring solver
@@ -154,7 +184,13 @@ void test_spring() {
// Simulate approx 1 sec with 0.5s smooth time
for (int i = 0; i < 60; ++i)
spring::solve(p, v, 10.0f, 0.5f, 0.016f);
- assert(p > 8.5f);
+ assert(p > 8.5f); // Should be close to 10 after 1 sec
+
+ // Test convergence over longer period
+ p = 0; v = 0;
+ for (int i = 0; i < 200; ++i)
+ spring::solve(p, v, 10.0f, 0.5f, 0.016f);
+ assert(near(p, 10.0f, 0.1f)); // Should be very close to target
// Test vector spring
vec3 vp(0, 0, 0), vv(0, 0, 0), vt(10, 0, 0);
@@ -223,6 +259,13 @@ void test_matrix_inversion() {
stress.m[1] = 0.5f;
mat4 stress_inv = stress.inverse();
check_identity(stress * stress_inv);
+
+ // 8. Test Singular Matrix
+ mat4 singular_scale;
+ singular_scale.m[5] = 0.0f; // Scale Y by zero, making it singular
+ mat4 singular_inv = singular_scale.inverse();
+ // The inverse of a singular matrix should be the identity matrix as per the implementation
+ check_identity(singular_inv);
}
int main() {
@@ -244,4 +287,4 @@ int main() {
std::cout << "--- ALL TESTS PASSED ---" << std::endl;
return 0;
-}
+} \ No newline at end of file