Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/engine/math/frustum_tests.zig
Original file line number Diff line number Diff line change
@@ -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);
}
75 changes: 75 additions & 0 deletions src/engine/math/mat4_tests.zig
Original file line number Diff line number Diff line change
@@ -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]);
}
2 changes: 2 additions & 0 deletions src/tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading