From 40bdcf0b84d40ebf26fe8bd245f53ad7983165c0 Mon Sep 17 00:00:00 2001 From: "opencode[bot]" Date: Tue, 14 Apr 2026 20:58:14 +0000 Subject: [PATCH] test: add math tests for engine/math --- src/engine/math/frustum_tests.zig | 60 +++++++++++++++++++++++++ src/engine/math/mat4_tests.zig | 75 +++++++++++++++++++++++++++++++ src/tests.zig | 2 + 3 files changed, 137 insertions(+) create mode 100644 src/engine/math/frustum_tests.zig create mode 100644 src/engine/math/mat4_tests.zig diff --git a/src/engine/math/frustum_tests.zig b/src/engine/math/frustum_tests.zig new file mode 100644 index 00000000..4bea9577 --- /dev/null +++ b/src/engine/math/frustum_tests.zig @@ -0,0 +1,60 @@ +const std = @import("std"); +const testing = std.testing; +const Frustum = @import("frustum.zig").Frustum; +const Plane = @import("frustum.zig").Plane; +const Vec3 = @import("vec3.zig").Vec3; +const Mat4 = @import("mat4.zig").Mat4; +const AABB = @import("zig-math").AABB; + +test "Frustum containsPoint returns true for point inside" { + const vp = Mat4.identity; + const frustum = Frustum.fromViewProj(vp); + try testing.expect(frustum.containsPoint(Vec3.init(0, 0, 0))); +} + +test "Frustum containsPoint returns false for point behind camera" { + const view = Mat4.lookAt(Vec3.init(0, 0, 0), Vec3.init(0, 0, -1), Vec3.init(0, 1, 0)); + const proj = Mat4.perspective(std.math.pi / 4.0, 16.0 / 9.0, 0.1, 100.0); + const vp = proj.multiply(view); + const frustum = Frustum.fromViewProj(vp); + try testing.expect(!frustum.containsPoint(Vec3.init(0, 0, 50))); +} + +test "Frustum intersectsAABB returns true for AABB intersecting frustum" { + const frustum = Frustum.fromViewProj(Mat4.identity); + const aabb = AABB.init(Vec3.init(-1, -1, -1), Vec3.init(1, 1, 1)); + const result = frustum.intersectsAABB(aabb); + try testing.expect(result); +} + +test "Frustum intersectsAABB returns false for AABB completely outside" { + const p = Mat4.perspective(std.math.pi / 4.0, 16.0 / 9.0, 0.1, 100.0); + const frustum = Frustum.fromViewProj(p); + const aabb = AABB.init(Vec3.init(-200, -200, -200), Vec3.init(-100, -100, -100)); + try testing.expect(!frustum.intersectsAABB(aabb)); +} + +test "Frustum intersectsChunk returns true for chunk near origin" { + const frustum = Frustum.fromViewProj(Mat4.identity); + try testing.expect(frustum.intersectsChunk(0, 0)); +} + +test "Frustum intersectsChunk returns false for distant chunk" { + const p = Mat4.perspective(std.math.pi / 4.0, 16.0 / 9.0, 0.1, 100.0); + const frustum = Frustum.fromViewProj(p); + try testing.expect(!frustum.intersectsChunk(100, 100)); +} + +test "Plane init and signedDistance" { + const plane = Plane.init(Vec3.init(0, 0, 1), 0); + try testing.expectEqual(@as(f32, 5), plane.signedDistance(Vec3.init(0, 0, 5))); + try testing.expectEqual(@as(f32, -3), plane.signedDistance(Vec3.init(0, 0, -3))); + try testing.expectEqual(@as(f32, 0), plane.signedDistance(Vec3.init(0, 0, 0))); +} + +test "Plane normalize preserves distance ratio" { + const plane = Plane.init(Vec3.init(0, 0, 2), 4); + const normalized = plane.normalize(); + try testing.expectApproxEqAbs(@as(f32, 1), normalized.normal.z, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 2), normalized.distance, 0.0001); +} diff --git a/src/engine/math/mat4_tests.zig b/src/engine/math/mat4_tests.zig new file mode 100644 index 00000000..498c38f1 --- /dev/null +++ b/src/engine/math/mat4_tests.zig @@ -0,0 +1,75 @@ +const std = @import("std"); +const testing = std.testing; +const Mat4 = @import("mat4.zig").Mat4; +const Vec3 = @import("vec3.zig").Vec3; + +test "Mat4 rotateX" { + const rot = Mat4.rotateX(std.math.pi / 2.0); + const v = Vec3.init(0, 1, 0); + const rotated = rot.transformDirection(v); + try testing.expectApproxEqAbs(@as(f32, 0), rotated.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), rotated.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), rotated.z, 0.0001); +} + +test "Mat4 rotateZ" { + const rot = Mat4.rotateZ(std.math.pi / 2.0); + const v = Vec3.init(1, 0, 0); + const rotated = rot.transformDirection(v); + try testing.expectApproxEqAbs(@as(f32, 0), rotated.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), rotated.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), rotated.z, 0.0001); +} + +test "Mat4 lookAt facing +Z" { + const view = Mat4.lookAt( + Vec3.init(0, 0, 5), + Vec3.init(0, 0, 0), + Vec3.init(0, 1, 0), + ); + const forward = Vec3.init(0, 0, -1); + const transformed = view.transformDirection(forward); + try testing.expectApproxEqAbs(@as(f32, 0), transformed.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), transformed.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, -1), transformed.z, 0.0001); +} + +test "Mat4 lookAt preserves length" { + const view = Mat4.lookAt( + Vec3.init(5, 5, 5), + Vec3.init(0, 0, 0), + Vec3.init(0, 1, 0), + ); + const v = Vec3.init(1, 0, 0); + const rotated = view.transformDirection(v); + try testing.expectApproxEqAbs(@as(f32, 1), rotated.length(), 0.0001); +} + +test "Mat4 orthographic creates correct matrix" { + const ortho = Mat4.orthographic(-10, 10, -10, 10, -100, 100); + try testing.expectEqual(@as(f32, 0.1), ortho.data[0][0]); + try testing.expectEqual(@as(f32, 0.1), ortho.data[1][1]); + try testing.expectEqual(@as(f32, -0.01), ortho.data[2][2]); +} + +test "Mat4 perspectiveReverseZ structure" { + const p = Mat4.perspectiveReverseZ(std.math.pi / 4.0, 16.0 / 9.0, 0.1, 100.0); + try testing.expectEqual(@as(f32, -1), p.data[2][3]); + try testing.expectEqual(@as(f32, 0), p.data[3][3]); +} + +test "Mat4 rotateX at 0 degrees returns identity direction" { + const rot = Mat4.rotateX(0); + const v = Vec3.init(0, 1, 0); + const rotated = rot.transformDirection(v); + try testing.expectApproxEqAbs(@as(f32, 0), rotated.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), rotated.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), rotated.z, 0.0001); +} + +test "Mat4 ptr returns valid pointer to data" { + const m = Mat4.identity; + const ptr = m.ptr(); + try testing.expectEqual(@as(f32, 1), ptr[0]); + try testing.expectEqual(@as(f32, 0), ptr[1]); +} diff --git a/src/tests.zig b/src/tests.zig index 83d8d951..66761616 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -78,6 +78,8 @@ test { _ = @import("vulkan_tests.zig"); _ = @import("engine/graphics/rhi_tests.zig"); _ = @import("engine/math/utils_tests.zig"); + _ = @import("engine/math/frustum_tests.zig"); + _ = @import("engine/math/mat4_tests.zig"); _ = @import("world/world_tests.zig"); _ = @import("world/worldgen/schematics.zig"); _ = @import("world/worldgen/tree_registry.zig");