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