2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 void aabb_construct_for_vec3( aabb_t *aabb, const vec3_t min, const vec3_t max ){
27 VectorMid( min, max, aabb->origin );
28 VectorSubtract( max, aabb->origin, aabb->extents );
31 void aabb_update_radius( aabb_t *aabb ){
32 aabb->radius = VectorLength( aabb->extents );
35 void aabb_clear( aabb_t *aabb ){
36 aabb->origin[0] = aabb->origin[1] = aabb->origin[2] = 0;
37 aabb->extents[0] = aabb->extents[1] = aabb->extents[2] = -FLT_MAX;
40 void aabb_extend_by_point( aabb_t *aabb, const vec3_t point ){
42 vec_t min, max, displacement;
43 for ( i = 0; i < 3; i++ )
45 displacement = point[i] - aabb->origin[i];
46 if ( fabs( displacement ) > aabb->extents[i] ) {
47 if ( aabb->extents[i] < 0 ) { // degenerate
50 else if ( displacement > 0 ) {
51 min = aabb->origin[i] - aabb->extents[i];
52 max = aabb->origin[i] + displacement;
56 max = aabb->origin[i] + aabb->extents[i];
57 min = aabb->origin[i] + displacement;
59 aabb->origin[i] = ( min + max ) * 0.5f;
60 aabb->extents[i] = max - aabb->origin[i];
65 void aabb_extend_by_aabb( aabb_t *aabb, const aabb_t *aabb_src ){
67 vec_t min, max, displacement, difference;
68 for ( i = 0; i < 3; i++ )
70 displacement = aabb_src->origin[i] - aabb->origin[i];
71 difference = aabb_src->extents[i] - aabb->extents[i];
72 if ( aabb->extents[i] < 0
73 || difference >= fabs( displacement ) ) {
75 aabb->extents[i] = aabb_src->extents[i];
76 aabb->origin[i] = aabb_src->origin[i];
78 else if ( aabb_src->extents[i] < 0
79 || -difference >= fabs( displacement ) ) {
86 if ( displacement > 0 ) {
87 min = aabb->origin[i] - aabb->extents[i];
88 max = aabb_src->origin[i] + aabb_src->extents[i];
92 min = aabb_src->origin[i] - aabb_src->extents[i];
93 max = aabb->origin[i] + aabb->extents[i];
95 aabb->origin[i] = ( min + max ) * 0.5f;
96 aabb->extents[i] = max - aabb->origin[i];
101 void aabb_extend_by_vec3( aabb_t *aabb, vec3_t extension ){
102 VectorAdd( aabb->extents, extension, aabb->extents );
105 int aabb_intersect_point( const aabb_t *aabb, const vec3_t point ){
107 for ( i = 0; i < 3; i++ )
108 if ( fabs( point[i] - aabb->origin[i] ) >= aabb->extents[i] ) {
114 int aabb_intersect_aabb( const aabb_t *aabb, const aabb_t *aabb_src ){
116 for ( i = 0; i < 3; i++ )
117 if ( fabs( aabb_src->origin[i] - aabb->origin[i] ) > ( fabs( aabb->extents[i] ) + fabs( aabb_src->extents[i] ) ) ) {
123 int aabb_intersect_plane( const aabb_t *aabb, const float *plane ){
124 float fDist, fIntersect;
126 // calc distance of origin from plane
127 fDist = DotProduct( plane, aabb->origin ) + plane[3];
129 // trivial accept/reject using bounding sphere
130 if ( fabs( fDist ) > aabb->radius ) {
132 return 2; // totally inside
135 return 0; // totally outside
139 // calc extents distance relative to plane normal
140 fIntersect = (vec_t)( fabs( plane[0] * aabb->extents[0] ) + fabs( plane[1] * aabb->extents[1] ) + fabs( plane[2] * aabb->extents[2] ) );
141 // accept if origin is less than or equal to this distance
142 if ( fabs( fDist ) < fIntersect ) {
143 return 1; // partially inside
145 else if ( fDist < 0 ) {
146 return 2; // totally inside
148 return 0; // totally outside
152 Fast Ray-Box Intersection
154 from "Graphics Gems", Academic Press, 1990
162 int aabb_intersect_ray( const aabb_t *aabb, const ray_t *ray, vec_t *dist ){
164 char quadrant[NUMDIM];
168 double candidatePlane[NUMDIM];
169 vec3_t coord, segment;
171 const float *origin = ray->origin;
172 const float *direction = ray->direction;
174 /* Find candidate planes; this loop can be avoided if
175 rays cast all from the eye(assume perpsective view) */
176 for ( i = 0; i < NUMDIM; i++ )
178 if ( origin[i] < ( aabb->origin[i] - aabb->extents[i] ) ) {
180 candidatePlane[i] = ( aabb->origin[i] - aabb->extents[i] );
183 else if ( origin[i] > ( aabb->origin[i] + aabb->extents[i] ) ) {
185 candidatePlane[i] = ( aabb->origin[i] + aabb->extents[i] );
190 quadrant[i] = MIDDLE;
194 /* Ray origin inside bounding box */
201 /* Calculate T distances to candidate planes */
202 for ( i = 0; i < NUMDIM; i++ )
204 if ( quadrant[i] != MIDDLE && direction[i] != 0. ) {
205 maxT[i] = ( candidatePlane[i] - origin[i] ) / direction[i];
212 /* Get largest of the maxT's for final choice of intersection */
214 for ( i = 1; i < NUMDIM; i++ )
215 if ( maxT[whichPlane] < maxT[i] ) {
219 /* Check final candidate actually inside box */
220 if ( maxT[whichPlane] < 0. ) {
223 for ( i = 0; i < NUMDIM; i++ )
225 if ( whichPlane != i ) {
226 coord[i] = (vec_t)( origin[i] + maxT[whichPlane] * direction[i] );
227 if ( fabs( coord[i] - aabb->origin[i] ) > aabb->extents[i] ) {
233 coord[i] = (vec_t)candidatePlane[i];
237 VectorSubtract( coord, origin, segment );
238 *dist = DotProduct( segment, direction );
240 return 1; /* ray hits box */
243 int aabb_test_ray( const aabb_t* aabb, const ray_t* ray ){
244 vec3_t displacement, ray_absolute;
247 displacement[0] = ray->origin[0] - aabb->origin[0];
248 if ( fabs( displacement[0] ) > aabb->extents[0] && displacement[0] * ray->direction[0] >= 0.0f ) {
252 displacement[1] = ray->origin[1] - aabb->origin[1];
253 if ( fabs( displacement[1] ) > aabb->extents[1] && displacement[1] * ray->direction[1] >= 0.0f ) {
257 displacement[2] = ray->origin[2] - aabb->origin[2];
258 if ( fabs( displacement[2] ) > aabb->extents[2] && displacement[2] * ray->direction[2] >= 0.0f ) {
262 ray_absolute[0] = (float)fabs( ray->direction[0] );
263 ray_absolute[1] = (float)fabs( ray->direction[1] );
264 ray_absolute[2] = (float)fabs( ray->direction[2] );
266 f = ray->direction[1] * displacement[2] - ray->direction[2] * displacement[1];
267 if ( (float)fabs( f ) > aabb->extents[1] * ray_absolute[2] + aabb->extents[2] * ray_absolute[1] ) {
271 f = ray->direction[2] * displacement[0] - ray->direction[0] * displacement[2];
272 if ( (float)fabs( f ) > aabb->extents[0] * ray_absolute[2] + aabb->extents[2] * ray_absolute[0] ) {
276 f = ray->direction[0] * displacement[1] - ray->direction[1] * displacement[0];
277 if ( (float)fabs( f ) > aabb->extents[0] * ray_absolute[1] + aabb->extents[1] * ray_absolute[0] ) {
284 void aabb_for_bbox( aabb_t *aabb, const bbox_t *bbox ){
288 VectorCopy( bbox->aabb.origin, aabb->origin );
290 // calculate the AABB extents in local coord space from the OBB extents and axes
291 VectorScale( bbox->axes[0], bbox->aabb.extents[0], temp[0] );
292 VectorScale( bbox->axes[1], bbox->aabb.extents[1], temp[1] );
293 VectorScale( bbox->axes[2], bbox->aabb.extents[2], temp[2] );
294 for ( i = 0; i < 3; i++ ) aabb->extents[i] = (vec_t)( fabs( temp[0][i] ) + fabs( temp[1][i] ) + fabs( temp[2][i] ) );
297 void aabb_for_area( aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis ){
299 aabb->extents[axis] = FLT_MAX;
300 aabb_extend_by_point( aabb, area_tl );
301 aabb_extend_by_point( aabb, area_br );
304 void aabb_for_transformed_aabb( aabb_t* dst, const aabb_t* src, const m4x4_t transform ){
305 VectorCopy( src->origin, dst->origin );
306 m4x4_transform_point( transform, dst->origin );
308 dst->extents[0] = (vec_t)( fabs( transform[0] * src->extents[0] )
309 + fabs( transform[4] * src->extents[1] )
310 + fabs( transform[8] * src->extents[2] ) );
311 dst->extents[1] = (vec_t)( fabs( transform[1] * src->extents[0] )
312 + fabs( transform[5] * src->extents[1] )
313 + fabs( transform[9] * src->extents[2] ) );
314 dst->extents[2] = (vec_t)( fabs( transform[2] * src->extents[0] )
315 + fabs( transform[6] * src->extents[1] )
316 + fabs( transform[10] * src->extents[2] ) );
320 void bbox_for_oriented_aabb( bbox_t *bbox, const aabb_t *aabb, const m4x4_t matrix, const vec3_t euler, const vec3_t scale ){
322 double pi_180 = Q_PI / 180;
323 double A, B, C, D, E, F, AD, BD;
325 VectorCopy( aabb->origin, bbox->aabb.origin );
327 m4x4_transform_point( matrix, bbox->aabb.origin );
329 bbox->aabb.extents[0] = aabb->extents[0] * scale[0];
330 bbox->aabb.extents[1] = aabb->extents[1] * scale[1];
331 bbox->aabb.extents[2] = aabb->extents[2] * scale[2];
333 rad[0] = euler[0] * pi_180;
334 rad[1] = euler[1] * pi_180;
335 rad[2] = euler[2] * pi_180;
347 bbox->axes[0][0] = (vec_t)( C * E );
348 bbox->axes[0][1] = (vec_t)( -BD * E + A * F );
349 bbox->axes[0][2] = (vec_t)( AD * E + B * F );
350 bbox->axes[1][0] = (vec_t)( -C * F );
351 bbox->axes[1][1] = (vec_t)( BD * F + A * E );
352 bbox->axes[1][2] = (vec_t)( -AD * F + B * E );
353 bbox->axes[2][0] = (vec_t)D;
354 bbox->axes[2][1] = (vec_t)( -B * C );
355 bbox->axes[2][2] = (vec_t)( A * C );
357 aabb_update_radius( &bbox->aabb );
360 int bbox_intersect_plane( const bbox_t *bbox, const vec_t* plane ){
361 vec_t fDist, fIntersect;
363 // calc distance of origin from plane
364 fDist = DotProduct( plane, bbox->aabb.origin ) + plane[3];
366 // trivial accept/reject using bounding sphere
367 if ( fabs( fDist ) > bbox->aabb.radius ) {
369 return 2; // totally inside
372 return 0; // totally outside
376 // calc extents distance relative to plane normal
377 fIntersect = (vec_t)( fabs( bbox->aabb.extents[0] * DotProduct( plane, bbox->axes[0] ) )
378 + fabs( bbox->aabb.extents[1] * DotProduct( plane, bbox->axes[1] ) )
379 + fabs( bbox->aabb.extents[2] * DotProduct( plane, bbox->axes[2] ) ) );
380 // accept if origin is less than this distance
381 if ( fabs( fDist ) < fIntersect ) {
382 return 1; // partially inside
384 else if ( fDist < 0 ) {
385 return 2; // totally inside
387 return 0; // totally outside