1 /* graphene-vectors.c: Assorted vectors
2 *
3 * SPDX-License-Identifier: MIT
4 *
5 * Copyright 2014 Emmanuele Bassi
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include "graphene-private.h"
27 #include "graphene-vectors-private.h"
28 #include "graphene-alloc-private.h"
29
30 #include <stdio.h>
31
32 #ifdef HAVE_PTHREAD
33 #include <pthread.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdio.h>
37 #endif
38
39 /**
40 * SECTION:graphene-vectors
41 * @Title: Vectors
42 * @Short_Description: Vectors in 2, 3, and 4 dimensions
43 *
44 * Graphene has three vector types, distinguished by their length:
45 *
46 * 1. #graphene_vec2_t, which holds 2 components x and y
47 * 2. #graphene_vec3_t, which holds 3 components x, y, and z
48 * 3. #graphene_vec4_t, which holds 4 components x, y, z, and w
49 *
50 * Each vector type should be treated as an opaque data type.
51 */
52
53 /* vec2 {{{ */
54
55 /**
56 * graphene_vec2_alloc: (constructor)
57 *
58 * Allocates a new #graphene_vec2_t structure.
59 *
60 * The contents of the returned structure are undefined.
61 *
62 * Use graphene_vec2_init() to initialize the vector.
63 *
64 * Returns: (transfer full): the newly allocated #graphene_vec2_t
65 * structure. Use graphene_vec2_free() to free the resources allocated
66 * by this function.
67 *
68 * Since: 1.0
69 */
70 graphene_vec2_t *
graphene_vec2_alloc(void)71 graphene_vec2_alloc (void)
72 {
73 return graphene_aligned_alloc (sizeof (graphene_vec2_t), 1, 16);
74 }
75
76 /**
77 * graphene_vec2_free:
78 * @v: a #graphene_vec2_t
79 *
80 * Frees the resources allocated by @v
81 *
82 * Since: 1.0
83 */
84 void
graphene_vec2_free(graphene_vec2_t * v)85 graphene_vec2_free (graphene_vec2_t *v)
86 {
87 graphene_aligned_free (v);
88 }
89
90 /**
91 * graphene_vec2_init:
92 * @v: a #graphene_vec2_t
93 * @x: the X field of the vector
94 * @y: the Y field of the vector
95 *
96 * Initializes a #graphene_vec2_t using the given values.
97 *
98 * This function can be called multiple times.
99 *
100 * Returns: (transfer none): the initialized vector
101 *
102 * Since: 1.0
103 */
104 graphene_vec2_t *
graphene_vec2_init(graphene_vec2_t * v,float x,float y)105 graphene_vec2_init (graphene_vec2_t *v,
106 float x,
107 float y)
108 {
109 v->value = graphene_simd4f_init (x, y, 0.f, 0.f);
110
111 return v;
112 }
113
114 /**
115 * graphene_vec2_init_from_vec2:
116 * @v: a #graphene_vec2_t
117 * @src: a #graphene_vec2_t
118 *
119 * Copies the contents of @src into @v.
120 *
121 * Returns: (transfer none): the initialized vector
122 *
123 * Since: 1.0
124 */
125 graphene_vec2_t *
graphene_vec2_init_from_vec2(graphene_vec2_t * v,const graphene_vec2_t * src)126 graphene_vec2_init_from_vec2 (graphene_vec2_t *v,
127 const graphene_vec2_t *src)
128 {
129 v->value = src->value;
130
131 return v;
132 }
133
134 /**
135 * graphene_vec2_init_from_float:
136 * @v: a #graphene_vec2_t
137 * @src: (array fixed-size=2): an array of floating point values
138 * with at least two elements
139 *
140 * Initializes @v with the contents of the given array.
141 *
142 * Returns: (transfer none): the initialized vector
143 *
144 * Since: 1.0
145 */
146 graphene_vec2_t *
graphene_vec2_init_from_float(graphene_vec2_t * v,const float * src)147 graphene_vec2_init_from_float (graphene_vec2_t *v,
148 const float *src)
149 {
150 v->value = graphene_simd4f_init_2f (src);
151
152 return v;
153 }
154
155 /**
156 * graphene_vec2_get_x:
157 * @v: a #graphene_vec2_t
158 *
159 * Retrieves the X component of the #graphene_vec2_t.
160 *
161 * Returns: the value of the X component
162 *
163 * Since: 1.0
164 */
165 float
graphene_vec2_get_x(const graphene_vec2_t * v)166 graphene_vec2_get_x (const graphene_vec2_t *v)
167 {
168 return graphene_simd4f_get_x (v->value);
169 }
170
171 /**
172 * graphene_vec2_get_y:
173 * @v: a #graphene_vec2_t
174 *
175 * Retrieves the Y component of the #graphene_vec2_t.
176 *
177 * Returns: the value of the Y component
178 *
179 * Since: 1.0
180 */
181 float
graphene_vec2_get_y(const graphene_vec2_t * v)182 graphene_vec2_get_y (const graphene_vec2_t *v)
183 {
184 return graphene_simd4f_get_y (v->value);
185 }
186
187 /**
188 * graphene_vec2_to_float:
189 * @v: a #graphene_vec2_t
190 * @dest: (out caller-allocates) (array fixed-size=2): return location
191 * for an array of floating point values with at least 2 elements
192 *
193 * Stores the components of @v into an array.
194 *
195 * Since: 1.0
196 */
197 void
graphene_vec2_to_float(const graphene_vec2_t * v,float * dest)198 graphene_vec2_to_float (const graphene_vec2_t *v,
199 float *dest)
200 {
201 graphene_simd4f_dup_2f (v->value, dest);
202 }
203
204 /**
205 * graphene_vec2_add:
206 * @a: a #graphene_vec2_t
207 * @b: a #graphene_vec2_t
208 * @res: (out caller-allocates): return location for the result
209 *
210 * Adds each component of the two passed vectors and places
211 * each result into the components of @res.
212 *
213 * Since: 1.0
214 */
215 void
graphene_vec2_add(const graphene_vec2_t * a,const graphene_vec2_t * b,graphene_vec2_t * res)216 graphene_vec2_add (const graphene_vec2_t *a,
217 const graphene_vec2_t *b,
218 graphene_vec2_t *res)
219 {
220 res->value = graphene_simd4f_add (a->value, b->value);
221 }
222
223 /**
224 * graphene_vec2_subtract:
225 * @a: a #graphene_vec2_t
226 * @b: a #graphene_vec2_t
227 * @res: (out caller-allocates): return location for the result
228 *
229 * Subtracts from each component of the first operand @a the
230 * corresponding component of the second operand @b and places
231 * each result into the components of @res.
232 *
233 * Since: 1.0
234 */
235 void
graphene_vec2_subtract(const graphene_vec2_t * a,const graphene_vec2_t * b,graphene_vec2_t * res)236 graphene_vec2_subtract (const graphene_vec2_t *a,
237 const graphene_vec2_t *b,
238 graphene_vec2_t *res)
239 {
240 res->value = graphene_simd4f_sub (a->value, b->value);
241 }
242
243 /**
244 * graphene_vec2_multiply:
245 * @a: a #graphene_vec2_t
246 * @b: a #graphene_vec2_t
247 * @res: (out caller-allocates): return location for the result
248 *
249 * Multiplies each component of the two passed vectors and places
250 * each result into the components of @res.
251 *
252 * Since: 1.0
253 */
254 void
graphene_vec2_multiply(const graphene_vec2_t * a,const graphene_vec2_t * b,graphene_vec2_t * res)255 graphene_vec2_multiply (const graphene_vec2_t *a,
256 const graphene_vec2_t *b,
257 graphene_vec2_t *res)
258 {
259 res->value = graphene_simd4f_mul (a->value, b->value);
260 }
261
262 /**
263 * graphene_vec2_divide:
264 * @a: a #graphene_vec2_t
265 * @b: a #graphene_vec2_t
266 * @res: (out caller-allocates): return location for the result
267 *
268 * Divides each component of the first operand @a by the corresponding
269 * component of the second operand @b, and places the results into the
270 * vector @res.
271 *
272 * Since: 1.0
273 */
274 void
graphene_vec2_divide(const graphene_vec2_t * a,const graphene_vec2_t * b,graphene_vec2_t * res)275 graphene_vec2_divide (const graphene_vec2_t *a,
276 const graphene_vec2_t *b,
277 graphene_vec2_t *res)
278 {
279 res->value = graphene_simd4f_div (a->value, b->value);
280 }
281
282 /**
283 * graphene_vec2_dot:
284 * @a: a #graphene_vec2_t
285 * @b: a #graphene_vec2_t
286 *
287 * Computes the dot product of the two given vectors.
288 *
289 * Returns: the dot product of the vectors
290 *
291 * Since: 1.0
292 */
293 float
graphene_vec2_dot(const graphene_vec2_t * a,const graphene_vec2_t * b)294 graphene_vec2_dot (const graphene_vec2_t *a,
295 const graphene_vec2_t *b)
296 {
297 return graphene_simd4f_get_x (graphene_simd4f_dot2 (a->value, b->value));
298 }
299
300 /**
301 * graphene_vec2_length:
302 * @v: a #graphene_vec2_t
303 *
304 * Computes the length of the given vector.
305 *
306 * Returns: the length of the vector
307 *
308 * Since: 1.0
309 */
310 float
graphene_vec2_length(const graphene_vec2_t * v)311 graphene_vec2_length (const graphene_vec2_t *v)
312 {
313 return graphene_simd4f_get_x (graphene_simd4f_length2 (v->value));
314 }
315
316 /**
317 * graphene_vec2_normalize:
318 * @v: a #graphene_vec2_t
319 * @res: (out caller-allocates): return location for the
320 * normalized vector
321 *
322 * Computes the normalized vector for the given vector @v.
323 *
324 * Since: 1.0
325 */
326 void
graphene_vec2_normalize(const graphene_vec2_t * v,graphene_vec2_t * res)327 graphene_vec2_normalize (const graphene_vec2_t *v,
328 graphene_vec2_t *res)
329 {
330 if (fabsf (graphene_vec2_length (v)) > FLT_EPSILON)
331 res->value = graphene_simd4f_normalize2 (v->value);
332 else
333 res->value = graphene_simd4f_init_zero ();
334 }
335
336 /**
337 * graphene_vec2_min:
338 * @a: a #graphene_vec2_t
339 * @b: a #graphene_vec2_t
340 * @res: (out caller-allocates): the resulting vector
341 *
342 * Compares the two given vectors and places the minimum
343 * values of each component into @res.
344 *
345 * Since: 1.0
346 */
347 void
graphene_vec2_min(const graphene_vec2_t * a,const graphene_vec2_t * b,graphene_vec2_t * res)348 graphene_vec2_min (const graphene_vec2_t *a,
349 const graphene_vec2_t *b,
350 graphene_vec2_t *res)
351 {
352 res->value = graphene_simd4f_min (a->value, b->value);
353 }
354
355 /**
356 * graphene_vec2_max:
357 * @a: a #graphene_vec2_t
358 * @b: a #graphene_vec2_t
359 * @res: (out caller-allocates): the resulting vector
360 *
361 * Compares the two given vectors and places the maximum
362 * values of each component into @res.
363 *
364 * Since: 1.0
365 */
366 void
graphene_vec2_max(const graphene_vec2_t * a,const graphene_vec2_t * b,graphene_vec2_t * res)367 graphene_vec2_max (const graphene_vec2_t *a,
368 const graphene_vec2_t *b,
369 graphene_vec2_t *res)
370 {
371 res->value = graphene_simd4f_max (a->value, b->value);
372 }
373
374 /**
375 * graphene_vec2_scale:
376 * @v: a #graphene_vec2_t
377 * @factor: the scalar factor
378 * @res: (out caller-allocates): return location for the result vector
379 *
380 * Multiplies all components of the given vector with the given scalar @factor.
381 *
382 * Since: 1.2
383 */
384 void
graphene_vec2_scale(const graphene_vec2_t * v,float factor,graphene_vec2_t * res)385 graphene_vec2_scale (const graphene_vec2_t *v,
386 float factor,
387 graphene_vec2_t *res)
388 {
389 res->value = graphene_simd4f_mul (v->value, graphene_simd4f_splat (factor));
390 }
391
392 /**
393 * graphene_vec2_negate:
394 * @v: a #graphene_vec2_t
395 * @res: (out caller-allocates): return location for the result vector
396 *
397 * Negates the given #graphene_vec2_t.
398 *
399 * Since: 1.2
400 */
401 void
graphene_vec2_negate(const graphene_vec2_t * v,graphene_vec2_t * res)402 graphene_vec2_negate (const graphene_vec2_t *v,
403 graphene_vec2_t *res)
404 {
405 res->value = graphene_simd4f_neg (v->value);
406 }
407
408 static bool
vec2_equal(const void * p1,const void * p2)409 vec2_equal (const void *p1,
410 const void *p2)
411 {
412 const graphene_vec2_t *v1 = p1;
413 const graphene_vec2_t *v2 = p2;
414
415 if (graphene_simd4f_cmp_eq (v1->value, v2->value))
416 return true;
417
418 return graphene_vec2_near (v1, v2, GRAPHENE_FLOAT_EPSILON);
419 }
420
421 /**
422 * graphene_vec2_equal:
423 * @v1: a #graphene_vec2_t
424 * @v2: a #graphene_vec2_t
425 *
426 * Checks whether the two given #graphene_vec2_t are equal.
427 *
428 * Returns: `true` if the two vectors are equal, and false otherwise
429 *
430 * Since: 1.2
431 */
432 bool
graphene_vec2_equal(const graphene_vec2_t * v1,const graphene_vec2_t * v2)433 graphene_vec2_equal (const graphene_vec2_t *v1,
434 const graphene_vec2_t *v2)
435 {
436 return graphene_pointer_equal (v1, v2, vec2_equal);
437 }
438
439 /**
440 * graphene_vec2_near:
441 * @v1: a #graphene_vec2_t
442 * @v2: a #graphene_vec2_t
443 * @epsilon: the threshold between the two vectors
444 *
445 * Compares the two given #graphene_vec2_t vectors and checks
446 * whether their values are within the given @epsilon.
447 *
448 * Returns: `true` if the two vectors are near each other
449 *
450 * Since: 1.2
451 */
452 bool
graphene_vec2_near(const graphene_vec2_t * v1,const graphene_vec2_t * v2,float epsilon)453 graphene_vec2_near (const graphene_vec2_t *v1,
454 const graphene_vec2_t *v2,
455 float epsilon)
456 {
457 graphene_simd4f_t d = graphene_simd4f_sub (v1->value, v2->value);
458 float epsilon_sq = epsilon * epsilon;
459
460 return graphene_simd4f_get_x (graphene_simd4f_dot2 (d, d)) < epsilon_sq;
461 }
462
463 /**
464 * graphene_vec2_interpolate:
465 * @v1: a #graphene_vec2_t
466 * @v2: a #graphene_vec2_t
467 * @factor: the interpolation factor
468 * @res: (out caller-allocates): the interpolated vector
469 *
470 * Linearly interpolates @v1 and @v2 using the given @factor.
471 *
472 * Since: 1.10
473 */
474 void
graphene_vec2_interpolate(const graphene_vec2_t * v1,const graphene_vec2_t * v2,double factor,graphene_vec2_t * res)475 graphene_vec2_interpolate (const graphene_vec2_t *v1,
476 const graphene_vec2_t *v2,
477 double factor,
478 graphene_vec2_t *res)
479 {
480 res->value = graphene_simd4f_interpolate (v1->value, v2->value, (float) factor);
481 }
482
483 enum {
484 VEC2_ZERO,
485 VEC2_ONE,
486 VEC2_X_AXIS,
487 VEC2_Y_AXIS,
488
489 N_STATIC_VEC2
490 };
491
492 static graphene_vec2_t static_vec2[N_STATIC_VEC2];
493
494 static void
init_static_vec2_once(void)495 init_static_vec2_once (void)
496 {
497 static_vec2[VEC2_ZERO].value = graphene_simd4f_init_zero ();
498 static_vec2[VEC2_ONE].value = graphene_simd4f_init (1.f, 1.f, 0.f, 0.f);
499 static_vec2[VEC2_X_AXIS].value = graphene_simd4f_init (1.f, 0.f, 0.f, 0.f);
500 static_vec2[VEC2_Y_AXIS].value = graphene_simd4f_init (0.f, 1.f, 0.f, 0.f);
501 }
502
503 #ifdef HAVE_PTHREAD
504 static pthread_once_t static_vec2_once = PTHREAD_ONCE_INIT;
505
506 static inline void
init_static_vec2(void)507 init_static_vec2 (void)
508 {
509 int status = pthread_once (&static_vec2_once, init_static_vec2_once);
510
511 if (status < 0)
512 {
513 int saved_errno = errno;
514
515 fprintf (stderr, "pthread_once failed: %s (errno:%d)\n",
516 strerror (saved_errno),
517 saved_errno);
518 }
519 }
520
521 #elif defined(HAVE_INIT_ONCE)
522 static INIT_ONCE static_vec2_once = INIT_ONCE_STATIC_INIT;
523
524 static BOOL CALLBACK
InitVec2Func(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * lpContext)525 InitVec2Func (PINIT_ONCE InitOnce,
526 PVOID Parameter,
527 PVOID *lpContext)
528 {
529 init_static_vec2_once ();
530 return TRUE;
531 }
532
533 static inline void
init_static_vec2(void)534 init_static_vec2 (void)
535 {
536 BOOL bStatus = InitOnceExecuteOnce (&static_vec2_once,
537 InitVec2Func,
538 NULL,
539 NULL);
540
541 if (!bStatus)
542 fprintf (stderr, "InitOnceExecuteOnce failed\n");
543 }
544
545 #else /* !HAVE_PTHREAD && !HAVE_INIT_ONCE */
546 static bool static_vec2_init = false;
547
548 static inline void
init_static_vec2(void)549 init_static_vec2 (void)
550 {
551 if (static_vec2_init)
552 return;
553
554 init_static_vec2_once ();
555 static_vec2_init = true;
556 }
557 #endif /* HAVE_PTHREAD */
558
559 /**
560 * graphene_vec2_zero:
561 *
562 * Retrieves a constant vector with (0, 0) components.
563 *
564 * Returns: (transfer none): the zero vector
565 *
566 * Since: 1.0
567 */
568 const graphene_vec2_t *
graphene_vec2_zero(void)569 graphene_vec2_zero (void)
570 {
571 init_static_vec2 ();
572
573 return &(static_vec2[VEC2_ZERO]);
574 }
575
576 /**
577 * graphene_vec2_one:
578 *
579 * Retrieves a constant vector with (1, 1) components.
580 *
581 * Returns: (transfer none): the one vector
582 *
583 * Since: 1.0
584 */
585 const graphene_vec2_t *
graphene_vec2_one(void)586 graphene_vec2_one (void)
587 {
588 init_static_vec2 ();
589
590 return &(static_vec2[VEC2_ONE]);
591 }
592
593 /**
594 * graphene_vec2_x_axis:
595 *
596 * Retrieves a constant vector with (1, 0) components.
597 *
598 * Returns: (transfer none): the X axis vector
599 *
600 * Since: 1.0
601 */
602 const graphene_vec2_t *
graphene_vec2_x_axis(void)603 graphene_vec2_x_axis (void)
604 {
605 init_static_vec2 ();
606
607 return &(static_vec2[VEC2_X_AXIS]);
608 }
609
610 /**
611 * graphene_vec2_y_axis:
612 *
613 * Retrieves a constant vector with (0, 1) components.
614 *
615 * Returns: (transfer none): the Y axis vector
616 *
617 * Since: 1.0
618 */
619 const graphene_vec2_t *
graphene_vec2_y_axis(void)620 graphene_vec2_y_axis (void)
621 {
622 init_static_vec2 ();
623
624 return &(static_vec2[VEC2_Y_AXIS]);
625 }
626
627 /* }}} vec2 */
628
629 /* vec3 {{{ */
630
631 /**
632 * graphene_vec3_alloc: (constructor)
633 *
634 * Allocates a new #graphene_vec3_t structure.
635 *
636 * The contents of the returned structure are undefined.
637 *
638 * Use graphene_vec3_init() to initialize the vector.
639 *
640 * Returns: (transfer full): the newly allocated #graphene_vec3_t
641 * structure. Use graphene_vec3_free() to free the resources allocated
642 * by this function.
643 *
644 * Since: 1.0
645 */
646 graphene_vec3_t *
graphene_vec3_alloc(void)647 graphene_vec3_alloc (void)
648 {
649 return graphene_aligned_alloc (sizeof (graphene_vec3_t), 1, 16);
650 }
651
652 /**
653 * graphene_vec3_free:
654 * @v: a #graphene_vec3_t
655 *
656 * Frees the resources allocated by @v
657 *
658 * Since: 1.0
659 */
660 void
graphene_vec3_free(graphene_vec3_t * v)661 graphene_vec3_free (graphene_vec3_t *v)
662 {
663 graphene_aligned_free (v);
664 }
665
666 /**
667 * graphene_vec3_init:
668 * @v: a #graphene_vec3_t
669 * @x: the X field of the vector
670 * @y: the Y field of the vector
671 * @z: the Z field of the vector
672 *
673 * Initializes a #graphene_vec3_t using the given values.
674 *
675 * This function can be called multiple times.
676 *
677 * Returns: (transfer none): a pointer to the initialized
678 * vector
679 *
680 * Since: 1.0
681 */
682 graphene_vec3_t *
graphene_vec3_init(graphene_vec3_t * v,float x,float y,float z)683 graphene_vec3_init (graphene_vec3_t *v,
684 float x,
685 float y,
686 float z)
687 {
688 v->value = graphene_simd4f_init (x, y, z, 0.f);
689
690 return v;
691 }
692
693 /**
694 * graphene_vec3_init_from_vec3:
695 * @v: a #graphene_vec3_t
696 * @src: a #graphene_vec3_t
697 *
698 * Initializes a #graphene_vec3_t with the values of another
699 * #graphene_vec3_t.
700 *
701 * Returns: (transfer none): the initialized vector
702 *
703 * Since: 1.0
704 */
705 graphene_vec3_t *
graphene_vec3_init_from_vec3(graphene_vec3_t * v,const graphene_vec3_t * src)706 graphene_vec3_init_from_vec3 (graphene_vec3_t *v,
707 const graphene_vec3_t *src)
708 {
709 v->value = src->value;
710
711 return v;
712 }
713
714 /**
715 * graphene_vec3_init_from_float:
716 * @v: a #graphene_vec3_t
717 * @src: (array fixed-size=3): an array of 3 floating point values
718 *
719 * Initializes a #graphene_vec3_t with the values from an array.
720 *
721 * Returns: (transfer none): the initialized vector
722 *
723 * Since: 1.0
724 */
725 graphene_vec3_t *
graphene_vec3_init_from_float(graphene_vec3_t * v,const float * src)726 graphene_vec3_init_from_float (graphene_vec3_t *v,
727 const float *src)
728 {
729 v->value = graphene_simd4f_init_3f (src);
730
731 return v;
732 }
733
734 /**
735 * graphene_vec3_get_x:
736 * @v: a #graphene_vec3_t
737 *
738 * Retrieves the first component of the given vector @v.
739 *
740 * Returns: the value of the first component of the vector
741 *
742 * Since: 1.0
743 */
744 float
graphene_vec3_get_x(const graphene_vec3_t * v)745 graphene_vec3_get_x (const graphene_vec3_t *v)
746 {
747 return graphene_simd4f_get_x (v->value);
748 }
749
750 /**
751 * graphene_vec3_get_y:
752 * @v: a #graphene_vec3_t
753 *
754 * Retrieves the second component of the given vector @v.
755 *
756 * Returns: the value of the second component of the vector
757 *
758 * Since: 1.0
759 */
760 float
graphene_vec3_get_y(const graphene_vec3_t * v)761 graphene_vec3_get_y (const graphene_vec3_t *v)
762 {
763 return graphene_simd4f_get_y (v->value);
764 }
765
766 /**
767 * graphene_vec3_get_z:
768 * @v: a #graphene_vec3_t
769 *
770 * Retrieves the third component of the given vector @v.
771 *
772 * Returns: the value of the third component of the vector
773 *
774 * Since: 1.0
775 */
776 float
graphene_vec3_get_z(const graphene_vec3_t * v)777 graphene_vec3_get_z (const graphene_vec3_t *v)
778 {
779 return graphene_simd4f_get_z (v->value);
780 }
781
782 /**
783 * graphene_vec3_to_float:
784 * @v: a #graphene_vec3_t
785 * @dest: (out caller-allocates) (array fixed-size=3): return location for
786 * an array of floating point values
787 *
788 * Copies the components of a #graphene_vec3_t into the given array.
789 *
790 * Since: 1.0
791 */
792 void
graphene_vec3_to_float(const graphene_vec3_t * v,float * dest)793 graphene_vec3_to_float (const graphene_vec3_t *v,
794 float *dest)
795 {
796 graphene_simd4f_dup_3f (v->value, dest);
797 }
798
799 /**
800 * graphene_vec3_add:
801 * @a: a #graphene_vec3_t
802 * @b: a #graphene_vec3_t
803 * @res: (out caller-allocates): return location for the resulting vector
804 *
805 * Adds each component of the two given vectors.
806 *
807 * Since: 1.0
808 */
809 void
graphene_vec3_add(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)810 graphene_vec3_add (const graphene_vec3_t *a,
811 const graphene_vec3_t *b,
812 graphene_vec3_t *res)
813 {
814 res->value = graphene_simd4f_add (a->value, b->value);
815 }
816
817 /**
818 * graphene_vec3_subtract:
819 * @a: a #graphene_vec3_t
820 * @b: a #graphene_vec3_t
821 * @res: (out caller-allocates): return location for the resulting vector
822 *
823 * Subtracts from each component of the first operand @a the
824 * corresponding component of the second operand @b and places
825 * each result into the components of @res.
826 *
827 * Since: 1.0
828 */
829 void
graphene_vec3_subtract(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)830 graphene_vec3_subtract (const graphene_vec3_t *a,
831 const graphene_vec3_t *b,
832 graphene_vec3_t *res)
833 {
834 res->value = graphene_simd4f_sub (a->value, b->value);
835 }
836
837 /**
838 * graphene_vec3_multiply:
839 * @a: a #graphene_vec3_t
840 * @b: a #graphene_vec3_t
841 * @res: (out caller-allocates): return location for the resulting vector
842 *
843 * Multiplies each component of the two given vectors.
844 *
845 * Since: 1.0
846 */
847 void
graphene_vec3_multiply(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)848 graphene_vec3_multiply (const graphene_vec3_t *a,
849 const graphene_vec3_t *b,
850 graphene_vec3_t *res)
851 {
852 res->value = graphene_simd4f_mul (a->value, b->value);
853 }
854
855 /**
856 * graphene_vec3_divide:
857 * @a: a #graphene_vec3_t
858 * @b: a #graphene_vec3_t
859 * @res: (out caller-allocates): return location for the resulting vector
860 *
861 * Divides each component of the first operand @a by the corresponding
862 * component of the second operand @b, and places the results into the
863 * vector @res.
864 *
865 * Since: 1.0
866 */
867 void
graphene_vec3_divide(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)868 graphene_vec3_divide (const graphene_vec3_t *a,
869 const graphene_vec3_t *b,
870 graphene_vec3_t *res)
871 {
872 res->value = graphene_simd4f_div (a->value, b->value);
873 }
874
875 /**
876 * graphene_vec3_cross:
877 * @a: a #graphene_vec3_t
878 * @b: a #graphene_vec3_t
879 * @res: (out caller-allocates): return location for the resulting vector
880 *
881 * Computes the cross product of the two given vectors.
882 *
883 * Since: 1.0
884 */
885 void
graphene_vec3_cross(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)886 graphene_vec3_cross (const graphene_vec3_t *a,
887 const graphene_vec3_t *b,
888 graphene_vec3_t *res)
889 {
890 res->value = graphene_simd4f_cross3 (a->value, b->value);
891 }
892
893 /**
894 * graphene_vec3_dot:
895 * @a: a #graphene_vec3_t
896 * @b: a #graphene_vec3_t
897 *
898 * Computes the dot product of the two given vectors.
899 *
900 * Returns: the value of the dot product
901 *
902 * Since: 1.0
903 */
904 float
graphene_vec3_dot(const graphene_vec3_t * a,const graphene_vec3_t * b)905 graphene_vec3_dot (const graphene_vec3_t *a,
906 const graphene_vec3_t *b)
907 {
908 return graphene_simd4f_dot3_scalar (a->value, b->value);
909 }
910
911 /**
912 * graphene_vec3_length:
913 * @v: a #graphene_vec3_t
914 *
915 * Retrieves the length of the given vector @v.
916 *
917 * Returns: the value of the length of the vector
918 *
919 * Since: 1.0
920 */
921 float
graphene_vec3_length(const graphene_vec3_t * v)922 graphene_vec3_length (const graphene_vec3_t *v)
923 {
924 return graphene_simd4f_get_x (graphene_simd4f_length3 (v->value));
925 }
926
927 /**
928 * graphene_vec3_normalize:
929 * @v: a #graphene_vec3_t
930 * @res: (out caller-allocates): return location for the normalized vector
931 *
932 * Normalizes the given #graphene_vec3_t.
933 *
934 * Since: 1.0
935 */
936 void
graphene_vec3_normalize(const graphene_vec3_t * v,graphene_vec3_t * res)937 graphene_vec3_normalize (const graphene_vec3_t *v,
938 graphene_vec3_t *res)
939 {
940 if (fabsf (graphene_vec3_length (v)) > FLT_EPSILON)
941 res->value = graphene_simd4f_normalize3 (v->value);
942 else
943 res->value = graphene_simd4f_init_zero ();
944 }
945
946 /**
947 * graphene_vec3_min:
948 * @a: a #graphene_vec3_t
949 * @b: a #graphene_vec3_t
950 * @res: (out caller-allocates): return location for the result vector
951 *
952 * Compares each component of the two given vectors and creates a
953 * vector that contains the minimum values.
954 *
955 * Since: 1.0
956 */
957 void
graphene_vec3_min(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)958 graphene_vec3_min (const graphene_vec3_t *a,
959 const graphene_vec3_t *b,
960 graphene_vec3_t *res)
961 {
962 res->value = graphene_simd4f_min (a->value, b->value);
963 }
964
965 /**
966 * graphene_vec3_max:
967 * @a: a #graphene_vec3_t
968 * @b: a #graphene_vec3_t
969 * @res: (out caller-allocates): return location for the result vector
970 *
971 * Compares each component of the two given vectors and creates a
972 * vector that contains the maximum values.
973 *
974 * Since: 1.0
975 */
976 void
graphene_vec3_max(const graphene_vec3_t * a,const graphene_vec3_t * b,graphene_vec3_t * res)977 graphene_vec3_max (const graphene_vec3_t *a,
978 const graphene_vec3_t *b,
979 graphene_vec3_t *res)
980 {
981 res->value = graphene_simd4f_max (a->value, b->value);
982 }
983
984 /**
985 * graphene_vec3_scale:
986 * @v: a #graphene_vec3_t
987 * @factor: the scalar factor
988 * @res: (out caller-allocates): return location for the result vector
989 *
990 * Multiplies all components of the given vector with the given scalar @factor.
991 *
992 * Since: 1.2
993 */
994 void
graphene_vec3_scale(const graphene_vec3_t * v,float factor,graphene_vec3_t * res)995 graphene_vec3_scale (const graphene_vec3_t *v,
996 float factor,
997 graphene_vec3_t *res)
998 {
999 res->value = graphene_simd4f_mul (v->value, graphene_simd4f_splat (factor));
1000 }
1001
1002 /**
1003 * graphene_vec3_get_xy:
1004 * @v: a #graphene_vec3_t
1005 * @res: (out caller-allocates): return location for a #graphene_vec2_t
1006 *
1007 * Creates a #graphene_vec2_t that contains the first and second
1008 * components of the given #graphene_vec3_t.
1009 *
1010 * Since: 1.0
1011 */
1012 void
graphene_vec3_get_xy(const graphene_vec3_t * v,graphene_vec2_t * res)1013 graphene_vec3_get_xy (const graphene_vec3_t *v,
1014 graphene_vec2_t *res)
1015 {
1016 res->value = graphene_simd4f_zero_zw (v->value);
1017 }
1018
1019 /**
1020 * graphene_vec3_get_xy0:
1021 * @v: a #graphene_vec3_t
1022 * @res: (out caller-allocates): return location for a #graphene_vec3_t
1023 *
1024 * Creates a #graphene_vec3_t that contains the first two components of
1025 * the given #graphene_vec3_t, and the third component set to 0.
1026 *
1027 * Since: 1.0
1028 */
1029 void
graphene_vec3_get_xy0(const graphene_vec3_t * v,graphene_vec3_t * res)1030 graphene_vec3_get_xy0 (const graphene_vec3_t *v,
1031 graphene_vec3_t *res)
1032 {
1033 res->value = graphene_simd4f_zero_zw (v->value);
1034 }
1035
1036 /**
1037 * graphene_vec3_get_xyz0:
1038 * @v: a #graphene_vec3_t
1039 * @res: (out caller-allocates): return location for the vector
1040 *
1041 * Converts a #graphene_vec3_t in a #graphene_vec4_t using 0.0
1042 * as the value for the fourth component of the resulting vector.
1043 *
1044 * Since: 1.0
1045 */
1046 void
graphene_vec3_get_xyz0(const graphene_vec3_t * v,graphene_vec4_t * res)1047 graphene_vec3_get_xyz0 (const graphene_vec3_t *v,
1048 graphene_vec4_t *res)
1049 {
1050 res->value = graphene_simd4f_zero_w (v->value);
1051 }
1052
1053 /**
1054 * graphene_vec3_get_xyz1:
1055 * @v: a #graphene_vec3_t
1056 * @res: (out caller-allocates): return location for the vector
1057 *
1058 * Converts a #graphene_vec3_t in a #graphene_vec4_t using 1.0
1059 * as the value for the fourth component of the resulting vector.
1060 *
1061 * Since: 1.0
1062 */
1063 void
graphene_vec3_get_xyz1(const graphene_vec3_t * v,graphene_vec4_t * res)1064 graphene_vec3_get_xyz1 (const graphene_vec3_t *v,
1065 graphene_vec4_t *res)
1066 {
1067 res->value = graphene_simd4f_add (graphene_simd4f_zero_w (v->value),
1068 graphene_simd4f_init (0.f, 0.f, 0.f, 1.f));
1069 }
1070
1071 /**
1072 * graphene_vec3_get_xyzw:
1073 * @v: a #graphene_vec3_t
1074 * @w: the value of the W component
1075 * @res: (out caller-allocates): return location for the vector
1076 *
1077 * Converts a #graphene_vec3_t in a #graphene_vec4_t using @w as
1078 * the value of the fourth component of the resulting vector.
1079 *
1080 * Since: 1.0
1081 */
1082 void
graphene_vec3_get_xyzw(const graphene_vec3_t * v,float w,graphene_vec4_t * res)1083 graphene_vec3_get_xyzw (const graphene_vec3_t *v,
1084 float w,
1085 graphene_vec4_t *res)
1086 {
1087 res->value = graphene_simd4f_add (graphene_simd4f_zero_w (v->value),
1088 graphene_simd4f_init (0.f, 0.f, 0.f, w));
1089 }
1090
1091 /**
1092 * graphene_vec3_negate:
1093 * @v: a #graphene_vec3_t
1094 * @res: (out caller-allocates): return location for the result vector
1095 *
1096 * Negates the given #graphene_vec3_t.
1097 *
1098 * Since: 1.2
1099 */
1100 void
graphene_vec3_negate(const graphene_vec3_t * v,graphene_vec3_t * res)1101 graphene_vec3_negate (const graphene_vec3_t *v,
1102 graphene_vec3_t *res)
1103 {
1104 res->value = graphene_simd4f_neg (v->value);
1105 }
1106
1107 static bool
vec3_equal(const void * p1,const void * p2)1108 vec3_equal (const void *p1,
1109 const void *p2)
1110 {
1111 const graphene_vec3_t *v1 = p1;
1112 const graphene_vec3_t *v2 = p2;
1113
1114 if (graphene_simd4f_cmp_eq (v1->value, v2->value))
1115 return true;
1116
1117 return graphene_vec3_near (v1, v2, GRAPHENE_FLOAT_EPSILON);
1118 }
1119
1120 /**
1121 * graphene_vec3_equal:
1122 * @v1: a #graphene_vec3_t
1123 * @v2: a #graphene_vec3_t
1124 *
1125 * Checks whether the two given #graphene_vec3_t are equal.
1126 *
1127 * Returns: `true` if the two vectors are equal, and false otherwise
1128 *
1129 * Since: 1.2
1130 */
1131 bool
graphene_vec3_equal(const graphene_vec3_t * v1,const graphene_vec3_t * v2)1132 graphene_vec3_equal (const graphene_vec3_t *v1,
1133 const graphene_vec3_t *v2)
1134 {
1135 return graphene_pointer_equal (v1, v2, vec3_equal);
1136 }
1137
1138 /**
1139 * graphene_vec3_near:
1140 * @v1: a #graphene_vec3_t
1141 * @v2: a #graphene_vec3_t
1142 * @epsilon: the threshold between the two vectors
1143 *
1144 * Compares the two given #graphene_vec3_t vectors and checks
1145 * whether their values are within the given @epsilon.
1146 *
1147 * Returns: `true` if the two vectors are near each other
1148 *
1149 * Since: 1.2
1150 */
1151 bool
graphene_vec3_near(const graphene_vec3_t * v1,const graphene_vec3_t * v2,float epsilon)1152 graphene_vec3_near (const graphene_vec3_t *v1,
1153 const graphene_vec3_t *v2,
1154 float epsilon)
1155 {
1156 graphene_simd4f_t d = graphene_simd4f_sub (v1->value, v2->value);
1157 float epsilon_sq = epsilon * epsilon;
1158
1159 return graphene_simd4f_dot3_scalar (d, d) < epsilon_sq;
1160 }
1161
1162 /**
1163 * graphene_vec3_interpolate:
1164 * @v1: a #graphene_vec3_t
1165 * @v2: a #graphene_vec3_t
1166 * @factor: the interpolation factor
1167 * @res: (out caller-allocates): the interpolated vector
1168 *
1169 * Linearly interpolates @v1 and @v2 using the given @factor.
1170 *
1171 * Since: 1.10
1172 */
1173 void
graphene_vec3_interpolate(const graphene_vec3_t * v1,const graphene_vec3_t * v2,double factor,graphene_vec3_t * res)1174 graphene_vec3_interpolate (const graphene_vec3_t *v1,
1175 const graphene_vec3_t *v2,
1176 double factor,
1177 graphene_vec3_t *res)
1178 {
1179 res->value = graphene_simd4f_interpolate (v1->value, v2->value, (float) factor);
1180 }
1181
1182 enum {
1183 VEC3_ZERO,
1184 VEC3_ONE,
1185 VEC3_X_AXIS,
1186 VEC3_Y_AXIS,
1187 VEC3_Z_AXIS,
1188
1189 N_STATIC_VEC3
1190 };
1191
1192 static graphene_vec3_t static_vec3[N_STATIC_VEC3];
1193
1194 static void
init_static_vec3_once(void)1195 init_static_vec3_once (void)
1196 {
1197 static_vec3[VEC3_ZERO].value = graphene_simd4f_init_zero ();
1198 static_vec3[VEC3_ONE].value = graphene_simd4f_init (1.f, 1.f, 1.f, 0.f);
1199 static_vec3[VEC3_X_AXIS].value = graphene_simd4f_init (1.f, 0.f, 0.f, 0.f);
1200 static_vec3[VEC3_Y_AXIS].value = graphene_simd4f_init (0.f, 1.f, 0.f, 0.f);
1201 static_vec3[VEC3_Z_AXIS].value = graphene_simd4f_init (0.f, 0.f, 1.f, 0.f);
1202 }
1203
1204 #ifdef HAVE_PTHREAD
1205 static pthread_once_t static_vec3_once = PTHREAD_ONCE_INIT;
1206
1207 static inline void
init_static_vec3(void)1208 init_static_vec3 (void)
1209 {
1210 int status = pthread_once (&static_vec3_once, init_static_vec3_once);
1211
1212 if (status < 0)
1213 {
1214 int saved_errno = errno;
1215
1216 fprintf (stderr, "pthread_once failed: %s (errno:%d)\n",
1217 strerror (saved_errno),
1218 saved_errno);
1219 }
1220 }
1221
1222 #elif defined(HAVE_INIT_ONCE)
1223 static INIT_ONCE static_vec3_once = INIT_ONCE_STATIC_INIT;
1224
1225 static BOOL CALLBACK
InitVec3Func(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * lpContext)1226 InitVec3Func (PINIT_ONCE InitOnce,
1227 PVOID Parameter,
1228 PVOID *lpContext)
1229 {
1230 init_static_vec3_once ();
1231 return TRUE;
1232 }
1233
1234 static inline void
init_static_vec3(void)1235 init_static_vec3 (void)
1236 {
1237 BOOL bStatus = InitOnceExecuteOnce (&static_vec3_once,
1238 InitVec3Func,
1239 NULL,
1240 NULL);
1241
1242 if (!bStatus)
1243 fprintf (stderr, "InitOnceExecuteOnce failed\n");
1244 }
1245
1246 #else /* !HAVE_PTHREAD && !HAVE_INIT_ONCE*/
1247 static bool static_vec3_init = false;
1248
1249 static inline void
init_static_vec3(void)1250 init_static_vec3 (void)
1251 {
1252 if (static_vec3_init)
1253 return;
1254
1255 init_static_vec3_once ();
1256 static_vec3_init = true;
1257 }
1258 #endif /* HAVE_PTHREAD */
1259
1260 /**
1261 * graphene_vec3_zero:
1262 *
1263 * Provides a constant pointer to a vector with three components,
1264 * all sets to 0.
1265 *
1266 * Returns: (transfer none): a constant vector
1267 *
1268 * Since: 1.0
1269 */
1270 const graphene_vec3_t *
graphene_vec3_zero(void)1271 graphene_vec3_zero (void)
1272 {
1273 init_static_vec3 ();
1274
1275 return &(static_vec3[VEC3_ZERO]);
1276 }
1277
1278 /**
1279 * graphene_vec3_one:
1280 *
1281 * Provides a constant pointer to a vector with three components,
1282 * all sets to 1.
1283 *
1284 * Returns: (transfer none): a constant vector
1285 *
1286 * Since: 1.0
1287 */
1288 const graphene_vec3_t *
graphene_vec3_one(void)1289 graphene_vec3_one (void)
1290 {
1291 init_static_vec3 ();
1292
1293 return &(static_vec3[VEC3_ONE]);
1294 }
1295
1296 /**
1297 * graphene_vec3_x_axis:
1298 *
1299 * Provides a constant pointer to a vector with three components
1300 * with values set to (1, 0, 0).
1301 *
1302 * Returns: (transfer none): a constant vector
1303 *
1304 * Since: 1.0
1305 */
1306 const graphene_vec3_t *
graphene_vec3_x_axis(void)1307 graphene_vec3_x_axis (void)
1308 {
1309 init_static_vec3 ();
1310
1311 return &(static_vec3[VEC3_X_AXIS]);
1312 }
1313
1314 /**
1315 * graphene_vec3_y_axis:
1316 *
1317 * Provides a constant pointer to a vector with three components
1318 * with values set to (0, 1, 0).
1319 *
1320 * Returns: (transfer none): a constant vector
1321 *
1322 * Since: 1.0
1323 */
1324 const graphene_vec3_t *
graphene_vec3_y_axis(void)1325 graphene_vec3_y_axis (void)
1326 {
1327 init_static_vec3 ();
1328
1329 return &(static_vec3[VEC3_Y_AXIS]);
1330 }
1331
1332 /**
1333 * graphene_vec3_z_axis:
1334 *
1335 * Provides a constant pointer to a vector with three components
1336 * with values set to (0, 0, 1).
1337 *
1338 * Returns: (transfer none): a constant vector
1339 *
1340 * Since: 1.0
1341 */
1342 const graphene_vec3_t *
graphene_vec3_z_axis(void)1343 graphene_vec3_z_axis (void)
1344 {
1345 init_static_vec3 ();
1346
1347 return &(static_vec3[VEC3_Z_AXIS]);
1348 }
1349
1350 /* }}} vec3 */
1351
1352 /* vec4 {{{ */
1353 /**
1354 * graphene_vec4_alloc: (constructor)
1355 *
1356 * Allocates a new #graphene_vec4_t structure.
1357 *
1358 * The contents of the returned structure are undefined.
1359 *
1360 * Use graphene_vec4_init() to initialize the vector.
1361 *
1362 * Returns: (transfer full): the newly allocated #graphene_vec4_t
1363 * structure. Use graphene_vec4_free() to free the resources allocated
1364 * by this function.
1365 *
1366 * Since: 1.0
1367 */
1368 graphene_vec4_t *
graphene_vec4_alloc(void)1369 graphene_vec4_alloc (void)
1370 {
1371 return graphene_aligned_alloc (sizeof (graphene_vec4_t), 1, 16);
1372 }
1373
1374 /**
1375 * graphene_vec4_free:
1376 * @v: a #graphene_vec4_t
1377 *
1378 * Frees the resources allocated by @v
1379 *
1380 * Since: 1.0
1381 */
1382 void
graphene_vec4_free(graphene_vec4_t * v)1383 graphene_vec4_free (graphene_vec4_t *v)
1384 {
1385 graphene_aligned_free (v);
1386 }
1387
1388 /**
1389 * graphene_vec4_init:
1390 * @v: a #graphene_vec4_t
1391 * @x: the X field of the vector
1392 * @y: the Y field of the vector
1393 * @z: the Z field of the vector
1394 * @w: the W field of the vector
1395 *
1396 * Initializes a #graphene_vec4_t using the given values.
1397 *
1398 * This function can be called multiple times.
1399 *
1400 * Returns: (transfer none): a pointer to the initialized
1401 * vector
1402 *
1403 * Since: 1.0
1404 */
1405 graphene_vec4_t *
graphene_vec4_init(graphene_vec4_t * v,float x,float y,float z,float w)1406 graphene_vec4_init (graphene_vec4_t *v,
1407 float x,
1408 float y,
1409 float z,
1410 float w)
1411 {
1412 v->value = graphene_simd4f_init (x, y, z, w);
1413
1414 return v;
1415 }
1416
1417 /**
1418 * graphene_vec4_init_from_vec4:
1419 * @v: a #graphene_vec4_t
1420 * @src: a #graphene_vec4_t
1421 *
1422 * Initializes a #graphene_vec4_t using the components of
1423 * another #graphene_vec4_t.
1424 *
1425 * Returns: (transfer none): the initialized vector
1426 *
1427 * Since: 1.0
1428 */
1429 graphene_vec4_t *
graphene_vec4_init_from_vec4(graphene_vec4_t * v,const graphene_vec4_t * src)1430 graphene_vec4_init_from_vec4 (graphene_vec4_t *v,
1431 const graphene_vec4_t *src)
1432 {
1433 v->value = src->value;
1434
1435 return v;
1436 }
1437
1438 /**
1439 * graphene_vec4_init_from_vec3:
1440 * @v: a #graphene_vec4_t
1441 * @src: a #graphene_vec3_t
1442 * @w: the value for the fourth component of @v
1443 *
1444 * Initializes a #graphene_vec4_t using the components of a
1445 * #graphene_vec3_t and the value of @w.
1446 *
1447 * Returns: (transfer none): the initialized vector
1448 *
1449 * Since: 1.0
1450 */
1451 graphene_vec4_t *
graphene_vec4_init_from_vec3(graphene_vec4_t * v,const graphene_vec3_t * src,float w)1452 graphene_vec4_init_from_vec3 (graphene_vec4_t *v,
1453 const graphene_vec3_t *src,
1454 float w)
1455 {
1456 v->value = graphene_simd4f_merge_w (src->value, w);
1457
1458 return v;
1459 }
1460
1461 /**
1462 * graphene_vec4_init_from_vec2:
1463 * @v: a #graphene_vec4_t
1464 * @src: a #graphene_vec2_t
1465 * @z: the value for the third component of @v
1466 * @w: the value for the fourth component of @v
1467 *
1468 * Initializes a #graphene_vec4_t using the components of a
1469 * #graphene_vec2_t and the values of @z and @w.
1470 *
1471 * Returns: (transfer none): the initialized vector
1472 *
1473 * Since: 1.0
1474 */
1475 graphene_vec4_t *
graphene_vec4_init_from_vec2(graphene_vec4_t * v,const graphene_vec2_t * src,float z,float w)1476 graphene_vec4_init_from_vec2 (graphene_vec4_t *v,
1477 const graphene_vec2_t *src,
1478 float z,
1479 float w)
1480 {
1481 v->value = graphene_simd4f_merge_low (src->value, graphene_simd4f_init (z, w, 0, 0));
1482
1483 return v;
1484 }
1485
1486 /**
1487 * graphene_vec4_init_from_float:
1488 * @v: a #graphene_vec4_t
1489 * @src: (array fixed-size=4): an array of four floating point values
1490 *
1491 * Initializes a #graphene_vec4_t with the values inside the given array.
1492 *
1493 * Returns: (transfer none): the initialized vector
1494 *
1495 * Since: 1.0
1496 */
1497 graphene_vec4_t *
graphene_vec4_init_from_float(graphene_vec4_t * v,const float * src)1498 graphene_vec4_init_from_float (graphene_vec4_t *v,
1499 const float *src)
1500 {
1501 v->value = graphene_simd4f_init_4f (src);
1502
1503 return v;
1504 }
1505
1506 /**
1507 * graphene_vec4_get_x:
1508 * @v: a #graphene_vec4_t
1509 *
1510 * Retrieves the value of the first component of the given #graphene_vec4_t.
1511 *
1512 * Returns: the value of the first component
1513 *
1514 * Since: 1.0
1515 */
1516 float
graphene_vec4_get_x(const graphene_vec4_t * v)1517 graphene_vec4_get_x (const graphene_vec4_t *v)
1518 {
1519 return graphene_simd4f_get_x (v->value);
1520 }
1521
1522 /**
1523 * graphene_vec4_get_y:
1524 * @v: a #graphene_vec4_t
1525 *
1526 * Retrieves the value of the second component of the given #graphene_vec4_t.
1527 *
1528 * Returns: the value of the second component
1529 *
1530 * Since: 1.0
1531 */
1532 float
graphene_vec4_get_y(const graphene_vec4_t * v)1533 graphene_vec4_get_y (const graphene_vec4_t *v)
1534 {
1535 return graphene_simd4f_get_y (v->value);
1536 }
1537
1538 /**
1539 * graphene_vec4_get_z:
1540 * @v: a #graphene_vec4_t
1541 *
1542 * Retrieves the value of the third component of the given #graphene_vec4_t.
1543 *
1544 * Returns: the value of the third component
1545 *
1546 * Since: 1.0
1547 */
1548 float
graphene_vec4_get_z(const graphene_vec4_t * v)1549 graphene_vec4_get_z (const graphene_vec4_t *v)
1550 {
1551 return graphene_simd4f_get_z (v->value);
1552 }
1553
1554 /**
1555 * graphene_vec4_get_w:
1556 * @v: a #graphene_vec4_t
1557 *
1558 * Retrieves the value of the fourth component of the given #graphene_vec4_t.
1559 *
1560 * Returns: the value of the fourth component
1561 *
1562 * Since: 1.0
1563 */
1564 float
graphene_vec4_get_w(const graphene_vec4_t * v)1565 graphene_vec4_get_w (const graphene_vec4_t *v)
1566 {
1567 return graphene_simd4f_get_w (v->value);
1568 }
1569
1570 /**
1571 * graphene_vec4_to_float:
1572 * @v: a #graphene_vec4_t
1573 * @dest: (out caller-allocates) (array fixed-size=4): return location for
1574 * an array of floating point values
1575 *
1576 * Stores the components of the given #graphene_vec4_t into an array
1577 * of floating point values.
1578 *
1579 * Since: 1.0
1580 */
1581 void
graphene_vec4_to_float(const graphene_vec4_t * v,float * dest)1582 graphene_vec4_to_float (const graphene_vec4_t *v,
1583 float *dest)
1584 {
1585 graphene_simd4f_dup_4f (v->value, dest);
1586 }
1587
1588 /**
1589 * graphene_vec4_add:
1590 * @a: a #graphene_vec4_t
1591 * @b: a #graphene_vec4_t
1592 * @res: (out caller-allocates): return location for the resulting vector
1593 *
1594 * Adds each component of the two given vectors.
1595 *
1596 * Since: 1.0
1597 */
1598 void
graphene_vec4_add(const graphene_vec4_t * a,const graphene_vec4_t * b,graphene_vec4_t * res)1599 graphene_vec4_add (const graphene_vec4_t *a,
1600 const graphene_vec4_t *b,
1601 graphene_vec4_t *res)
1602 {
1603 res->value = graphene_simd4f_add (a->value, b->value);
1604 }
1605
1606 /**
1607 * graphene_vec4_subtract:
1608 * @a: a #graphene_vec4_t
1609 * @b: a #graphene_vec4_t
1610 * @res: (out caller-allocates): return location for the resulting vector
1611 *
1612 * Subtracts from each component of the first operand @a the
1613 * corresponding component of the second operand @b and places
1614 * each result into the components of @res.
1615 *
1616 * Since: 1.0
1617 */
1618 void
graphene_vec4_subtract(const graphene_vec4_t * a,const graphene_vec4_t * b,graphene_vec4_t * res)1619 graphene_vec4_subtract (const graphene_vec4_t *a,
1620 const graphene_vec4_t *b,
1621 graphene_vec4_t *res)
1622 {
1623 res->value = graphene_simd4f_sub (a->value, b->value);
1624 }
1625
1626 /**
1627 * graphene_vec4_multiply:
1628 * @a: a #graphene_vec4_t
1629 * @b: a #graphene_vec4_t
1630 * @res: (out caller-allocates): return location for the resulting vector
1631 *
1632 * Multiplies each component of the two given vectors.
1633 *
1634 * Since: 1.0
1635 */
1636 void
graphene_vec4_multiply(const graphene_vec4_t * a,const graphene_vec4_t * b,graphene_vec4_t * res)1637 graphene_vec4_multiply (const graphene_vec4_t *a,
1638 const graphene_vec4_t *b,
1639 graphene_vec4_t *res)
1640 {
1641 res->value = graphene_simd4f_mul (a->value, b->value);
1642 }
1643
1644 /**
1645 * graphene_vec4_divide:
1646 * @a: a #graphene_vec4_t
1647 * @b: a #graphene_vec4_t
1648 * @res: (out caller-allocates): return location for the resulting vector
1649 *
1650 * Divides each component of the first operand @a by the corresponding
1651 * component of the second operand @b, and places the results into the
1652 * vector @res.
1653 *
1654 * Since: 1.0
1655 */
1656 void
graphene_vec4_divide(const graphene_vec4_t * a,const graphene_vec4_t * b,graphene_vec4_t * res)1657 graphene_vec4_divide (const graphene_vec4_t *a,
1658 const graphene_vec4_t *b,
1659 graphene_vec4_t *res)
1660 {
1661 res->value = graphene_simd4f_div (a->value, b->value);
1662 }
1663
1664 /**
1665 * graphene_vec4_dot:
1666 * @a: a #graphene_vec4_t
1667 * @b: a #graphene_vec4_t
1668 *
1669 * Computes the dot product of the two given vectors.
1670 *
1671 * Returns: the value of the dot product
1672 *
1673 * Since: 1.0
1674 */
1675 float
graphene_vec4_dot(const graphene_vec4_t * a,const graphene_vec4_t * b)1676 graphene_vec4_dot (const graphene_vec4_t *a,
1677 const graphene_vec4_t *b)
1678 {
1679 return graphene_simd4f_get_x (graphene_simd4f_dot4 (a->value, b->value));
1680 }
1681
1682 /**
1683 * graphene_vec4_length:
1684 * @v: a #graphene_vec4_t
1685 *
1686 * Computes the length of the given #graphene_vec4_t.
1687 *
1688 * Returns: the length of the vector
1689 *
1690 * Since: 1.0
1691 */
1692 float
graphene_vec4_length(const graphene_vec4_t * v)1693 graphene_vec4_length (const graphene_vec4_t *v)
1694 {
1695 return graphene_simd4f_get_x (graphene_simd4f_length4 (v->value));
1696 }
1697
1698 /**
1699 * graphene_vec4_normalize:
1700 * @v: a #graphene_vec4_t
1701 * @res: (out caller-allocates): return location for the normalized
1702 * vector
1703 *
1704 * Normalizes the given #graphene_vec4_t.
1705 *
1706 * Since: 1.0
1707 */
1708 void
graphene_vec4_normalize(const graphene_vec4_t * v,graphene_vec4_t * res)1709 graphene_vec4_normalize (const graphene_vec4_t *v,
1710 graphene_vec4_t *res)
1711 {
1712 if (fabsf (graphene_vec4_length (v)) > FLT_EPSILON)
1713 res->value = graphene_simd4f_normalize4 (v->value);
1714 else
1715 res->value = graphene_simd4f_init_zero ();
1716 }
1717
1718 /**
1719 * graphene_vec4_min:
1720 * @a: a #graphene_vec4_t
1721 * @b: a #graphene_vec4_t
1722 * @res: (out caller-allocates): return location for the result vector
1723 *
1724 * Compares each component of the two given vectors and creates a
1725 * vector that contains the minimum values.
1726 *
1727 * Since: 1.0
1728 */
1729 void
graphene_vec4_min(const graphene_vec4_t * a,const graphene_vec4_t * b,graphene_vec4_t * res)1730 graphene_vec4_min (const graphene_vec4_t *a,
1731 const graphene_vec4_t *b,
1732 graphene_vec4_t *res)
1733 {
1734 res->value = graphene_simd4f_min (a->value, b->value);
1735 }
1736
1737 /**
1738 * graphene_vec4_max:
1739 * @a: a #graphene_vec4_t
1740 * @b: a #graphene_vec4_t
1741 * @res: (out caller-allocates): return location for the result vector
1742 *
1743 * Compares each component of the two given vectors and creates a
1744 * vector that contains the maximum values.
1745 *
1746 * Since: 1.0
1747 */
1748 void
graphene_vec4_max(const graphene_vec4_t * a,const graphene_vec4_t * b,graphene_vec4_t * res)1749 graphene_vec4_max (const graphene_vec4_t *a,
1750 const graphene_vec4_t *b,
1751 graphene_vec4_t *res)
1752 {
1753 res->value = graphene_simd4f_max (a->value, b->value);
1754 }
1755
1756 /**
1757 * graphene_vec4_scale:
1758 * @v: a #graphene_vec4_t
1759 * @factor: the scalar factor
1760 * @res: (out caller-allocates): return location for the result vector
1761 *
1762 * Multiplies all components of the given vector with the given scalar @factor.
1763 *
1764 * Since: 1.2
1765 */
1766 void
graphene_vec4_scale(const graphene_vec4_t * v,float factor,graphene_vec4_t * res)1767 graphene_vec4_scale (const graphene_vec4_t *v,
1768 float factor,
1769 graphene_vec4_t *res)
1770 {
1771 res->value = graphene_simd4f_mul (v->value, graphene_simd4f_splat (factor));
1772 }
1773
1774 /**
1775 * graphene_vec4_get_xy:
1776 * @v: a #graphene_vec4_t
1777 * @res: (out caller-allocates): return location for a #graphene_vec2_t
1778 *
1779 * Creates a #graphene_vec2_t that contains the first two components
1780 * of the given #graphene_vec4_t.
1781 *
1782 * Since: 1.0
1783 */
1784 void
graphene_vec4_get_xy(const graphene_vec4_t * v,graphene_vec2_t * res)1785 graphene_vec4_get_xy (const graphene_vec4_t *v,
1786 graphene_vec2_t *res)
1787 {
1788 res->value = graphene_simd4f_zero_zw (v->value);
1789 }
1790
1791 /**
1792 * graphene_vec4_get_xyz:
1793 * @v: a #graphene_vec4_t
1794 * @res: (out caller-allocates): return location for a graphene_vec3_t
1795 *
1796 * Creates a #graphene_vec3_t that contains the first three components
1797 * of the given #graphene_vec4_t.
1798 *
1799 * Since: 1.0
1800 */
1801 void
graphene_vec4_get_xyz(const graphene_vec4_t * v,graphene_vec3_t * res)1802 graphene_vec4_get_xyz (const graphene_vec4_t *v,
1803 graphene_vec3_t *res)
1804 {
1805 res->value = graphene_simd4f_zero_w (v->value);
1806 }
1807
1808 /**
1809 * graphene_vec4_negate:
1810 * @v: a #graphene_vec4_t
1811 * @res: (out caller-allocates): return location for the result vector
1812 *
1813 * Negates the given #graphene_vec4_t.
1814 *
1815 * Since: 1.2
1816 */
1817 void
graphene_vec4_negate(const graphene_vec4_t * v,graphene_vec4_t * res)1818 graphene_vec4_negate (const graphene_vec4_t *v,
1819 graphene_vec4_t *res)
1820 {
1821 res->value = graphene_simd4f_neg (v->value);
1822 }
1823
1824 static bool
vec4_equal(const void * p1,const void * p2)1825 vec4_equal (const void *p1,
1826 const void *p2)
1827 {
1828 const graphene_vec4_t *v1 = p1;
1829 const graphene_vec4_t *v2 = p2;
1830
1831 if (graphene_simd4f_cmp_eq (v1->value, v2->value))
1832 return true;
1833
1834 return graphene_vec4_near (v1, v2, GRAPHENE_FLOAT_EPSILON);
1835 }
1836
1837 /**
1838 * graphene_vec4_equal:
1839 * @v1: a #graphene_vec4_t
1840 * @v2: a #graphene_vec4_t
1841 *
1842 * Checks whether the two given #graphene_vec4_t are equal.
1843 *
1844 * Returns: `true` if the two vectors are equal, and false otherwise
1845 *
1846 * Since: 1.2
1847 */
1848 bool
graphene_vec4_equal(const graphene_vec4_t * v1,const graphene_vec4_t * v2)1849 graphene_vec4_equal (const graphene_vec4_t *v1,
1850 const graphene_vec4_t *v2)
1851 {
1852 return graphene_pointer_equal (v1, v2, vec4_equal);
1853 }
1854
1855 /**
1856 * graphene_vec4_near:
1857 * @v1: a #graphene_vec4_t
1858 * @v2: a #graphene_vec4_t
1859 * @epsilon: the threshold between the two vectors
1860 *
1861 * Compares the two given #graphene_vec4_t vectors and checks
1862 * whether their values are within the given @epsilon.
1863 *
1864 * Returns: `true` if the two vectors are near each other
1865 *
1866 * Since: 1.2
1867 */
1868 bool
graphene_vec4_near(const graphene_vec4_t * v1,const graphene_vec4_t * v2,float epsilon)1869 graphene_vec4_near (const graphene_vec4_t *v1,
1870 const graphene_vec4_t *v2,
1871 float epsilon)
1872 {
1873 graphene_simd4f_t d = graphene_simd4f_sub (v1->value, v2->value);
1874 float epsilon_sq = epsilon * epsilon;
1875
1876 return graphene_simd4f_get_x (graphene_simd4f_dot4 (d, d)) < epsilon_sq;
1877 }
1878
1879 /**
1880 * graphene_vec4_interpolate:
1881 * @v1: a #graphene_vec4_t
1882 * @v2: a #graphene_vec4_t
1883 * @factor: the interpolation factor
1884 * @res: (out caller-allocates): the interpolated vector
1885 *
1886 * Linearly interpolates @v1 and @v2 using the given @factor.
1887 *
1888 * Since: 1.10
1889 */
1890 void
graphene_vec4_interpolate(const graphene_vec4_t * v1,const graphene_vec4_t * v2,double factor,graphene_vec4_t * res)1891 graphene_vec4_interpolate (const graphene_vec4_t *v1,
1892 const graphene_vec4_t *v2,
1893 double factor,
1894 graphene_vec4_t *res)
1895 {
1896 res->value = graphene_simd4f_interpolate (v1->value, v2->value, (float) factor);
1897 }
1898
1899 enum {
1900 VEC4_ZERO,
1901 VEC4_ONE,
1902 VEC4_X_AXIS,
1903 VEC4_Y_AXIS,
1904 VEC4_Z_AXIS,
1905 VEC4_W_AXIS,
1906
1907 N_STATIC_VEC4
1908 };
1909
1910 static graphene_vec4_t static_vec4[N_STATIC_VEC4];
1911
1912 static void
init_static_vec4_once(void)1913 init_static_vec4_once (void)
1914 {
1915 static_vec4[VEC4_ZERO].value = graphene_simd4f_init_zero ();
1916 static_vec4[VEC4_ONE].value = graphene_simd4f_splat (1.f);
1917 static_vec4[VEC4_X_AXIS].value = graphene_simd4f_init (1.f, 0.f, 0.f, 0.f);
1918 static_vec4[VEC4_Y_AXIS].value = graphene_simd4f_init (0.f, 1.f, 0.f, 0.f);
1919 static_vec4[VEC4_Z_AXIS].value = graphene_simd4f_init (0.f, 0.f, 1.f, 0.f);
1920 static_vec4[VEC4_W_AXIS].value = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f);
1921 }
1922
1923 #ifdef HAVE_PTHREAD
1924 static pthread_once_t static_vec4_init_once = PTHREAD_ONCE_INIT;
1925
1926 static inline void
init_static_vec4(void)1927 init_static_vec4 (void)
1928 {
1929 int status = pthread_once (&static_vec4_init_once, init_static_vec4_once);
1930
1931 if (status < 0)
1932 {
1933 int saved_errno = errno;
1934
1935 fprintf (stderr, "pthread_once failed: %s (errno:%d)\n",
1936 strerror (saved_errno),
1937 saved_errno);
1938 }
1939 }
1940
1941 #elif defined(HAVE_INIT_ONCE)
1942 static INIT_ONCE static_vec4_once = INIT_ONCE_STATIC_INIT;
1943
1944 static BOOL CALLBACK
InitVec4Func(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * lpContext)1945 InitVec4Func (PINIT_ONCE InitOnce,
1946 PVOID Parameter,
1947 PVOID *lpContext)
1948 {
1949 init_static_vec4_once ();
1950 return TRUE;
1951 }
1952
1953 static inline void
init_static_vec4(void)1954 init_static_vec4 (void)
1955 {
1956 BOOL bStatus = InitOnceExecuteOnce (&static_vec4_once,
1957 InitVec4Func,
1958 NULL,
1959 NULL);
1960
1961 if (!bStatus)
1962 fprintf (stderr, "InitOnceExecuteOnce failed\n");
1963 }
1964
1965 #else /* !HAVE_PTHREAD && !HAVE_INIT_ONCE */
1966
1967 static bool static_vec4_init = false;
1968
1969 static inline void
init_static_vec4(void)1970 init_static_vec4 (void)
1971 {
1972 if (static_vec4_init)
1973 return;
1974
1975 init_static_vec4_once ();
1976 static_vec4_init = true;
1977 }
1978 #endif /* HAVE_PTHREAD */
1979
1980 /**
1981 * graphene_vec4_zero:
1982 *
1983 * Retrieves a pointer to a #graphene_vec4_t with all its
1984 * components set to 0.
1985 *
1986 * Returns: (transfer none): a constant vector
1987 *
1988 * Since: 1.0
1989 */
1990 const graphene_vec4_t *
graphene_vec4_zero(void)1991 graphene_vec4_zero (void)
1992 {
1993 init_static_vec4 ();
1994
1995 return &(static_vec4[VEC4_ZERO]);
1996 }
1997
1998 /**
1999 * graphene_vec4_one:
2000 *
2001 * Retrieves a pointer to a #graphene_vec4_t with all its
2002 * components set to 1.
2003 *
2004 * Returns: (transfer none): a constant vector
2005 *
2006 * Since: 1.0
2007 */
2008 const graphene_vec4_t *
graphene_vec4_one(void)2009 graphene_vec4_one (void)
2010 {
2011 init_static_vec4 ();
2012
2013 return &(static_vec4[VEC4_ONE]);
2014 }
2015
2016 /**
2017 * graphene_vec4_x_axis:
2018 *
2019 * Retrieves a pointer to a #graphene_vec4_t with its
2020 * components set to (1, 0, 0, 0).
2021 *
2022 * Returns: (transfer none): a constant vector
2023 *
2024 * Since: 1.0
2025 */
2026 const graphene_vec4_t *
graphene_vec4_x_axis(void)2027 graphene_vec4_x_axis (void)
2028 {
2029 init_static_vec4 ();
2030
2031 return &(static_vec4[VEC4_X_AXIS]);
2032 }
2033
2034 /**
2035 * graphene_vec4_y_axis:
2036 *
2037 * Retrieves a pointer to a #graphene_vec4_t with its
2038 * components set to (0, 1, 0, 0).
2039 *
2040 * Returns: (transfer none): a constant vector
2041 *
2042 * Since: 1.0
2043 */
2044 const graphene_vec4_t *
graphene_vec4_y_axis(void)2045 graphene_vec4_y_axis (void)
2046 {
2047 init_static_vec4 ();
2048
2049 return &(static_vec4[VEC4_Y_AXIS]);
2050 }
2051
2052 /**
2053 * graphene_vec4_z_axis:
2054 *
2055 * Retrieves a pointer to a #graphene_vec4_t with its
2056 * components set to (0, 0, 1, 0).
2057 *
2058 * Returns: (transfer none): a constant vector
2059 *
2060 * Since: 1.0
2061 */
2062 const graphene_vec4_t *
graphene_vec4_z_axis(void)2063 graphene_vec4_z_axis (void)
2064 {
2065 init_static_vec4 ();
2066
2067 return &(static_vec4[VEC4_Z_AXIS]);
2068 }
2069
2070 /**
2071 * graphene_vec4_w_axis:
2072 *
2073 * Retrieves a pointer to a #graphene_vec4_t with its
2074 * components set to (0, 0, 0, 1).
2075 *
2076 * Returns: (transfer none): a constant vector
2077 *
2078 * Since: 1.0
2079 */
2080 const graphene_vec4_t *
graphene_vec4_w_axis(void)2081 graphene_vec4_w_axis (void)
2082 {
2083 init_static_vec4 ();
2084
2085 return &(static_vec4[VEC4_W_AXIS]);
2086 }
2087
2088 /* }}} vec4 */
2089