DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Bounds.cpp (10806B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../precompiled.h"
     31 
     32 idBounds bounds_zero( vec3_zero, vec3_zero );
     33 idBounds bounds_zeroOneCube( idVec3( 0.0f ), idVec3( 1.0f ) );
     34 idBounds bounds_unitCube( idVec3( -1.0f ), idVec3( 1.0f ) );
     35 
     36 /*
     37 ============
     38 idBounds::GetRadius
     39 ============
     40 */
     41 float idBounds::GetRadius() const {
     42 	int		i;
     43 	float	total, b0, b1;
     44 
     45 	total = 0.0f;
     46 	for ( i = 0; i < 3; i++ ) {
     47 		b0 = (float)idMath::Fabs( b[0][i] );
     48 		b1 = (float)idMath::Fabs( b[1][i] );
     49 		if ( b0 > b1 ) {
     50 			total += b0 * b0;
     51 		} else {
     52 			total += b1 * b1;
     53 		}
     54 	}
     55 	return idMath::Sqrt( total );
     56 }
     57 
     58 /*
     59 ============
     60 idBounds::GetRadius
     61 ============
     62 */
     63 float idBounds::GetRadius( const idVec3 &center ) const {
     64 	int		i;
     65 	float	total, b0, b1;
     66 
     67 	total = 0.0f;
     68 	for ( i = 0; i < 3; i++ ) {
     69 		b0 = (float)idMath::Fabs( center[i] - b[0][i] );
     70 		b1 = (float)idMath::Fabs( b[1][i] - center[i] );
     71 		if ( b0 > b1 ) {
     72 			total += b0 * b0;
     73 		} else {
     74 			total += b1 * b1;
     75 		}
     76 	}
     77 	return idMath::Sqrt( total );
     78 }
     79 
     80 /*
     81 ================
     82 idBounds::PlaneDistance
     83 ================
     84 */
     85 float idBounds::PlaneDistance( const idPlane &plane ) const {
     86 	idVec3 center;
     87 	float d1, d2;
     88 
     89 	center = ( b[0] + b[1] ) * 0.5f;
     90 
     91 	d1 = plane.Distance( center );
     92 	d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) +
     93 			idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) +
     94 				idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] );
     95 
     96 	if ( d1 - d2 > 0.0f ) {
     97 		return d1 - d2;
     98 	}
     99 	if ( d1 + d2 < 0.0f ) {
    100 		return d1 + d2;
    101 	}
    102 	return 0.0f;
    103 }
    104 
    105 /*
    106 ================
    107 idBounds::PlaneSide
    108 ================
    109 */
    110 int idBounds::PlaneSide( const idPlane &plane, const float epsilon ) const {
    111 	idVec3 center;
    112 	float d1, d2;
    113 
    114 	center = ( b[0] + b[1] ) * 0.5f;
    115 
    116 	d1 = plane.Distance( center );
    117 	d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) +
    118 			idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) +
    119 				idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] );
    120 
    121 	if ( d1 - d2 > epsilon ) {
    122 		return PLANESIDE_FRONT;
    123 	}
    124 	if ( d1 + d2 < -epsilon ) {
    125 		return PLANESIDE_BACK;
    126 	}
    127 	return PLANESIDE_CROSS;
    128 }
    129 
    130 /*
    131 ============
    132 idBounds::LineIntersection
    133 
    134   Returns true if the line intersects the bounds between the start and end point.
    135 ============
    136 */
    137 bool idBounds::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
    138 	const idVec3 center = ( b[0] + b[1] ) * 0.5f;
    139 	const idVec3 extents = b[1] - center;
    140 	const idVec3 lineDir = 0.5f * ( end - start );
    141 	const idVec3 lineCenter = start + lineDir;
    142 	const idVec3 dir = lineCenter - center;
    143 
    144 	const float ld0 = idMath::Fabs( lineDir[0] );
    145 	if ( idMath::Fabs( dir[0] ) > extents[0] + ld0 ) {
    146 		return false;
    147 	}
    148 
    149 	const float ld1 = idMath::Fabs( lineDir[1] );
    150 	if ( idMath::Fabs( dir[1] ) > extents[1] + ld1 ) {
    151 		return false;
    152 	}
    153 
    154 	const float ld2 = idMath::Fabs( lineDir[2] );
    155 	if ( idMath::Fabs( dir[2] ) > extents[2] + ld2 ) {
    156 		return false;
    157 	}
    158 
    159 	const idVec3 cross = lineDir.Cross( dir );
    160 
    161 	if ( idMath::Fabs( cross[0] ) > extents[1] * ld2 + extents[2] * ld1 ) {
    162 		return false;
    163 	}
    164 
    165 	if ( idMath::Fabs( cross[1] ) > extents[0] * ld2 + extents[2] * ld0 ) {
    166 		return false;
    167 	}
    168 
    169 	if ( idMath::Fabs( cross[2] ) > extents[0] * ld1 + extents[1] * ld0 ) {
    170 		return false;
    171 	}
    172 
    173 	return true;
    174 }
    175 
    176 /*
    177 ============
    178 idBounds::RayIntersection
    179 
    180   Returns true if the ray intersects the bounds.
    181   The ray can intersect the bounds in both directions from the start point.
    182   If start is inside the bounds it is considered an intersection with scale = 0
    183 ============
    184 */
    185 bool idBounds::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const {
    186 	int i, ax0, ax1, ax2, side, inside;
    187 	float f;
    188 	idVec3 hit;
    189 
    190 	ax0 = -1;
    191 	inside = 0;
    192 	for ( i = 0; i < 3; i++ ) {
    193 		if ( start[i] < b[0][i] ) {
    194 			side = 0;
    195 		}
    196 		else if ( start[i] > b[1][i] ) {
    197 			side = 1;
    198 		}
    199 		else {
    200 			inside++;
    201 			continue;
    202 		}
    203 		if ( dir[i] == 0.0f ) {
    204 			continue;
    205 		}
    206 		f = ( start[i] - b[side][i] );
    207 		if ( ax0 < 0 || idMath::Fabs( f ) > idMath::Fabs( scale * dir[i] ) ) {
    208 			scale = - ( f / dir[i] );
    209 			ax0 = i;
    210 		}
    211 	}
    212 
    213 	if ( ax0 < 0 ) {
    214 		scale = 0.0f;
    215 		// return true if the start point is inside the bounds
    216 		return ( inside == 3 );
    217 	}
    218 
    219 	ax1 = (ax0+1)%3;
    220 	ax2 = (ax0+2)%3;
    221 	hit[ax1] = start[ax1] + scale * dir[ax1];
    222 	hit[ax2] = start[ax2] + scale * dir[ax2];
    223 
    224 	return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&
    225 				hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );
    226 }
    227 
    228 /*
    229 ============
    230 idBounds::FromTransformedBounds
    231 ============
    232 */
    233 void idBounds::FromTransformedBounds( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis ) {
    234 	int i;
    235 	idVec3 center, extents, rotatedExtents;
    236 
    237 	center = (bounds[0] + bounds[1]) * 0.5f;
    238 	extents = bounds[1] - center;
    239 
    240 	for ( i = 0; i < 3; i++ ) {
    241 		rotatedExtents[i] = idMath::Fabs( extents[0] * axis[0][i] ) +
    242 							idMath::Fabs( extents[1] * axis[1][i] ) +
    243 							idMath::Fabs( extents[2] * axis[2][i] );
    244 	}
    245 
    246 	center = origin + center * axis;
    247 	b[0] = center - rotatedExtents;
    248 	b[1] = center + rotatedExtents;
    249 }
    250 
    251 /*
    252 ============
    253 idBounds::FromPoints
    254 
    255   Most tight bounds for a point set.
    256 ============
    257 */
    258 void idBounds::FromPoints( const idVec3 *points, const int numPoints ) {
    259 	SIMDProcessor->MinMax( b[0], b[1], points, numPoints );
    260 }
    261 
    262 /*
    263 ============
    264 idBounds::FromPointTranslation
    265 
    266   Most tight bounds for the translational movement of the given point.
    267 ============
    268 */
    269 void idBounds::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
    270 	int i;
    271 
    272 	for ( i = 0; i < 3; i++ ) {
    273 		if ( translation[i] < 0.0f ) {
    274 			b[0][i] = point[i] + translation[i];
    275 			b[1][i] = point[i];
    276 		}
    277 		else {
    278 			b[0][i] = point[i];
    279 			b[1][i] = point[i] + translation[i];
    280 		}
    281 	}
    282 }
    283 
    284 /*
    285 ============
    286 idBounds::FromBoundsTranslation
    287 
    288   Most tight bounds for the translational movement of the given bounds.
    289 ============
    290 */
    291 void idBounds::FromBoundsTranslation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation ) {
    292 	int i;
    293 
    294 	if ( axis.IsRotated() ) {
    295 		FromTransformedBounds( bounds, origin, axis );
    296 	}
    297 	else {
    298 		b[0] = bounds[0] + origin;
    299 		b[1] = bounds[1] + origin;
    300 	}
    301 	for ( i = 0; i < 3; i++ ) {
    302 		if ( translation[i] < 0.0f ) {
    303 			b[0][i] += translation[i];
    304 		}
    305 		else {
    306 			b[1][i] += translation[i];
    307 		}
    308 	}
    309 }
    310 
    311 /*
    312 ================
    313 BoundsForPointRotation
    314 
    315   only for rotations < 180 degrees
    316 ================
    317 */
    318 idBounds BoundsForPointRotation( const idVec3 &start, const idRotation &rotation ) {
    319 	int i;
    320 	float radiusSqr;
    321 	idVec3 v1, v2;
    322 	idVec3 origin, axis, end;
    323 	idBounds bounds;
    324 
    325 	end = start * rotation;
    326 	axis = rotation.GetVec();
    327 	origin = rotation.GetOrigin() + axis * ( axis * ( start - rotation.GetOrigin() ) );
    328 	radiusSqr = ( start - origin ).LengthSqr();
    329 	v1 = ( start - origin ).Cross( axis );
    330 	v2 = ( end - origin ).Cross( axis );
    331 
    332 	for ( i = 0; i < 3; i++ ) {
    333 		// if the derivative changes sign along this axis during the rotation from start to end
    334 		if ( ( v1[i] > 0.0f && v2[i] < 0.0f ) || ( v1[i] < 0.0f && v2[i] > 0.0f ) ) {
    335 			if ( ( 0.5f * (start[i] + end[i]) - origin[i] ) > 0.0f ) {
    336 				bounds[0][i] = Min( start[i], end[i] );
    337 				bounds[1][i] = origin[i] + idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
    338 			}
    339 			else {
    340 				bounds[0][i] = origin[i] - idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
    341 				bounds[1][i] = Max( start[i], end[i] );
    342 			}
    343 		}
    344 		else if ( start[i] > end[i] ) {
    345 			bounds[0][i] = end[i];
    346 			bounds[1][i] = start[i];
    347 		}
    348 		else {
    349 			bounds[0][i] = start[i];
    350 			bounds[1][i] = end[i];
    351 		}
    352 	}
    353 
    354 	return bounds;
    355 }
    356 
    357 /*
    358 ============
    359 idBounds::FromPointRotation
    360 
    361   Most tight bounds for the rotational movement of the given point.
    362 ============
    363 */
    364 void idBounds::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
    365 	float radius;
    366 
    367 	if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
    368 		(*this) = BoundsForPointRotation( point, rotation );
    369 	}
    370 	else {
    371 
    372 		radius = ( point - rotation.GetOrigin() ).Length();
    373 
    374 		// FIXME: these bounds are usually way larger
    375 		b[0].Set( -radius, -radius, -radius );
    376 		b[1].Set( radius, radius, radius );
    377 	}
    378 }
    379 
    380 /*
    381 ============
    382 idBounds::FromBoundsRotation
    383 
    384   Most tight bounds for the rotational movement of the given bounds.
    385 ============
    386 */
    387 void idBounds::FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation ) {
    388 	int i;
    389 	float radius;
    390 	idVec3 point;
    391 	idBounds rBounds;
    392 
    393 	if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
    394 
    395 		(*this) = BoundsForPointRotation( bounds[0] * axis + origin, rotation );
    396 		for ( i = 1; i < 8; i++ ) {
    397 			point[0] = bounds[(i^(i>>1))&1][0];
    398 			point[1] = bounds[(i>>1)&1][1];
    399 			point[2] = bounds[(i>>2)&1][2];
    400 			(*this) += BoundsForPointRotation( point * axis + origin, rotation );
    401 		}
    402 	}
    403 	else {
    404 
    405 		point = (bounds[1] - bounds[0]) * 0.5f;
    406 		radius = (bounds[1] - point).Length() + (point - rotation.GetOrigin()).Length();
    407 
    408 		// FIXME: these bounds are usually way larger
    409 		b[0].Set( -radius, -radius, -radius );
    410 		b[1].Set( radius, radius, radius );
    411 	}
    412 }
    413 
    414 /*
    415 ============
    416 idBounds::ToPoints
    417 ============
    418 */
    419 void idBounds::ToPoints( idVec3 points[8] ) const {
    420 	for ( int i = 0; i < 8; i++ ) {
    421 		points[i][0] = b[(i^(i>>1))&1][0];
    422 		points[i][1] = b[(i>>1)&1][1];
    423 		points[i][2] = b[(i>>2)&1][2];
    424 	}
    425 }