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