diff options
| author | skal <pascal.massimino@gmail.com> | 2026-01-29 23:18:25 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-01-30 23:08:05 +0100 |
| commit | eae9e03be4c9082187508a14a075b768db5f1aaa (patch) | |
| tree | d928faa7ca87d87a615529789cf103057dd128ac /src/tests/test_maths.cc | |
| parent | 84e484645ff70d3a63f11ae0d23727c65a8d5c71 (diff) | |
add mini_math.h header-only vector lib
Diffstat (limited to 'src/tests/test_maths.cc')
| -rw-r--r-- | src/tests/test_maths.cc | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/tests/test_maths.cc b/src/tests/test_maths.cc new file mode 100644 index 0000000..03b2a4c --- /dev/null +++ b/src/tests/test_maths.cc @@ -0,0 +1,149 @@ +#include "util/mini_math.h" +#include <iostream> +#include <vector> +#include <cassert> +#include <cmath> + +// Checks if two floats are approximately equal +bool near(float a, float b, float e = 0.001f) { return std::abs(a - b) < e; } + +// Generic test runner for any vector type (vec2, vec3, vec4) +template<typename T> +void test_vector_ops(int n) { + T a, b; + // Set values + for(int i=0; i<n; ++i) { a[i] = (float)(i + 1); b[i] = 10.0f; } + + // Add + T c = a + b; + for(int i=0; i<n; ++i) assert(near(c[i], (float)(i + 1) + 10.0f)); + + // Scale + T s = a * 2.0f; + for(int i=0; i<n; ++i) assert(near(s[i], (float)(i + 1) * 2.0f)); + + // Dot Product + // vec3(1,2,3) . vec3(1,2,3) = 1+4+9 = 14 + float expected_dot = 0; + for(int i=0; i<n; ++i) expected_dot += a[i] * a[i]; + assert(near(T::dot(a, a), expected_dot)); + + // Norm (Length) + assert(near(a.norm(), std::sqrt(expected_dot))); + + // Normalize + T n_vec = a.normalize(); + assert(near(n_vec.norm(), 1.0f)); + + // Lerp + T l = lerp(a, b, 0.3f); + for(int i=0; i<n; ++i) assert(near(l[i], .7 * (i+1) + .3 * 10.0f)); +} + +// Specific test for padding alignment in vec3 +void test_vec3_special() { + std::cout << "Testing vec3 alignment..." << std::endl; + // Verify sizeof is 16 bytes (4 floats) due to padding for WebGPU + assert(sizeof(vec3) == 16); + + vec3 v(1, 0, 0); + vec3 v2(0, 1, 0); + + // Cross Product + vec3 c = vec3::cross(v, v2); + assert(near(c.x, 0) && near(c.y, 0) && near(c.z, 1)); +} + +// Tests quaternion rotation, look_at, and slerp +void test_quat() { + std::cout << "Testing Quat..." << std::endl; + + // Rotation (Rodrigues) + vec3 v(1, 0, 0); + quat q = quat::from_axis({0, 1, 0}, 1.5708f); // 90 deg Y + vec3 r = q.rotate(v); + assert(near(r.x, 0) && near(r.z, -1)); + + // 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) + quat l = quat::look_at({0,0,0}, {10,0,0}, {0,1,0}); + vec3 f = l.rotate({0,0,-1}); + assert(near(f.x, 1.0f) && near(f.y, 0.0f) && near(f.z, 0.0f)); + + // Slerp Midpoint + quat q1(0,0,0,1); + 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) +} + +// Tests WebGPU specific matrices +void test_matrices() { + std::cout << "Testing Matrices..." << std::endl; + float n = 0.1f, f = 100.0f; + mat4 p = mat4::perspective(0.785f, 1.0f, n, f); + + // Check WebGPU Z-range [0, 1] + // Z_ndc = (m10 * Z_view + m14) / -Z_view + float z_near = (p.m[10] * -n + p.m[14]) / n; + float z_far = (p.m[10] * -f + p.m[14]) / f; + assert(near(z_near, 0.0f)); + assert(near(z_far, 1.0f)); + + // Test mat4::look_at + vec3 eye(0, 0, 5); + vec3 target(0, 0, 0); + vec3 up(0, 1, 0); + mat4 view = mat4::look_at(eye, target, up); + // Point (0,0,0) in world should be at (0,0,-5) in view space + assert(near(view.m[14], -5.0f)); +} + +// Tests easing curves +void test_ease() { + std::cout << "Testing Easing..." << std::endl; + // Boundary tests + assert(near(ease::out_cubic(0.0f), 0.0f)); + 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)); + + // 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 +} + +// Tests spring solver +void test_spring() { + std::cout << "Testing Spring..." << std::endl; + float p = 0, v = 0; + // 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); + + // Test vector spring + vec3 vp(0,0,0), vv(0,0,0), vt(10,0,0); + spring::solve(vp, vv, vt, 0.5f, 0.016f * 60.0f); // 1 huge step approx + assert(vp.x > 1.0f); // Should have moved significantly +} + +int main() { + std::cout << "Testing vec2..." << std::endl; + test_vector_ops<vec2>(2); + + std::cout << "Testing vec3..." << std::endl; + test_vector_ops<vec3>(3); + test_vec3_special(); + + std::cout << "Testing vec4..." << std::endl; + test_vector_ops<vec4>(4); + + test_quat(); + test_matrices(); + test_ease(); + test_spring(); + + std::cout << "--- ALL TESTS PASSED ---" << std::endl; + return 0; +} |
