1 /* SPDX-License-Identifier: MIT */
2
3 #include <math.h>
4 #include <string.h>
5 #include <graphene.h>
6 #include <mutest.h>
7
8 static void
vectors_vec3_const(void)9 vectors_vec3_const (void)
10 {
11 const graphene_vec3_t *vec;
12
13 vec = graphene_vec3_zero ();
14 mutest_expect ("zero() vec3 to not be null",
15 mutest_pointer ((void *) vec),
16 mutest_not, mutest_to_be_null,
17 NULL);
18 mutest_expect ("zero() to return the same pointer",
19 mutest_pointer ((void *) vec),
20 mutest_to_be, graphene_vec3_zero (),
21 NULL);
22 mutest_expect ("zero().x to be 0",
23 mutest_float_value (graphene_vec3_get_x (vec)),
24 mutest_to_be_close_to, 0.0, 0.00001,
25 NULL);
26 mutest_expect ("zero().y to be 0",
27 mutest_float_value (graphene_vec3_get_y (vec)),
28 mutest_to_be_close_to, 0.0, 0.00001,
29 NULL);
30 mutest_expect ("zero().z to be 0",
31 mutest_float_value (graphene_vec3_get_z (vec)),
32 mutest_to_be_close_to, 0.0, 0.00001,
33 NULL);
34 mutest_expect ("length(zero()) to be 0",
35 mutest_float_value (graphene_vec3_length (vec)),
36 mutest_to_be_close_to, 0.0, 0.00001,
37 NULL);
38
39 vec = graphene_vec3_one ();
40 mutest_expect ("one() to not return null",
41 mutest_pointer ((void *) vec),
42 mutest_not, mutest_to_be_null,
43 NULL);
44 mutest_expect ("one() to return the same pointer",
45 mutest_pointer ((void *) vec),
46 mutest_to_be, graphene_vec3_one (),
47 NULL);
48 mutest_expect ("one().x to be 1",
49 mutest_float_value (graphene_vec3_get_x (vec)),
50 mutest_to_be_close_to, 1.0, 0.00001,
51 NULL);
52 mutest_expect ("one().y to be 1",
53 mutest_float_value (graphene_vec3_get_y (vec)),
54 mutest_to_be_close_to, 1.0, 0.00001,
55 NULL);
56 mutest_expect ("one().z to be 1",
57 mutest_float_value (graphene_vec3_get_z (vec)),
58 mutest_to_be_close_to, 1.0, 0.00001,
59 NULL);
60
61 vec = graphene_vec3_x_axis ();
62 mutest_expect ("x_axis() to not return null",
63 mutest_pointer ((void *) vec),
64 mutest_not, mutest_to_be_null,
65 NULL);
66 mutest_expect ("x_axis() to return the same pointer",
67 mutest_pointer ((void *) vec),
68 mutest_to_be, graphene_vec3_x_axis (),
69 NULL);
70 mutest_expect ("x_axis().x to be 1",
71 mutest_float_value (graphene_vec3_get_x (vec)),
72 mutest_to_be_close_to, 1.0, 0.00001,
73 NULL);
74
75 vec = graphene_vec3_y_axis ();
76 mutest_expect ("y_axis() to not return null",
77 mutest_pointer ((void *) vec),
78 mutest_not, mutest_to_be_null,
79 NULL);
80 mutest_expect ("y_axis() to return the same pointer",
81 mutest_pointer ((void *) vec),
82 mutest_to_be, graphene_vec3_y_axis (),
83 NULL);
84 mutest_expect ("y_axis().y to be 1",
85 mutest_float_value (graphene_vec3_get_y (vec)),
86 mutest_to_be_close_to, 1.0, 0.00001,
87 NULL);
88
89 vec = graphene_vec3_z_axis ();
90 mutest_expect ("z_axis() to not return null",
91 mutest_pointer ((void *) vec),
92 mutest_not, mutest_to_be_null,
93 NULL);
94 mutest_expect ("z_axis() to return the same pointer",
95 mutest_pointer ((void *) vec),
96 mutest_to_be, graphene_vec3_z_axis (),
97 NULL);
98 mutest_expect ("z_axis().z to be 1",
99 mutest_float_value (graphene_vec3_get_z (vec)),
100 mutest_to_be_close_to, 1.0, 0.00001,
101 NULL);
102 }
103
104 static void
vectors_vec3_init(void)105 vectors_vec3_init (void)
106 {
107 graphene_vec3_t *vec = graphene_vec3_alloc ();
108 const float v[3] = { 1.f, 2.f, 3.f };
109 float v_out[3];
110
111 graphene_vec3_init (vec, v[0], v[1], v[2]);
112 mutest_expect ("init() to initialize x component",
113 mutest_float_value (graphene_vec3_get_x (vec)),
114 mutest_to_be_close_to, v[0], 0.0001,
115 NULL);
116 mutest_expect ("init() to initialize y component",
117 mutest_float_value (graphene_vec3_get_y (vec)),
118 mutest_to_be_close_to, v[1], 0.0001,
119 NULL);
120 mutest_expect ("init() to initialize z component",
121 mutest_float_value (graphene_vec3_get_z (vec)),
122 mutest_to_be_close_to, v[2], 0.0001,
123 NULL);
124
125 graphene_vec3_init_from_vec3 (vec, graphene_vec3_x_axis ());
126 mutest_expect ("init_from_vec3() to initialize x component",
127 mutest_float_value (graphene_vec3_get_x (vec)),
128 mutest_to_be_close_to, 1.0, 0.0001,
129 NULL);
130 mutest_expect ("init_from_vec3() to initialize y component",
131 mutest_float_value (graphene_vec3_get_y (vec)),
132 mutest_to_be_close_to, 0.0, 0.0001,
133 NULL);
134 mutest_expect ("init_from_vec3() to initialize z component",
135 mutest_float_value (graphene_vec3_get_z (vec)),
136 mutest_to_be_close_to, 0.0, 0.0001,
137 NULL);
138
139 graphene_vec3_init_from_float (vec, v);
140 mutest_expect ("init_from_float() to initialize x component",
141 mutest_float_value (graphene_vec3_get_x (vec)),
142 mutest_to_be_close_to, v[0], 0.0001,
143 NULL);
144 mutest_expect ("init_from_float() to initialize y component",
145 mutest_float_value (graphene_vec3_get_y (vec)),
146 mutest_to_be_close_to, v[1], 0.0001,
147 NULL);
148 mutest_expect ("init_from_float() to initialize z component",
149 mutest_float_value (graphene_vec3_get_z (vec)),
150 mutest_to_be_close_to, v[2], 0.0001,
151 NULL);
152
153 graphene_vec3_to_float (vec, v_out);
154 mutest_expect ("roundtrip between init_from_float() and to_float()",
155 mutest_bool_value (memcmp (v, v_out, sizeof (float) * 3) == 0),
156 mutest_to_be_true,
157 NULL);
158
159 graphene_vec3_free (vec);
160 }
161
162 static void
vectors_vec3_ops_add(void)163 vectors_vec3_ops_add (void)
164 {
165 graphene_vec3_t a, b, res, check;
166
167 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
168 graphene_vec3_init (&b, 3.f, 4.f, 5.f);
169
170 graphene_vec3_add (&a, &b, &res);
171
172 graphene_vec3_init (&check, 1.f + 3.f, 2.f + 4.f, 3.f + 5.f);
173 mutest_expect ("add() to subtract each component",
174 mutest_bool_value (graphene_vec3_equal (&res, &check)),
175 mutest_to_be_true,
176 NULL);
177 }
178
179 static void
vectors_vec3_ops_sub(void)180 vectors_vec3_ops_sub (void)
181 {
182 graphene_vec3_t a, b, res, check;
183
184 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
185 graphene_vec3_init (&b, 3.f, 4.f, 5.f);
186
187 graphene_vec3_subtract (&a, &b, &res);
188
189 graphene_vec3_init (&check, 1.f - 3.f, 2.f - 4.f, 3.f - 5.f);
190 mutest_expect ("sub() to subtract each component",
191 mutest_bool_value (graphene_vec3_equal (&res, &check)),
192 mutest_to_be_true,
193 NULL);
194 }
195
196 static void
vectors_vec3_ops_mul(void)197 vectors_vec3_ops_mul (void)
198 {
199 graphene_vec3_t a, b, res, check;
200
201 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
202 graphene_vec3_init (&b, 3.f, 4.f, 5.f);
203
204 graphene_vec3_multiply (&a, &b, &res);
205
206 graphene_vec3_init (&check, 1.f * 3.f, 2.f * 4.f, 3.f * 5.f);
207 mutest_expect ("mul() to multiply each component",
208 mutest_bool_value (graphene_vec3_near (&res, &check, 0.0001f)),
209 mutest_to_be_true,
210 NULL);
211 }
212
213 static void
vectors_vec3_ops_div(void)214 vectors_vec3_ops_div (void)
215 {
216 graphene_vec3_t a, b, res, check;
217
218 graphene_vec3_init (&a, 6.f, 4.f, 2.f);
219 graphene_vec3_init (&b, 3.f, 2.f, 1.f);
220
221 graphene_vec3_divide (&a, &b, &res);
222
223 graphene_vec3_init (&check, 6.f / 3.f, 4.f / 2.f, 2.f / 1.f);
224 mutest_expect ("divide() to divide each component",
225 mutest_bool_value (graphene_vec3_near (&res, &check, 0.0001f)),
226 mutest_to_be_true,
227 NULL);
228 }
229
230 static void
vectors_vec3_ops_dot(void)231 vectors_vec3_ops_dot (void)
232 {
233 graphene_vec3_t a, b;
234 float dot, check;
235
236 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
237 graphene_vec3_init (&b, 2.f, 3.f, 4.f);
238
239 dot = graphene_vec3_dot (&a, &b);
240 check = 1.f * 2.f + 2.f * 3.f + 3.f * 4.f;
241
242 mutest_expect ("dot() to compute the dot product of all component",
243 mutest_float_value (dot),
244 mutest_to_be_close_to, check, 0.0001,
245 NULL);
246 }
247
248 static void
vectors_vec3_ops_cross(void)249 vectors_vec3_ops_cross (void)
250 {
251 graphene_vec3_t a, b, res, cross;
252 float cross_x, cross_y, cross_z;
253
254 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
255 graphene_vec3_init (&b, 2.f, 3.f, 4.f);
256
257 graphene_vec3_cross (&a, &b, &res);
258
259 cross_x = 2.f * 4.f - 3.f * 3.f;
260 cross_y = 3.f * 2.f - 1.f * 4.f;
261 cross_z = 1.f * 3.f - 2.f * 2.f;
262 graphene_vec3_init (&cross, cross_x, cross_y, cross_z);
263
264 mutest_expect ("cross() to compute the cross product of all component",
265 mutest_bool_value (graphene_vec3_near (&res, &cross, 0.0001f)),
266 mutest_to_be_true,
267 NULL);
268 }
269
270 static void
vectors_vec3_ops_scale(void)271 vectors_vec3_ops_scale (void)
272 {
273 graphene_vec3_t a, res, check;
274
275 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
276 graphene_vec3_scale (&a, 2.f, &res);
277
278 graphene_vec3_init (&check, 2.f, 4.f, 6.f);
279 mutest_expect ("scale() to scale every component",
280 mutest_bool_value (graphene_vec3_equal (&res, &check)),
281 mutest_to_be_true,
282 NULL);
283 }
284
285 static void
vectors_vec3_ops_negate(void)286 vectors_vec3_ops_negate (void)
287 {
288 graphene_vec3_t a, res, check;
289
290 graphene_vec3_init (&a, 1.f, -2.f, 3.f);
291 graphene_vec3_negate (&a, &res);
292
293 graphene_vec3_init (&check, -1.f, 2.f, -3.f);
294 mutest_expect ("negate() to flip the sign on every component",
295 mutest_bool_value (graphene_vec3_equal (&res, &check)),
296 mutest_to_be_true,
297 NULL);
298 }
299
300 static void
vectors_vec3_length(void)301 vectors_vec3_length (void)
302 {
303 graphene_vec3_t a;
304 float len, check;
305
306 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
307
308 len = graphene_vec3_length (&a);
309 check = sqrtf ((1.f * 1.f) + (2.f * 2.f) + (3.f * 3.f));
310
311 mutest_expect ("length() to be the square distance on all components",
312 mutest_float_value (len),
313 mutest_to_be_close_to, check, 0.0001,
314 NULL);
315 }
316
317 static void
vectors_vec3_normalize(void)318 vectors_vec3_normalize (void)
319 {
320 graphene_vec3_t a, b, c;
321 float inv_len;
322
323 graphene_vec3_init (&a, 1.f, 2.f, 3.f);
324 inv_len = 1.f / graphene_vec3_length (&a);
325
326 graphene_vec3_normalize (&a, &b);
327 graphene_vec3_scale (&a, inv_len, &c);
328
329 mutest_expect ("normalize() to scale components with the inverse of the length",
330 mutest_bool_value (graphene_vec3_near (&b, &c, 0.0001f)),
331 mutest_to_be_true,
332 NULL);
333 }
334
335 static void
vectors_vec3_compare(void)336 vectors_vec3_compare (void)
337 {
338 graphene_vec3_t a, b;
339 graphene_vec3_t res, check;
340
341 graphene_vec3_init (&a, 5.f, 10.f, 8.f);
342 graphene_vec3_init (&b, 2.f, 12.f, 8.f);
343
344 graphene_vec3_init (&check, 2.f, 10.f, 8.f);
345 graphene_vec3_min (&a, &b, &res);
346 mutest_expect ("min() to return the minimum value in each channel",
347 mutest_bool_value (graphene_vec3_equal (&res, &check)),
348 mutest_to_be_true,
349 NULL);
350
351 graphene_vec3_init (&check, 5.f, 12.f, 8.f);
352 graphene_vec3_max (&a, &b, &res);
353 mutest_expect ("max() to return the maximum value in each channel",
354 mutest_bool_value (graphene_vec3_equal (&res, &check)),
355 mutest_to_be_true,
356 NULL);
357 }
358
359 static void
vectors_vec3_conversion(void)360 vectors_vec3_conversion (void)
361 {
362 graphene_vec3_t v;
363
364 graphene_vec3_init (&v, 1.f, 2.f, 3.f);
365
366 graphene_vec2_t xy, check2;
367
368 graphene_vec2_init (&check2, graphene_vec3_get_x (&v), graphene_vec3_get_y (&v));
369 graphene_vec3_get_xy (&v, &xy);
370 mutest_expect ("get_xy() to use the first two components",
371 mutest_bool_value (graphene_vec2_equal (&xy, &check2)),
372 mutest_to_be_true,
373 NULL);
374
375 graphene_vec3_t xy0, check3;
376
377 graphene_vec3_init (&check3, graphene_vec3_get_x (&v), graphene_vec3_get_y (&v), 0.f);
378 graphene_vec3_get_xy0 (&v, &xy0);
379 mutest_expect ("get_xy0() to use the first two components, and set the third to 0",
380 mutest_bool_value (graphene_vec3_equal (&xy0, &check3)),
381 mutest_to_be_true,
382 NULL);
383
384 graphene_vec4_t xyz0, xyz1, xyzw, check4;
385
386 graphene_vec4_init (&check4,
387 graphene_vec3_get_x (&v),
388 graphene_vec3_get_y (&v),
389 graphene_vec3_get_z (&v),
390 0.f);
391 graphene_vec3_get_xyz0 (&v, &xyz0);
392 mutest_expect ("get_xyz0() to use all three components, and set the fourth to 0",
393 mutest_bool_value (graphene_vec4_equal (&xyz0, &check4)),
394 mutest_to_be_true,
395 NULL);
396
397 graphene_vec4_init (&check4,
398 graphene_vec3_get_x (&v),
399 graphene_vec3_get_y (&v),
400 graphene_vec3_get_z (&v),
401 1.f);
402 graphene_vec3_get_xyz1 (&v, &xyz1);
403 mutest_expect ("get_xyz1() to use all three components, and set the fourth to 1",
404 mutest_bool_value (graphene_vec4_equal (&xyz1, &check4)),
405 mutest_to_be_true,
406 NULL);
407
408 graphene_vec4_init (&check4,
409 graphene_vec3_get_x (&v),
410 graphene_vec3_get_y (&v),
411 graphene_vec3_get_z (&v),
412 4.f);
413 graphene_vec3_get_xyzw (&v, 4.f, &xyzw);
414 mutest_expect ("get_xyzw() to use all three components, and set the fourth to the w argument",
415 mutest_bool_value (graphene_vec4_equal (&xyzw, &check4)),
416 mutest_to_be_true,
417 NULL);
418 }
419
420 static void
vectors_vec3_equal(void)421 vectors_vec3_equal (void)
422 {
423 const graphene_vec3_t *zero = graphene_vec3_zero ();
424 const graphene_vec3_t *one = graphene_vec3_one ();
425
426 mutest_expect ("a vector to be equal to itself",
427 mutest_bool_value (graphene_vec3_equal (zero, zero)),
428 mutest_to_be_true,
429 NULL);
430 mutest_expect ("a vector not to be equal to null",
431 mutest_bool_value (graphene_vec3_equal (zero, NULL)),
432 mutest_not, mutest_to_be_true,
433 NULL);
434 mutest_expect ("null not to be equal to a vector",
435 mutest_bool_value (graphene_vec3_equal (NULL, zero)),
436 mutest_not, mutest_to_be_true,
437 NULL);
438 mutest_expect ("two different vectors to not be equal",
439 mutest_bool_value (graphene_vec3_equal (zero, one)),
440 mutest_not, mutest_to_be_true,
441 NULL);
442 }
443
444 static void
vec3_suite(void)445 vec3_suite (void)
446 {
447 mutest_it ("has constant vectors", vectors_vec3_const);
448 mutest_it ("initializes channels", vectors_vec3_init);
449 mutest_it ("can add", vectors_vec3_ops_add);
450 mutest_it ("can subtract", vectors_vec3_ops_sub);
451 mutest_it ("can multiply", vectors_vec3_ops_mul);
452 mutest_it ("can divide", vectors_vec3_ops_div);
453 mutest_it ("can compute the dot product", vectors_vec3_ops_dot);
454 mutest_it ("can compute the cross product", vectors_vec3_ops_cross);
455 mutest_it ("can scale", vectors_vec3_ops_scale);
456 mutest_it ("can negate", vectors_vec3_ops_negate);
457 mutest_it ("can compute the length", vectors_vec3_length);
458 mutest_it ("can normalize", vectors_vec3_normalize);
459 mutest_it ("can compare", vectors_vec3_compare);
460 mutest_it ("can convert to other vector types", vectors_vec3_conversion);
461 mutest_it ("can check for equality", vectors_vec3_equal);
462 }
463
464 MUTEST_MAIN (
465 mutest_describe ("graphene_vec3_t", vec3_suite);
466 )
467