1/* graphene-frustum.c: A 3D field of view
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-frustum
28 * @Title: Frustum
29 * @Short_Description: A 3D field of view
30 *
31 * A #graphene_frustum_t represents a volume of space delimited by planes. It
32 * is usually employed to represent the field of view of a camera, and can be
33 * used to determine whether an object falls within that view, to efficiently
34 * remove invisible objects from the render process.
35 */
36
37#include "graphene-private.h"
38
39#include "graphene-frustum.h"
40
41#include "graphene-alloc-private.h"
42#include "graphene-box.h"
43#include "graphene-matrix.h"
44#include "graphene-sphere.h"
45#include "graphene-point3d.h"
46#include "graphene-vec4.h"
47
48#define N_CLIP_PLANES 6
49
50/**
51 * graphene_frustum_alloc: (constructor)
52 *
53 * Allocates a new #graphene_frustum_t structure.
54 *
55 * The contents of the returned structure are undefined.
56 *
57 * Returns: (transfer full): the newly allocated #graphene_frustum_t
58 * structure. Use graphene_frustum_free() to free the resources
59 * allocated by this function.
60 *
61 * Since: 1.2
62 */
63graphene_frustum_t *
64graphene_frustum_alloc (void)
65{
66 return graphene_aligned_alloc0 (size: sizeof (graphene_frustum_t), number: 1, alignment: 16);
67}
68
69/**
70 * graphene_frustum_free:
71 * @f: a #graphene_frustum_t
72 *
73 * Frees the resources allocated by graphene_frustum_alloc().
74 *
75 * Since: 1.2
76 */
77void
78graphene_frustum_free (graphene_frustum_t *f)
79{
80 graphene_aligned_free (mem: f);
81}
82
83/**
84 * graphene_frustum_init:
85 * @f: the #graphene_frustum_t to initialize
86 * @p0: a clipping plane
87 * @p1: a clipping plane
88 * @p2: a clipping plane
89 * @p3: a clipping plane
90 * @p4: a clipping plane
91 * @p5: a clipping plane
92 *
93 * Initializes the given #graphene_frustum_t using the provided
94 * clipping planes.
95 *
96 * Returns: (transfer none): the initialized frustum
97 *
98 * Since: 1.2
99 */
100graphene_frustum_t *
101graphene_frustum_init (graphene_frustum_t *f,
102 const graphene_plane_t *p0,
103 const graphene_plane_t *p1,
104 const graphene_plane_t *p2,
105 const graphene_plane_t *p3,
106 const graphene_plane_t *p4,
107 const graphene_plane_t *p5)
108{
109 graphene_plane_init_from_plane (p: &f->planes[0], src: p0);
110 graphene_plane_init_from_plane (p: &f->planes[1], src: p1);
111 graphene_plane_init_from_plane (p: &f->planes[2], src: p2);
112 graphene_plane_init_from_plane (p: &f->planes[3], src: p3);
113 graphene_plane_init_from_plane (p: &f->planes[4], src: p4);
114 graphene_plane_init_from_plane (p: &f->planes[5], src: p5);
115
116 return f;
117}
118
119/**
120 * graphene_frustum_init_from_frustum:
121 * @f: the #graphene_frustum_t to initialize
122 * @src: a #graphene_frustum_t
123 *
124 * Initializes the given #graphene_frustum_t using the clipping
125 * planes of another #graphene_frustum_t.
126 *
127 * Returns: (transfer none): the initialized frustum
128 *
129 * Since: 1.2
130 */
131graphene_frustum_t *
132graphene_frustum_init_from_frustum (graphene_frustum_t *f,
133 const graphene_frustum_t *src)
134{
135 for (int i = 0; i < N_CLIP_PLANES; i++)
136 graphene_plane_init_from_plane (p: &f->planes[i], src: &src->planes[i]);
137
138 return f;
139}
140
141/**
142 * graphene_frustum_init_from_matrix:
143 * @f: a #graphene_frustum_t
144 * @matrix: a #graphene_matrix_t
145 *
146 * Initializes a #graphene_frustum_t using the given @matrix.
147 *
148 * Returns: (transfer none): the initialized frustum
149 *
150 * Since: 1.2
151 */
152graphene_frustum_t *
153graphene_frustum_init_from_matrix (graphene_frustum_t *f,
154 const graphene_matrix_t *matrix)
155{
156 graphene_vec4_t r1, r2, r3, r4, t;
157 graphene_plane_t p;
158 graphene_matrix_t m;
159
160 graphene_matrix_transpose (m: matrix, res: &m);
161
162 graphene_matrix_get_row (m: &m, index_: 0, res: &r1);
163 graphene_matrix_get_row (m: &m, index_: 1, res: &r2);
164 graphene_matrix_get_row (m: &m, index_: 2, res: &r3);
165 graphene_matrix_get_row (m: &m, index_: 3, res: &r4);
166
167 graphene_vec4_subtract (a: &r4, b: &r1, res: &t);
168 graphene_plane_init_from_vec4 (p: &p, src: &t);
169 graphene_plane_normalize (p: &p, res: &f->planes[0]);
170
171 graphene_vec4_add (a: &r4, b: &r1, res: &t);
172 graphene_plane_init_from_vec4 (p: &p, src: &t);
173 graphene_plane_normalize (p: &p, res: &f->planes[1]);
174
175 graphene_vec4_subtract (a: &r4, b: &r2, res: &t);
176 graphene_plane_init_from_vec4 (p: &p, src: &t);
177 graphene_plane_normalize (p: &p, res: &f->planes[2]);
178
179 graphene_vec4_add (a: &r4, b: &r2, res: &t);
180 graphene_plane_init_from_vec4 (p: &p, src: &t);
181 graphene_plane_normalize (p: &p, res: &f->planes[3]);
182
183 graphene_vec4_subtract (a: &r4, b: &r3, res: &t);
184 graphene_plane_init_from_vec4 (p: &p, src: &t);
185 graphene_plane_normalize (p: &p, res: &f->planes[4]);
186
187 graphene_vec4_add (a: &r4, b: &r3, res: &t);
188 graphene_plane_init_from_vec4 (p: &p, src: &t);
189 graphene_plane_normalize (p: &p, res: &f->planes[5]);
190
191 return f;
192}
193
194/**
195 * graphene_frustum_get_planes:
196 * @f: a #graphene_frustum_t
197 * @planes: (out) (array fixed-size=6): return location for an array
198 * of 6 #graphene_plane_t
199 *
200 * Retrieves the planes that define the given #graphene_frustum_t.
201 *
202 * Since: 1.2
203 */
204void
205graphene_frustum_get_planes (const graphene_frustum_t *f,
206 graphene_plane_t planes[])
207{
208 for (int i = 0; i < N_CLIP_PLANES; i++)
209 graphene_plane_init_from_plane (p: &planes[i], src: &f->planes[i]);
210}
211
212/**
213 * graphene_frustum_contains_point:
214 * @f: a #graphene_frustum_t
215 * @point: a #graphene_point3d_t
216 *
217 * Checks whether a point is inside the volume defined by the given
218 * #graphene_frustum_t.
219 *
220 * Returns: `true` if the point is inside the frustum
221 *
222 * Since: 1.2
223 */
224bool
225graphene_frustum_contains_point (const graphene_frustum_t *f,
226 const graphene_point3d_t *point)
227{
228 if (point == NULL)
229 return false;
230
231 for (int i = 0; i < N_CLIP_PLANES; i++)
232 {
233 const graphene_plane_t *p = &f->planes[i];
234
235 if (graphene_plane_distance (p, point) < 0)
236 return false;
237 }
238
239 return true;
240}
241
242/**
243 * graphene_frustum_intersects_sphere:
244 * @f: a #graphene_frustum_t
245 * @sphere: a #graphene_sphere_t
246 *
247 * Checks whether the given @sphere intersects a plane of
248 * a #graphene_frustum_t.
249 *
250 * Returns: `true` if the sphere intersects the frustum
251 *
252 * Since: 1.2
253 */
254bool
255graphene_frustum_intersects_sphere (const graphene_frustum_t *f,
256 const graphene_sphere_t *sphere)
257{
258 graphene_point3d_t center;
259
260 graphene_point3d_init_from_vec3 (p: &center, v: &sphere->center);
261
262 for (int i = 0; i < N_CLIP_PLANES; i++)
263 {
264 float distance = graphene_plane_distance (p: &f->planes[i], point: &center);
265
266 if (distance < -sphere->radius)
267 return false;
268 }
269
270 return true;
271}
272
273/**
274 * graphene_frustum_intersects_box:
275 * @f: a #graphene_frustum_t
276 * @box: a #graphene_box_t
277 *
278 * Checks whether the given @box intersects a plane of
279 * a #graphene_frustum_t.
280 *
281 * Returns: `true` if the box intersects the frustum
282 *
283 * Since: 1.2
284 */
285bool
286graphene_frustum_intersects_box (const graphene_frustum_t *f,
287 const graphene_box_t *box)
288{
289 graphene_point3d_t min, max, normal;
290 graphene_point3d_t p0, p1;
291 const graphene_plane_t *plane;
292 float d0, d1;
293
294 graphene_box_get_min (box, min: &min);
295 graphene_box_get_max (box, max: &max);
296
297 for (int i = 0; i < N_CLIP_PLANES; i++)
298 {
299 plane = &f->planes[i];
300
301 graphene_point3d_init_from_vec3 (p: &normal, v: &(plane->normal));
302
303 p0.x = normal.x > 0 ? min.x : max.x;
304 p1.x = normal.x > 0 ? max.x : min.x;
305
306 p0.y = normal.y > 0 ? min.y : max.y;
307 p1.y = normal.y > 0 ? max.y : min.y;
308
309 p0.z = normal.z > 0 ? min.z : max.z;
310 p1.z = normal.z > 0 ? max.z : min.z;
311
312 d0 = graphene_plane_distance (p: plane, point: &p0);
313 d1 = graphene_plane_distance (p: plane, point: &p1);
314
315 if (d0 < 0 && d1 < 0)
316 return false;
317 }
318
319 return true;
320}
321
322static bool
323frustum_equal (const void *p1,
324 const void *p2)
325{
326 const graphene_frustum_t *a = p1;
327 const graphene_frustum_t *b = p2;
328
329 return graphene_plane_equal (a: &a->planes[0], b: &b->planes[0]) &&
330 graphene_plane_equal (a: &a->planes[1], b: &b->planes[1]) &&
331 graphene_plane_equal (a: &a->planes[2], b: &b->planes[2]) &&
332 graphene_plane_equal (a: &a->planes[3], b: &b->planes[3]) &&
333 graphene_plane_equal (a: &a->planes[4], b: &b->planes[4]) &&
334 graphene_plane_equal (a: &a->planes[5], b: &b->planes[5]);
335}
336
337/**
338 * graphene_frustum_equal:
339 * @a: a #graphene_frustum_t
340 * @b: a #graphene_frustum_t
341 *
342 * Checks whether the two given #graphene_frustum_t are equal.
343 *
344 * Returns: `true` if the given frustums are equal
345 *
346 * Since: 1.6
347 */
348bool
349graphene_frustum_equal (const graphene_frustum_t *a,
350 const graphene_frustum_t *b)
351{
352 return graphene_pointer_equal (p1: a, p2: b, func: frustum_equal);
353}
354

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