1 /* SPDX-License-Identifier: MIT */
2 
3 #include <math.h>
4 #include <graphene.h>
5 #include <mutest.h>
6 
7 static void
point_zero(mutest_spec_t * spec)8 point_zero (mutest_spec_t *spec)
9 {
10   graphene_point3d_t zero = GRAPHENE_POINT3D_INIT_ZERO;
11   const graphene_point3d_t *p;
12 
13   p = graphene_point3d_zero ();
14   mutest_expect ("graphene_point3d_zero() to not return null",
15                  mutest_pointer ((void *) p),
16                  mutest_not, mutest_to_be_null,
17                  NULL);
18   mutest_expect ("graphene_point3d_zero() to return the same pointer",
19                  mutest_pointer ((void *) graphene_point3d_zero ()),
20                  mutest_to_be, p,
21                  NULL);
22   mutest_expect ("graphene_point3d_zero() to return (0, 0, 0)",
23                  mutest_bool_value (graphene_point3d_equal (p, &zero)),
24                  mutest_to_be_true,
25                  NULL);
26 }
27 
28 static void
point_alloc_and_init(mutest_spec_t * spec)29 point_alloc_and_init (mutest_spec_t *spec)
30 {
31   graphene_point3d_t *a, b;
32   graphene_point3d_t p, r;
33   graphene_vec3_t vec3;
34 
35   a = graphene_point3d_alloc ();
36   mutest_expect ("allocation to not fail",
37                  mutest_pointer (a),
38                  mutest_not, mutest_to_be_null,
39                  NULL);
40 
41   graphene_point3d_init (a, 1.f, 2.f, 3.f);
42   graphene_point3d_init_from_point (&b, a);
43   mutest_expect ("init_from_point to copy the source",
44                  mutest_bool_value (graphene_point3d_equal (&b, a)),
45                  mutest_to_be_true,
46                  NULL);
47 
48   graphene_point3d_free (a);
49 
50   graphene_point3d_init (&p, 1.f, 2.f, 3.f);
51   mutest_expect ("init to set the X coordinate",
52                  mutest_float_value (p.x),
53                  mutest_to_be_close_to, 1.0, 0.0001,
54                  NULL);
55   mutest_expect ("init to set the Y coordinate",
56                  mutest_float_value (p.y),
57                  mutest_to_be_close_to, 2.0, 0.0001,
58                  NULL);
59   mutest_expect ("init to set the Z coordinate",
60                  mutest_float_value (p.z),
61                  mutest_to_be_close_to, 3.0, 0.0001,
62                  NULL);
63 
64   graphene_vec3_init (&vec3, 1.0, 2.0, 4.0);
65   graphene_point3d_init_from_vec3 (&r, &vec3);
66   mutest_expect ("init from vec3 to set the X coordinate",
67                  mutest_float_value (graphene_vec3_get_x (&vec3)),
68                  mutest_to_be_close_to, r.x, 0.0001,
69                  NULL);
70   mutest_expect ("init from vec3 to set the Y coordinate",
71                  mutest_float_value (graphene_vec3_get_y (&vec3)),
72                  mutest_to_be_close_to, r.y, 0.0001,
73                  NULL);
74   mutest_expect ("init from vec3 to set the Z coordinate",
75                  mutest_float_value (graphene_vec3_get_z (&vec3)),
76                  mutest_to_be_close_to, r.z, 0.0001,
77                  NULL);
78 }
79 
80 static void
point_equal(mutest_spec_t * spec)81 point_equal (mutest_spec_t *spec)
82 {
83   graphene_point3d_t p, q;
84 
85   graphene_point3d_init (&p, 0.f, 0.f, 0.f);
86 
87   mutest_expect ("a point to be equal to itself",
88                  mutest_bool_value (graphene_point3d_equal (&p, &p)),
89                  mutest_to_be_true,
90                  NULL);
91   mutest_expect ("a point to not be equal to null",
92                  mutest_bool_value (graphene_point3d_equal (&p, NULL)),
93                  mutest_to_be_false,
94                  NULL);
95   mutest_expect ("null to not be equal to a point",
96                  mutest_bool_value (graphene_point3d_equal (NULL, &p)),
97                  mutest_to_be_false,
98                  NULL);
99 
100   graphene_point3d_init (&q, 0.f, 0.f, 0.f);
101   mutest_expect ("two points initialized to the same coordinates to be equal",
102                  mutest_bool_value (graphene_point3d_equal (&p, &q)),
103                  mutest_to_be_true,
104                  NULL);
105 
106   graphene_point3d_init (&q, 1.f, 1.f, 1.f);
107   mutest_expect ("two points initialized to different coordinates not to be equal",
108                  mutest_bool_value (graphene_point3d_equal (&p, &q)),
109                  mutest_to_be_false,
110                  NULL);
111 }
112 
113 static void
point_near(mutest_spec_t * spec)114 point_near (mutest_spec_t *spec)
115 {
116   graphene_point3d_t p, q;
117 
118   graphene_point3d_init (&p, 0.f, 0.f, 0.f);
119   mutest_expect ("a point to be near itself",
120                  mutest_bool_value (graphene_point3d_near (&p, &p, 0.f)),
121                  mutest_to_be_true,
122                  NULL);
123 
124   graphene_point3d_init (&q, 0.1f, 0.1f, 0.1f);
125   mutest_expect ("(0.1, 0.1, 0.1) to be within 0.2 units from (0, 0, 0)",
126                  mutest_bool_value (graphene_point3d_near (&p, &q, 0.2f)),
127                  mutest_to_be_true,
128                  NULL);
129   mutest_expect ("(0.1, 0.1, 0.1) to not be within 0.001 from (0, 0, 0)",
130                  mutest_bool_value (graphene_point3d_near (&p, &q, 0.001f)),
131                  mutest_to_be_false,
132                  NULL);
133 }
134 
135 static void
point_interpolate(mutest_spec_t * spec)136 point_interpolate (mutest_spec_t *spec)
137 {
138   graphene_point3d_t zero = GRAPHENE_POINT3D_INIT (0.f, 0.f, 0.f);
139   graphene_point3d_t half = GRAPHENE_POINT3D_INIT (.5f, .5f, .5f);
140   graphene_point3d_t one = GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f);
141   graphene_point3d_t res;
142 
143   graphene_point3d_interpolate (&zero, &one, 0.0, &res);
144   mutest_expect ("lerp(0, 1, 0.0) = 0",
145                  mutest_bool_value (graphene_point3d_equal (&res, &zero)),
146                  mutest_to_be_true,
147                  NULL);
148 
149   graphene_point3d_interpolate (&zero, &one, 0.5, &res);
150   mutest_expect ("lerp(0, 1, 0.5) = 0.5",
151                  mutest_bool_value (graphene_point3d_equal (&res, &half)),
152                  mutest_to_be_true,
153                  NULL);
154 
155   graphene_point3d_interpolate (&zero, &one, 1.0, &res);
156   mutest_expect ("lerp(0, 1, 1.0) = 1",
157                  mutest_bool_value (graphene_point3d_equal (&res, &one)),
158                  mutest_to_be_true,
159                  NULL);
160 }
161 
162 static void
point_scale(mutest_spec_t * spec)163 point_scale (mutest_spec_t *spec)
164 {
165   float x = 1.f, y = 2.f, z = 3.f;
166   graphene_point3d_t p;
167 
168   graphene_point3d_init (&p, x, y, z);
169   graphene_point3d_scale (&p, 2.f, &p);
170   mutest_expect ("scale(2) scales the X coordinate",
171                  mutest_float_value (p.x),
172                  mutest_to_be_close_to, x * 2.0, 0.0001,
173                  NULL);
174   mutest_expect ("scale(2) scales the Y coordinate",
175                  mutest_float_value (p.y),
176                  mutest_to_be_close_to, y * 2.0, 0.0001,
177                  NULL);
178   mutest_expect ("scale(2) scales the Z coordinate",
179                  mutest_float_value (p.z),
180                  mutest_to_be_close_to, z * 2.0, 0.0001,
181                  NULL);
182 
183   graphene_point3d_init (&p, x, y, z);
184   graphene_point3d_scale (&p, .5f, &p);
185   mutest_expect ("scale(0.5) scales the X coordinate",
186                  mutest_float_value (p.x),
187                  mutest_to_be_close_to, x * 0.5, 0.0001,
188                  NULL);
189   mutest_expect ("scale(0.5) scales the Y coordinate",
190                  mutest_float_value (p.y),
191                  mutest_to_be_close_to, y * 0.5, 0.0001,
192                  NULL);
193   mutest_expect ("scale(0.5) scales the Z coordinate",
194                  mutest_float_value (p.z),
195                  mutest_to_be_close_to, z * 0.5, 0.0001,
196                  NULL);
197 }
198 
199 static void
point_cross(mutest_spec_t * spec)200 point_cross (mutest_spec_t *spec)
201 {
202   graphene_point3d_t a, b, res;
203   graphene_vec3_t v_a, v_b, v_res, check;
204 
205   graphene_point3d_init (&a, 1.f, 2.f, 3.f);
206   graphene_point3d_to_vec3 (&a, &v_a);
207 
208   graphene_point3d_init (&b, 4.f, 5.f, 6.f);
209   graphene_point3d_to_vec3 (&b, &v_b);
210 
211   graphene_point3d_cross (&a, &b, &res);
212   graphene_point3d_to_vec3 (&res, &check);
213 
214   graphene_vec3_cross (&v_a, &v_b, &v_res);
215 
216   mutest_expect ("cross(a, b) matches both point3d and vec3",
217                  mutest_bool_value (graphene_vec3_equal (&check, &v_res)),
218                  mutest_to_be_true,
219                  NULL);
220 }
221 
222 static void
point_dot(mutest_spec_t * spec)223 point_dot (mutest_spec_t *spec)
224 {
225   graphene_point3d_t a, b;
226   graphene_vec3_t v_a, v_b;
227 
228   graphene_point3d_init (&a, 1.f, 2.f, 3.f);
229   graphene_point3d_to_vec3 (&a, &v_a);
230   graphene_point3d_init (&b, 4.f, 5.f, 6.f);
231   graphene_point3d_to_vec3 (&b, &v_b);
232 
233   mutest_expect ("dot(a, b) matches both point3d and vec3",
234                  mutest_float_value (graphene_point3d_dot (&a, &b)),
235                  mutest_to_be_close_to, graphene_vec3_dot (&v_a, &v_b), 0.0001,
236                  NULL);
237 }
238 
239 static void
point_length(mutest_spec_t * spec)240 point_length (mutest_spec_t *spec)
241 {
242   graphene_point3d_t p;
243   float res;
244 
245   graphene_point3d_init (&p, 1.f, 3.f, 5.f);
246   res = sqrtf (1.f + (3.f * 3.f) + (5.f * 5.f));
247 
248   mutest_expect ("length is the square root of the sum components squared",
249                  mutest_float_value (graphene_point3d_length (&p)),
250                  mutest_to_be_close_to, res, 0.0001f,
251                  NULL);
252 }
253 
254 static void
point_normalize(mutest_spec_t * spec)255 point_normalize (mutest_spec_t *spec)
256 {
257   graphene_point3d_t p, q;
258 
259   graphene_point3d_init (&p, 4.f, 8.f, 2.f);
260   graphene_point3d_normalize (&p, &q);
261 
262   mutest_expect ("normalization to change the point",
263                  mutest_bool_value (graphene_point3d_equal (&p, &q)),
264                  mutest_to_be_false,
265                  NULL);
266 }
267 
268 static void
point_normalize_viewport(mutest_spec_t * spec)269 point_normalize_viewport (mutest_spec_t *spec)
270 {
271   graphene_point3d_t p, q;
272   graphene_rect_t v;
273 
274   graphene_point3d_init (&p, 150.f, 20.f, 0.f);
275   graphene_rect_init (&v, 0.f, 0.f, 640.f, 480.f);
276   graphene_point3d_normalize_viewport (&p, &v, 1.f, 100.f, &q);
277 
278   mutest_expect ("original point and normalized point not to match",
279                  mutest_bool_value (graphene_point3d_equal (&p, &q)),
280                  mutest_to_be_false,
281                  NULL);
282 
283   mutest_expect ("normalized X coordinate to be [-1, 1)",
284                  mutest_float_value (q.x),
285                  mutest_to_be_in_range, -1.0, 1.01,
286                  NULL);
287   mutest_expect ("normalized Y coordinate to be [-1, 1)",
288                  mutest_float_value (q.y),
289                  mutest_to_be_in_range, -1.0, 1.01,
290                  NULL);
291   mutest_expect ("normalized Z coordinate to be [-1, 1)",
292                  mutest_float_value (q.z),
293                  mutest_to_be_in_range, -1.0, 1.01,
294                  NULL);
295 }
296 
297 static void
point3d_suite(mutest_suite_t * suite)298 point3d_suite (mutest_suite_t *suite)
299 {
300   mutest_it ("allocates and initializes data", point_alloc_and_init);
301   mutest_it ("provides a zero point", point_zero);
302   mutest_it ("has exact equality", point_equal);
303   mutest_it ("has near equality", point_near);
304   mutest_it ("interpolates between values", point_interpolate);
305   mutest_it ("scales coordinates", point_scale);
306   mutest_it ("implements cross product", point_cross);
307   mutest_it ("implements dot product", point_dot);
308   mutest_it ("implements length", point_length);
309   mutest_it ("implements normalization", point_normalize);
310   mutest_it ("allows normalizing within a viewport", point_normalize_viewport);
311 }
312 
313 MUTEST_MAIN (
314   mutest_describe ("graphene_point3d_t", point3d_suite);
315 )
316