1/* graphene-box.c: An axis aligned bounding box
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/**
27 * SECTION:graphene-box
28 * @Title: Box
29 * @Short_Description: Axis-aligned bounding box
30 *
31 * #graphene_box_t provides a representation of an axis aligned minimum
32 * bounding box using the coordinates of its minimum and maximum vertices.
33 */
34
35#include "graphene-private.h"
36
37#include "graphene-box.h"
38
39#include "graphene-alloc-private.h"
40#include "graphene-point3d.h"
41#include "graphene-simd4f.h"
42#include "graphene-sphere.h"
43
44#include <math.h>
45#include <stdio.h>
46#include <string.h>
47
48#ifdef HAVE_PTHREAD
49#include <pthread.h>
50#include <errno.h>
51#endif
52
53/**
54 * graphene_box_alloc: (constructor)
55 *
56 * Allocates a new #graphene_box_t.
57 *
58 * The contents of the returned structure are undefined.
59 *
60 * Returns: (transfer full): the newly allocated #graphene_box_t structure.
61 * Use graphene_box_free() to free the resources allocated by this function
62 *
63 * Since: 1.2
64 */
65graphene_box_t *
66graphene_box_alloc (void)
67{
68 return graphene_aligned_alloc0 (size: sizeof (graphene_box_t), number: 1, alignment: 16);
69}
70
71/**
72 * graphene_box_free:
73 * @box: a #graphene_box_t
74 *
75 * Frees the resources allocated by graphene_box_alloc().
76 *
77 * Since: 1.2
78 */
79void
80graphene_box_free (graphene_box_t *box)
81{
82 graphene_aligned_free (mem: box);
83}
84
85/**
86 * graphene_box_init:
87 * @box: the #graphene_box_t to initialize
88 * @min: (nullable): the coordinates of the minimum vertex
89 * @max: (nullable): the coordinates of the maximum vertex
90 *
91 * Initializes the given #graphene_box_t with two vertices.
92 *
93 * Returns: (transfer none): the initialized #graphene_box_t
94 *
95 * Since: 1.2
96 */
97graphene_box_t *
98graphene_box_init (graphene_box_t *box,
99 const graphene_point3d_t *min,
100 const graphene_point3d_t *max)
101{
102 if (min != NULL)
103 graphene_point3d_to_vec3 (p: min, v: &box->min);
104 else
105 graphene_vec3_init_from_vec3 (v: &box->min, src: graphene_vec3_zero ());
106
107 if (max != NULL)
108 graphene_point3d_to_vec3 (p: max, v: &box->max);
109 else
110 graphene_vec3_init_from_vec3 (v: &box->max, src: graphene_vec3_zero ());
111
112 return box;
113}
114
115/**
116 * graphene_box_init_from_points:
117 * @box: the #graphene_box_t to initialize
118 * @n_points: the number #graphene_point3d_t in the @points array
119 * @points: (array length=n_points): an array of #graphene_point3d_t
120 *
121 * Initializes the given #graphene_box_t with the given array
122 * of vertices.
123 *
124 * If @n_points is 0, the returned box is initialized with
125 * graphene_box_empty().
126 *
127 * Returns: (transfer none): the initialized #graphene_box_t
128 *
129 * Since: 1.2
130 */
131graphene_box_t *
132graphene_box_init_from_points (graphene_box_t *box,
133 unsigned int n_points,
134 const graphene_point3d_t *points)
135{
136 graphene_box_init_from_box (box, src: graphene_box_empty ());
137
138 for (unsigned int i = 0; i < n_points; i++)
139 {
140 graphene_vec3_t v;
141
142 graphene_point3d_to_vec3 (p: &points[i], v: &v);
143 graphene_box_expand_vec3 (box, vec: &v, res: box);
144 }
145
146 return box;
147}
148
149/**
150 * graphene_box_init_from_vectors:
151 * @box: the #graphene_box_t to initialize
152 * @n_vectors: the number #graphene_point3d_t in the @vectors array
153 * @vectors: (array length=n_vectors): an array of #graphene_vec3_t
154 *
155 * Initializes the given #graphene_box_t with the given array
156 * of vertices.
157 *
158 * If @n_vectors is 0, the returned box is initialized with
159 * graphene_box_empty().
160 *
161 * Returns: (transfer none): the initialized #graphene_box_t
162 *
163 * Since: 1.2
164 */
165graphene_box_t *
166graphene_box_init_from_vectors (graphene_box_t *box,
167 unsigned int n_vectors,
168 const graphene_vec3_t *vectors)
169{
170 graphene_box_init_from_box (box, src: graphene_box_empty ());
171
172 for (unsigned int i = 0; i < n_vectors; i++)
173 graphene_box_expand_vec3 (box, vec: &vectors[i], res: box);
174
175 return box;
176}
177
178/**
179 * graphene_box_init_from_box:
180 * @box: the #graphene_box_t to initialize
181 * @src: a #graphene_box_t
182 *
183 * Initializes the given #graphene_box_t with the vertices of
184 * another #graphene_box_t.
185 *
186 * Returns: (transfer none): the initialized #graphene_box_t
187 *
188 * Since: 1.2
189 */
190graphene_box_t *
191graphene_box_init_from_box (graphene_box_t *box,
192 const graphene_box_t *src)
193{
194 box->min = src->min;
195 box->max = src->max;
196
197 return box;
198}
199
200/**
201 * graphene_box_init_from_vec3:
202 * @box: the #graphene_box_t to initialize
203 * @min: (nullable): the coordinates of the minimum vertex
204 * @max: (nullable): the coordinates of the maximum vertex
205 *
206 * Initializes the given #graphene_box_t with two vertices
207 * stored inside #graphene_vec3_t.
208 *
209 * Returns: (transfer none): the initialized #graphene_box_t
210 *
211 * Since: 1.2
212 */
213graphene_box_t *
214graphene_box_init_from_vec3 (graphene_box_t *box,
215 const graphene_vec3_t *min,
216 const graphene_vec3_t *max)
217{
218 if (min != NULL)
219 box->min = *min;
220 else
221 graphene_vec3_init_from_vec3 (v: &box->min, src: graphene_vec3_zero ());
222
223 if (max != NULL)
224 box->max = *max;
225 else
226 graphene_vec3_init_from_vec3 (v: &box->max, src: graphene_vec3_zero ());
227
228 return box;
229}
230
231static inline graphene_box_t *
232graphene_box_init_from_simd4f (graphene_box_t *box,
233 const graphene_simd4f_t min,
234 const graphene_simd4f_t max)
235{
236 box->min.value = min;
237 box->max.value = max;
238
239 return box;
240}
241
242static inline void
243graphene_box_expand_simd4f (const graphene_box_t *box,
244 const graphene_simd4f_t v,
245 graphene_box_t *res)
246{
247 res->min.value = graphene_simd4f_min (box->min.value, v);
248 res->max.value = graphene_simd4f_max (box->max.value, v);
249}
250
251/**
252 * graphene_box_expand_vec3:
253 * @box: a #graphene_box_t
254 * @vec: the coordinates of the point to include, as a #graphene_vec3_t
255 * @res: (out caller-allocates): return location for the expanded box
256 *
257 * Expands the dimensions of @box to include the coordinates of the
258 * given vector.
259 *
260 * Since: 1.2
261 */
262void
263graphene_box_expand_vec3 (const graphene_box_t *box,
264 const graphene_vec3_t *vec,
265 graphene_box_t *res)
266{
267 graphene_box_expand_simd4f (box, v: vec->value, res);
268}
269
270/**
271 * graphene_box_expand:
272 * @box: a #graphene_box_t
273 * @point: the coordinates of the point to include
274 * @res: (out caller-allocates): return location for the expanded box
275 *
276 * Expands the dimensions of @box to include the coordinates at @point.
277 *
278 * Since: 1.2
279 */
280void
281graphene_box_expand (const graphene_box_t *box,
282 const graphene_point3d_t *point,
283 graphene_box_t *res)
284{
285 graphene_simd4f_t v = graphene_simd4f_init (point->x, point->y, point->z, 0.f);
286
287 graphene_box_expand_simd4f (box, v, res);
288}
289
290/**
291 * graphene_box_expand_scalar:
292 * @box: a #graphene_box_t
293 * @scalar: a scalar value
294 * @res: (out caller-allocates): return location for the expanded box
295 *
296 * Expands the dimensions of @box by the given @scalar value.
297 *
298 * If @scalar is positive, the #graphene_box_t will grow; if @scalar is
299 * negative, the #graphene_box_t will shrink.
300 *
301 * Since: 1.2
302 */
303void
304graphene_box_expand_scalar (const graphene_box_t *box,
305 float scalar,
306 graphene_box_t *res)
307{
308 float min = scalar * -1.f;
309 float max = scalar;
310
311 res->min.value = graphene_simd4f_add (box->min.value, graphene_simd4f_splat (min));
312 res->max.value = graphene_simd4f_add (box->max.value, graphene_simd4f_splat (max));
313}
314
315/**
316 * graphene_box_union:
317 * @a: a #graphene_box_t
318 * @b: the box to union to @a
319 * @res: (out caller-allocates): return location for the result
320 *
321 * Unions the two given #graphene_box_t.
322 *
323 * Since: 1.2
324 */
325void
326graphene_box_union (const graphene_box_t *a,
327 const graphene_box_t *b,
328 graphene_box_t *res)
329{
330 res->min.value = graphene_simd4f_min (a->min.value, b->min.value);
331 res->max.value = graphene_simd4f_max (a->max.value, b->max.value);
332}
333
334/**
335 * graphene_box_intersection:
336 * @a: a #graphene_box_t
337 * @b: a #graphene_box_t
338 * @res: (out caller-allocates) (optional): return location for the result
339 *
340 * Intersects the two given #graphene_box_t.
341 *
342 * If the two boxes do not intersect, @res will contain a degenerate box
343 * initialized with graphene_box_empty().
344 *
345 * Returns: true if the two boxes intersect
346 *
347 * Since: 1.2
348 */
349bool
350graphene_box_intersection (const graphene_box_t *a,
351 const graphene_box_t *b,
352 graphene_box_t *res)
353{
354 graphene_simd4f_t min, max;
355
356 min = graphene_simd4f_max (a->min.value, b->min.value);
357 max = graphene_simd4f_min (a->max.value, b->max.value);
358
359 if (!graphene_simd4f_cmp_le (min, max))
360 {
361 if (res != NULL)
362 graphene_box_init_from_box (box: res, src: graphene_box_empty ());
363
364 return false;
365 }
366
367 if (res != NULL)
368 graphene_box_init_from_simd4f (box: res, min, max);
369
370 return true;
371}
372
373/**
374 * graphene_box_get_width:
375 * @box: a #graphene_box_t
376 *
377 * Retrieves the size of the @box on the X axis.
378 *
379 * Returns: the width of the box
380 *
381 * Since: 1.2
382 */
383float
384graphene_box_get_width (const graphene_box_t *box)
385{
386 float res = graphene_simd4f_get_x (graphene_simd4f_sub (box->max.value, box->min.value));
387
388 return fabsf (x: res);
389}
390
391/**
392 * graphene_box_get_height:
393 * @box: a #graphene_box_t
394 *
395 * Retrieves the size of the @box on the Y axis.
396 *
397 * Returns: the height of the box
398 *
399 * Since: 1.2
400 */
401float
402graphene_box_get_height (const graphene_box_t *box)
403{
404 float res = graphene_simd4f_get_y (graphene_simd4f_sub (box->max.value, box->min.value));
405
406 return fabsf (x: res);
407}
408
409/**
410 * graphene_box_get_depth:
411 * @box: a #graphene_box_t
412 *
413 * Retrieves the size of the @box on the Z axis.
414 *
415 * Returns: the depth of the box
416 *
417 * Since: 1.2
418 */
419float
420graphene_box_get_depth (const graphene_box_t *box)
421{
422 float res = graphene_simd4f_get_z (graphene_simd4f_sub (box->max.value, box->min.value));
423
424 return fabsf (x: res);
425}
426
427static inline bool
428graphene_box_is_empty (const graphene_box_t *box)
429{
430#ifdef HAVE_ISINFF
431 float vmin[3], vmax[3];
432
433 graphene_simd4f_dup_3f (box->min.value, vmin);
434 graphene_simd4f_dup_3f (box->max.value, vmax);
435
436 return (isinff (value: vmin[0]) == 1 && isinff (value: vmin[1]) == 1 && isinff (value: vmin[2]) == 1) &&
437 (isinff (value: vmax[0]) == -1 && isinff (value: vmax[1]) == -1 && isinff (value: vmax[2]) == -1);
438#else
439 graphene_simd4f_t neg_inf = graphene_simd4f_init (-INFINITY, -INFINITY, -INFINITY, 0.f);
440 graphene_simd4f_t pos_inf = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f);
441
442 /* This is only every going to be valid for boxes that we have
443 * initialized ourselves, because we use the same values; the
444 * bitwise comparison will not hold for infinities generated by
445 * other operations
446 */
447 int min_cmp = memcmp (&box->min.value, &pos_inf, sizeof (graphene_simd4f_t));
448 int max_cmp = memcmp (&box->max.value, &neg_inf, sizeof (graphene_simd4f_t));
449
450 return min_cmp == 0 && max_cmp == 0;
451#endif
452}
453
454static inline bool
455graphene_box_is_infinity (const graphene_box_t *box)
456{
457#ifdef HAVE_ISINFF
458 float vmin[3], vmax[3];
459
460 graphene_simd4f_dup_3f (box->min.value, vmin);
461 graphene_simd4f_dup_3f (box->max.value, vmax);
462
463 return (isinff (value: vmin[0]) == -1 && isinff (value: vmin[1]) == -1 && isinff (value: vmin[2]) == -1) &&
464 (isinff (value: vmax[0]) == 1 && isinff (value: vmax[1]) == 1 && isinff (value: vmax[2]) == 1);
465#else
466 graphene_simd4f_t neg_inf = graphene_simd4f_init (-INFINITY, -INFINITY, -INFINITY, 0.f);
467 graphene_simd4f_t pos_inf = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f);
468
469 /* This is only every going to be valid for boxes that we have
470 * initialized ourselves, because we use the same values; the
471 * bitwise comparison will not hold for infinities generated by
472 * other operations
473 */
474 int min_cmp = memcmp (&box->min.value, &neg_inf, sizeof (graphene_simd4f_t));
475 int max_cmp = memcmp (&box->max.value, &pos_inf, sizeof (graphene_simd4f_t));
476
477 return min_cmp == 0 && max_cmp == 0;
478#endif
479}
480
481/**
482 * graphene_box_get_size:
483 * @box: a #graphene_box_t
484 * @size: (out caller-allocates): return location for the size
485 *
486 * Retrieves the size of the box on all three axes, and stores
487 * it into the given @size vector.
488 *
489 * Since: 1.2
490 */
491void
492graphene_box_get_size (const graphene_box_t *box,
493 graphene_vec3_t *size)
494{
495 if (graphene_box_is_empty (box))
496 size->value = graphene_simd4f_init_zero ();
497 else if (graphene_box_is_infinity (box))
498 size->value = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f);
499 else
500 size->value = graphene_simd4f_sub (box->max.value, box->min.value);
501}
502
503/**
504 * graphene_box_get_center:
505 * @box: a #graphene_box_t
506 * @center: (out caller-allocates): return location for the coordinates of
507 * the center
508 *
509 * Retrieves the coordinates of the center of a #graphene_box_t.
510 *
511 * Since: 1.2
512 */
513void
514graphene_box_get_center (const graphene_box_t *box,
515 graphene_point3d_t *center)
516{
517 graphene_vec3_t res;
518
519 if (graphene_box_is_empty (box) || graphene_box_is_infinity (box))
520 {
521 graphene_point3d_init (p: center, x: 0.f, y: 0.f, z: 0.f);
522 return;
523 }
524
525 graphene_vec3_add (a: &box->min, b: &box->max, res: &res);
526 graphene_vec3_scale (v: &res, factor: 0.5f, res: &res);
527
528 graphene_point3d_init_from_vec3 (p: center, v: &res);
529}
530
531/**
532 * graphene_box_get_min:
533 * @box: a #graphene_box_t
534 * @min: (out caller-allocates): return location for the minimum point
535 *
536 * Retrieves the coordinates of the minimum point of the given
537 * #graphene_box_t.
538 *
539 * Since: 1.2
540 */
541void
542graphene_box_get_min (const graphene_box_t *box,
543 graphene_point3d_t *min)
544{
545 graphene_point3d_init_from_vec3 (p: min, v: &box->min);
546}
547
548/**
549 * graphene_box_get_max:
550 * @box: a #graphene_box_t
551 * @max: (out caller-allocates): return location for the maximum point
552 *
553 * Retrieves the coordinates of the maximum point of the given
554 * #graphene_box_t.
555 *
556 * Since: 1.2
557 */
558void
559graphene_box_get_max (const graphene_box_t *box,
560 graphene_point3d_t *max)
561{
562 graphene_point3d_init_from_vec3 (p: max, v: &box->max);
563}
564
565/**
566 * graphene_box_get_vertices:
567 * @box: a #graphene_box_t
568 * @vertices: (out) (array fixed-size=8): return location for an array
569 * of 8 #graphene_vec3_t
570 *
571 * Computes the vertices of the given #graphene_box_t.
572 *
573 * Since: 1.2
574 */
575void
576graphene_box_get_vertices (const graphene_box_t *box,
577 graphene_vec3_t vertices[])
578{
579 graphene_point3d_t min, max;
580
581 graphene_box_get_min (box, min: &min);
582 graphene_box_get_max (box, max: &max);
583
584 graphene_vec3_init (v: &vertices[0], x: min.x, y: min.y, z: min.z);
585 graphene_vec3_init (v: &vertices[1], x: min.x, y: min.y, z: max.z);
586 graphene_vec3_init (v: &vertices[2], x: min.x, y: max.y, z: min.z);
587 graphene_vec3_init (v: &vertices[3], x: min.x, y: max.y, z: max.z);
588 graphene_vec3_init (v: &vertices[4], x: max.x, y: min.y, z: min.z);
589 graphene_vec3_init (v: &vertices[5], x: max.x, y: min.y, z: max.z);
590 graphene_vec3_init (v: &vertices[6], x: max.x, y: max.y, z: min.z);
591 graphene_vec3_init (v: &vertices[7], x: max.x, y: max.y, z: max.z);
592}
593
594/**
595 * graphene_box_contains_point:
596 * @box: a #graphene_box_t
597 * @point: the coordinates to check
598 *
599 * Checks whether @box contains the given @point.
600 *
601 * Returns: `true` if the point is contained in the given box
602 *
603 * Since: 1.2
604 */
605bool
606graphene_box_contains_point (const graphene_box_t *box,
607 const graphene_point3d_t *point)
608{
609 if (graphene_box_is_empty (box))
610 return false;
611
612 if (graphene_box_is_infinity (box))
613 return true;
614
615 graphene_simd4f_t p = graphene_simd4f_init (point->x, point->y, point->z, 0.f);
616
617 if (graphene_simd4f_cmp_ge (p, box->min.value) &&
618 graphene_simd4f_cmp_le (p, box->max.value))
619 return true;
620
621 return false;
622}
623
624/**
625 * graphene_box_contains_box:
626 * @a: a #graphene_box_t
627 * @b: a #graphene_box_t
628 *
629 * Checks whether the #graphene_box_t @a contains the given
630 * #graphene_box_t @b.
631 *
632 * Returns: `true` if the box is contained in the given box
633 *
634 * Since: 1.2
635 */
636bool
637graphene_box_contains_box (const graphene_box_t *a,
638 const graphene_box_t *b)
639{
640 if (graphene_box_is_empty (box: a) || graphene_box_is_infinity (box: b))
641 return false;
642
643 if (graphene_box_is_infinity (box: a) || graphene_box_is_empty (box: b))
644 return true;
645
646 /* we cheat a bit and access the SIMD directly */
647 if (graphene_simd4f_cmp_ge (b->min.value, a->min.value) &&
648 graphene_simd4f_cmp_le (b->max.value, a->max.value))
649 return true;
650
651 return false;
652}
653
654static bool
655box_equal (const void *p1,
656 const void *p2)
657{
658 const graphene_box_t *a = p1;
659 const graphene_box_t *b = p2;
660
661 if (graphene_box_is_empty (box: a) && graphene_box_is_empty (box: b))
662 return true;
663 else if (graphene_box_is_empty (box: a) || graphene_box_is_empty (box: b))
664 return false;
665
666 if (graphene_box_is_infinity (box: a) && graphene_box_is_infinity (box: b))
667 return true;
668 else if (graphene_box_is_infinity (box: a) || graphene_box_is_infinity (box: b))
669 return false;
670
671 return graphene_vec3_equal (v1: &a->min, v2: &b->min) &&
672 graphene_vec3_equal (v1: &a->max, v2: &b->max);
673}
674
675/**
676 * graphene_box_equal:
677 * @a: a #graphene_box_t
678 * @b: a #graphene_box_t
679 *
680 * Checks whether the two given boxes are equal.
681 *
682 * Returns: `true` if the boxes are equal
683 *
684 * Since: 1.2
685 */
686bool
687graphene_box_equal (const graphene_box_t *a,
688 const graphene_box_t *b)
689{
690 return graphene_pointer_equal (p1: a, p2: b, func: box_equal);
691}
692
693/**
694 * graphene_box_get_bounding_sphere:
695 * @box: a #graphene_box_t
696 * @sphere: (out caller-allocates): return location for the bounding sphere
697 *
698 * Computes the bounding #graphene_sphere_t capable of containing the given
699 * #graphene_box_t.
700 *
701 * Since: 1.2
702 */
703void
704graphene_box_get_bounding_sphere (const graphene_box_t *box,
705 graphene_sphere_t *sphere)
706{
707 graphene_point3d_t center;
708 graphene_vec3_t size;
709
710 graphene_box_get_center (box, center: &center);
711
712 graphene_box_get_size (box, size: &size);
713 float radius = graphene_vec3_length (v: &size) * 0.5f;
714
715 graphene_sphere_init (s: sphere, center: &center, radius);
716}
717
718enum {
719 BOX_ZERO = 0,
720 BOX_ONE,
721 BOX_MINUS_ONE,
722 BOX_ONE_MINUS_ONE,
723 BOX_INFINITY,
724 BOX_EMPTY,
725
726 N_STATIC_BOX
727};
728
729static graphene_box_t static_box[N_STATIC_BOX];
730
731static void
732init_static_box_once (void)
733{
734 static_box[BOX_ZERO].min.value = graphene_simd4f_init_zero ();
735 static_box[BOX_ZERO].max.value = graphene_simd4f_init_zero ();
736
737 static_box[BOX_ONE].min.value = graphene_simd4f_init_zero ();
738 static_box[BOX_ONE].max.value = graphene_simd4f_init (1.f, 1.f, 1.f, 0.f);
739
740 static_box[BOX_MINUS_ONE].min.value = graphene_simd4f_init (-1.f, -1.f, -1.f, 0.f);
741 static_box[BOX_MINUS_ONE].max.value = graphene_simd4f_init_zero ();
742
743 static_box[BOX_ONE_MINUS_ONE].min.value = graphene_simd4f_init (-1.f, -1.f, -1.f, 0.f);
744 static_box[BOX_ONE_MINUS_ONE].max.value = graphene_simd4f_init (1.f, 1.f, 1.f, 0.f);
745
746 static_box[BOX_INFINITY].min.value = graphene_simd4f_init (-INFINITY, -INFINITY, -INFINITY, 0.f);
747 static_box[BOX_INFINITY].max.value = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f);
748
749 static_box[BOX_EMPTY].min.value = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f);
750 static_box[BOX_EMPTY].max.value = graphene_simd4f_init (-INFINITY, -INFINITY, -INFINITY, 0.f);
751}
752
753#ifdef HAVE_PTHREAD
754static pthread_once_t static_box_once = PTHREAD_ONCE_INIT;
755
756static inline void
757init_static_box (void)
758{
759 int status = pthread_once (&static_box_once, init_static_box_once);
760
761 if (status < 0)
762 {
763 int saved_errno = errno;
764
765 fprintf (stderr, "pthread_once failed: %s (errno:%d)\n",
766 strerror (saved_errno),
767 saved_errno);
768 }
769}
770
771#elif defined(HAVE_INIT_ONCE)
772static INIT_ONCE static_box_once = INIT_ONCE_STATIC_INIT;
773
774static BOOL CALLBACK
775InitBoxFunc (PINIT_ONCE InitOnce,
776 PVOID param,
777 PVOID *ctx)
778{
779 init_static_box_once ();
780 return TRUE;
781}
782
783static inline void
784init_static_box (void)
785{
786 BOOL bStatus = InitOnceExecuteOnce (&static_box_once,
787 InitBoxFunc,
788 NULL,
789 NULL);
790
791 if (!bStatus)
792 fprintf (stderr, "InitOnceExecuteOnce failed\n");
793}
794
795#else /* !HAVE_PTHREAD */
796static bool static_box_init = false;
797
798static inline void
799init_static_box (void)
800{
801 if (static_box_init)
802 return;
803
804 init_static_box_once ();
805 static_box_init = true;
806}
807
808#endif /* HAVE_PTHREAD */
809
810/**
811 * graphene_box_zero:
812 *
813 * A #graphene_box_t with both the minimum and maximum vertices set at (0, 0, 0).
814 *
815 * The returned value is owned by Graphene and should not be modified or freed.
816 *
817 * Returns: (transfer none): a #graphene_box_t
818 *
819 * Since: 1.2
820 */
821const graphene_box_t *
822graphene_box_zero (void)
823{
824 init_static_box ();
825
826 return &(static_box[BOX_ZERO]);
827}
828
829/**
830 * graphene_box_one:
831 *
832 * A #graphene_box_t with the minimum vertex set at (0, 0, 0) and the
833 * maximum vertex set at (1, 1, 1).
834 *
835 * The returned value is owned by Graphene and should not be modified or freed.
836 *
837 * Returns: (transfer none): a #graphene_box_t
838 *
839 * Since: 1.2
840 */
841const graphene_box_t *
842graphene_box_one (void)
843{
844 init_static_box ();
845
846 return &(static_box[BOX_ONE]);
847}
848
849/**
850 * graphene_box_minus_one:
851 *
852 * A #graphene_box_t with the minimum vertex set at (-1, -1, -1) and the
853 * maximum vertex set at (0, 0, 0).
854 *
855 * The returned value is owned by Graphene and should not be modified or freed.
856 *
857 * Returns: (transfer none): a #graphene_box_t
858 *
859 * Since: 1.2
860 */
861const graphene_box_t *
862graphene_box_minus_one (void)
863{
864 init_static_box ();
865
866 return &(static_box[BOX_MINUS_ONE]);
867}
868
869/**
870 * graphene_box_one_minus_one:
871 *
872 * A #graphene_box_t with the minimum vertex set at (-1, -1, -1) and the
873 * maximum vertex set at (1, 1, 1).
874 *
875 * The returned value is owned by Graphene and should not be modified or freed.
876 *
877 * Returns: (transfer none): a #graphene_box_t
878 *
879 * Since: 1.2
880 */
881const graphene_box_t *
882graphene_box_one_minus_one (void)
883{
884 init_static_box ();
885
886 return &(static_box[BOX_ONE_MINUS_ONE]);
887}
888
889/**
890 * graphene_box_infinite:
891 *
892 * A degenerate #graphene_box_t that cannot be expanded.
893 *
894 * The returned value is owned by Graphene and should not be modified or freed.
895 *
896 * Returns: (transfer none): a #graphene_box_t
897 *
898 * Since: 1.2
899 */
900const graphene_box_t *
901graphene_box_infinite (void)
902{
903 init_static_box ();
904
905 return &(static_box[BOX_INFINITY]);
906}
907
908/**
909 * graphene_box_empty:
910 *
911 * A degenerate #graphene_box_t that can only be expanded.
912 *
913 * The returned value is owned by Graphene and should not be modified or freed.
914 *
915 * Returns: (transfer none): a #graphene_box_t
916 *
917 * Since: 1.2
918 */
919const graphene_box_t *
920graphene_box_empty (void)
921{
922 init_static_box ();
923
924 return &(static_box[BOX_EMPTY]);
925}
926

source code of gtk/subprojects/graphene/src/graphene-box.c