1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
// This file is part of the 64k demo project.
// Unit tests for math utilities.
#include "util/mini_math.h"
#include "util/asset_manager.h" // For AssetId, though not strictly needed for math tests
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <map>
#include <vector>
#include <cassert>
// Helper to convert C++ vec3 to WGSL vec3
inline vec3 to_wgsl_vec3(const vec3& v) {
return vec3(v.x, v.y, v.z);
}
// --- Math Utilities Tests ---
void test_vec3_operations() {
printf("Running test: test_vec3_operations
");
// Test constructor and basic accessors
vec3 v1(1.0f, 2.0f, 3.0f);
assert(v1.x == 1.0f && v1.y == 2.0f && v1.z == 3.0f);
assert(v1[0] == 1.0f && v1[1] == 2.0f && v1[2] == 3.0f);
// Test normalization
vec3 v_unnormalized = vec3(3.0f, 4.0f, 0.0f);
vec3 v_normalized = v_unnormalized.normalize();
assert(std::abs(v_normalized.x - 0.6f) < 1e-5f);
assert(std::abs(v_normalized.y - 0.8f) < 1e-5f);
assert(std::abs(v_normalized.z - 0.0f) < 1e-5f);
assert(std::abs(v_normalized.norm() - 1.0f) < 1e-5f);
// Test dot product
vec3 v_dot1 = vec3(1.0f, 2.0f, 3.0f);
vec3 v_dot2 = vec3(4.0f, 5.0f, 6.0f);
float dot_product = vec3::dot(v_dot1, v_dot2); // 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
assert(std::abs(dot_product - 32.0f) < 1e-5f);
// Test cross product
vec3 v_cross1 = vec3(1.0f, 0.0f, 0.0f); // i
vec3 v_cross2 = vec3(0.0f, 1.0f, 0.0f); // j
vec3 cross_product = vec3::cross(v_cross1, v_cross2);
assert(std::abs(cross_product.x - 0.0f) < 1e-5f);
assert(std::abs(cross_product.y - 0.0f) < 1e-5f);
assert(std::abs(cross_product.z - 1.0f) < 1e-5f); // k
// Test element-wise multiplication
vec3 v_scale1 = vec3(2.0f, 3.0f, 4.0f);
vec3 v_scale2 = vec3(5.0f, 2.0f, 1.0f);
vec3 scaled_v = v_scale1 * v_scale2;
assert(std::abs(scaled_v.x - 10.0f) < 1e-5f);
assert(std::abs(scaled_v.y - 6.0f) < 1e-5f);
assert(std::abs(scaled_v.z - 4.0f) < 1e-5f);
printf("test_vec3_operations passed.
");
}
// --- Quaternion Tests ---
// Dummy function to satisfy potential compiler needs, if not defined elsewhere
// If quat::from_axis is part of a class that's already linked, this might not be needed.
// However, to be safe, I'll assume it might need a declaration.
// If this causes issues, it means quat is not properly available here.
#if !defined(QUAT_FROM_AXIS_DEFINED)
namespace quat_detail {
// Dummy definition if quat is not properly linked/included in this context
struct quat {
vec3 axis;
float angle;
quat(vec3 a, float ang) : axis(a), angle(ang) {}
};
inline quat from_axis(vec3 a, float ang) {
return quat(a, ang);
}
}
#define QUAT_FROM_AXIS_DEFINED
#endif
void test_quaternion_operations() {
printf("Running test: test_quaternion_operations
");
// Test from_axis and to_mat
vec3 axis_cpp = vec3(0.0f, 1.0f, 0.0f).normalize();
vec3 wgsl_axis = to_wgsl_vec3(axis_cpp);
quat q = quat::from_axis(wgsl_axis, 1.5708f); // 90 degrees around Y axis
mat4 rot_mat = q.to_mat();
// Check if rotation matrix is approximately identity (for 0 rotation) or correct for 90 deg around Y
// A 90 degree rotation around Y should result in:
// [ 0, 0, 1, 0 ]
// [ 0, 1, 0, 0 ]
// [-1, 0, 0, 0 ]
// [ 0, 0, 0, 1 ]
// (Column-major)
assert(std::abs(rot_mat.m[0] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[1] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[2] - -1.0f) < 1e-5f);
assert(std::abs(rot_mat.m[3] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[4] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[5] - 1.0f) < 1e-5f);
assert(std::abs(rot_mat.m[6] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[7] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[8] - 1.0f) < 1e-5f);
assert(std::abs(rot_mat.m[9] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[10] - 0.0f) < 1e-5f);
assert(std::abs(rot_mat.m[11] - 0.0f) < 1e-5f);
// Test rotating a vector
vec3 test_vec(1.0f, 0.0f, 0.0f);
vec3 rotated_vec = q.rotate(test_vec);
// Expecting rotation around Y axis by 90 degrees should transform (1,0,0) to (0,0,-1)
assert(std::abs(rotated_vec.x - 0.0f) < 1e-5f);
assert(std::abs(rotated_vec.y - 0.0f) < 1e-5f);
assert(std::abs(rotated_vec.z - -1.0f) < 1e-5f);
printf("test_quaternion_operations passed.
");
}
// --- Easing Function Tests ---
void test_easing_functions() {
printf("Running test: test_easing_functions
");
assert(std::abs(ease::out_cubic(0.0f) - 0.0f) < 1e-5f);
assert(std::abs(ease::out_cubic(0.5f) - 0.875f) < 1e-5f);
assert(std::abs(ease::out_cubic(1.0f) - 1.0f) < 1e-5f);
assert(std::abs(ease::in_out_quad(0.0f) - 0.0f) < 1e-5f);
assert(std::abs(ease::in_out_quad(0.5f) - 0.5f) < 1e-5f);
assert(std::abs(ease::in_out_quad(1.0f) - 1.0f) < 1e-5f);
assert(std::abs(ease::out_expo(0.0f) - 0.0f) < 1e-5f);
assert(std::abs(ease::out_expo(1.0f) - 1.0f) < 1e-5f);
// Check a mid-point for out_expo, e.g., 0.5 should be 1 - 2^(-5) = 1 - 1/32 = 31/32 = 0.96875
assert(std::abs(ease::out_expo(0.5f) - 0.96875f) < 1e-5f);
printf("test_easing_functions passed.
");
}
// --- Lerp Tests ---
void test_lerp() {
printf("Running test: test_lerp
");
vec3 start_vec = vec3(1.0f, 2.0f, 3.0f);
vec3 end_vec = vec3(5.0f, 6.0f, 7.0f);
float t_mid = 0.5f;
vec3 mid_point = lerp(start_vec, end_vec, t_mid);
assert(std::abs(mid_point.x - 3.0f) < 1e-5f);
assert(std::abs(mid_point.y - 4.0f) < 1e-5f);
assert(std::abs(mid_point.z - 5.0f) < 1e-5f);
// Test lerp with float
float start_f = 10.0f;
float end_f = 20.0f;
float mid_f = lerp(start_f, end_f, t_mid);
assert(std::abs(mid_f - 15.0f) < 1e-5f);
printf("test_lerp passed.
");
}
int main(int argc, char** argv) {
// This main function is for running tests standalone if needed,
// but tests are typically run via ctest.
// However, for the sake of this execution, we can run them directly.
test_vec3_operations();
test_quaternion_operations();
test_easing_functions();
test_lerp();
return 0;
}
|