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