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 * |
71 | graphene_vec2_alloc (void) |
72 | { |
73 | return graphene_aligned_alloc (size: sizeof (graphene_vec2_t), number: 1, alignment: 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 |
85 | graphene_vec2_free (graphene_vec2_t *v) |
86 | { |
87 | graphene_aligned_free (mem: 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 * |
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 * |
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 * |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
327 | graphene_vec2_normalize (const graphene_vec2_t *v, |
328 | graphene_vec2_t *res) |
329 | { |
330 | if (fabsf (x: graphene_vec2_length (v)) > FLT_EPSILON) |
331 | res->value = graphene_simd4f_normalize2 (v: 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 |
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 |
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 |
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 |
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 |
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 |
433 | graphene_vec2_equal (const graphene_vec2_t *v1, |
434 | const graphene_vec2_t *v2) |
435 | { |
436 | return graphene_pointer_equal (p1: v1, p2: v2, func: 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 |
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 |
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 (a: v1->value, b: v2->value, f: (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 |
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 |
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 |
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 |
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 |
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 * |
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 * |
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 * |
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 * |
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 * |
647 | graphene_vec3_alloc (void) |
648 | { |
649 | return graphene_aligned_alloc (size: sizeof (graphene_vec3_t), number: 1, alignment: 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 |
661 | graphene_vec3_free (graphene_vec3_t *v) |
662 | { |
663 | graphene_aligned_free (mem: 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 * |
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 * |
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 * |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
937 | graphene_vec3_normalize (const graphene_vec3_t *v, |
938 | graphene_vec3_t *res) |
939 | { |
940 | if (fabsf (x: graphene_vec3_length (v)) > FLT_EPSILON) |
941 | res->value = graphene_simd4f_normalize3 (v: 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
1132 | graphene_vec3_equal (const graphene_vec3_t *v1, |
1133 | const graphene_vec3_t *v2) |
1134 | { |
1135 | return graphene_pointer_equal (p1: v1, p2: v2, func: 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 |
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 |
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 (a: v1->value, b: v2->value, f: (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 |
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 |
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 |
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 |
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 |
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 * |
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 * |
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 * |
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 * |
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 * |
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 * |
1369 | graphene_vec4_alloc (void) |
1370 | { |
1371 | return graphene_aligned_alloc (size: sizeof (graphene_vec4_t), number: 1, alignment: 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 |
1383 | graphene_vec4_free (graphene_vec4_t *v) |
1384 | { |
1385 | graphene_aligned_free (mem: 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 * |
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 * |
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 * |
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 * |
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 * |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
1709 | graphene_vec4_normalize (const graphene_vec4_t *v, |
1710 | graphene_vec4_t *res) |
1711 | { |
1712 | if (fabsf (x: graphene_vec4_length (v)) > FLT_EPSILON) |
1713 | res->value = graphene_simd4f_normalize4 (v: 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
1849 | graphene_vec4_equal (const graphene_vec4_t *v1, |
1850 | const graphene_vec4_t *v2) |
1851 | { |
1852 | return graphene_pointer_equal (p1: v1, p2: v2, func: 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 |
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 |
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 (a: v1->value, b: v2->value, f: (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 |
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 |
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 |
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 |
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 |
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 * |
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 * |
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 * |
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 * |
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 * |
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 * |
2081 | graphene_vec4_w_axis (void) |
2082 | { |
2083 | init_static_vec4 (); |
2084 | |
2085 | return &(static_vec4[VEC4_W_AXIS]); |
2086 | } |
2087 | |
2088 | /* }}} vec4 */ |
2089 | |