123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
- 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.
- ===========================================================================
- */
- #include "../precompiled.h"
- #pragma hdrstop
- idBounds bounds_zero( vec3_zero, vec3_zero );
- /*
- ============
- idBounds::GetRadius
- ============
- */
- float idBounds::GetRadius( void ) const {
- int i;
- float total, b0, b1;
- total = 0.0f;
- for ( i = 0; i < 3; i++ ) {
- b0 = (float)idMath::Fabs( b[0][i] );
- b1 = (float)idMath::Fabs( b[1][i] );
- if ( b0 > b1 ) {
- total += b0 * b0;
- } else {
- total += b1 * b1;
- }
- }
- return idMath::Sqrt( total );
- }
- /*
- ============
- idBounds::GetRadius
- ============
- */
- float idBounds::GetRadius( const idVec3 ¢er ) const {
- int i;
- float total, b0, b1;
- total = 0.0f;
- for ( i = 0; i < 3; i++ ) {
- b0 = (float)idMath::Fabs( center[i] - b[0][i] );
- b1 = (float)idMath::Fabs( b[1][i] - center[i] );
- if ( b0 > b1 ) {
- total += b0 * b0;
- } else {
- total += b1 * b1;
- }
- }
- return idMath::Sqrt( total );
- }
- /*
- ================
- idBounds::PlaneDistance
- ================
- */
- float idBounds::PlaneDistance( const idPlane &plane ) const {
- idVec3 center;
- float d1, d2;
- center = ( b[0] + b[1] ) * 0.5f;
- d1 = plane.Distance( center );
- d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) +
- idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) +
- idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] );
- if ( d1 - d2 > 0.0f ) {
- return d1 - d2;
- }
- if ( d1 + d2 < 0.0f ) {
- return d1 + d2;
- }
- return 0.0f;
- }
- /*
- ================
- idBounds::PlaneSide
- ================
- */
- int idBounds::PlaneSide( const idPlane &plane, const float epsilon ) const {
- idVec3 center;
- float d1, d2;
- center = ( b[0] + b[1] ) * 0.5f;
- d1 = plane.Distance( center );
- d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) +
- idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) +
- idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] );
- if ( d1 - d2 > epsilon ) {
- return PLANESIDE_FRONT;
- }
- if ( d1 + d2 < -epsilon ) {
- return PLANESIDE_BACK;
- }
- return PLANESIDE_CROSS;
- }
- /*
- ============
- idBounds::LineIntersection
- Returns true if the line intersects the bounds between the start and end point.
- ============
- */
- bool idBounds::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
- float ld[3];
- idVec3 center = ( b[0] + b[1] ) * 0.5f;
- idVec3 extents = b[1] - center;
- idVec3 lineDir = 0.5f * ( end - start );
- idVec3 lineCenter = start + lineDir;
- idVec3 dir = lineCenter - center;
- ld[0] = idMath::Fabs( lineDir[0] );
- if ( idMath::Fabs( dir[0] ) > extents[0] + ld[0] ) {
- return false;
- }
- ld[1] = idMath::Fabs( lineDir[1] );
- if ( idMath::Fabs( dir[1] ) > extents[1] + ld[1] ) {
- return false;
- }
- ld[2] = idMath::Fabs( lineDir[2] );
- if ( idMath::Fabs( dir[2] ) > extents[2] + ld[2] ) {
- return false;
- }
- idVec3 cross = lineDir.Cross( dir );
- if ( idMath::Fabs( cross[0] ) > extents[1] * ld[2] + extents[2] * ld[1] ) {
- return false;
- }
- if ( idMath::Fabs( cross[1] ) > extents[0] * ld[2] + extents[2] * ld[0] ) {
- return false;
- }
- if ( idMath::Fabs( cross[2] ) > extents[0] * ld[1] + extents[1] * ld[0] ) {
- return false;
- }
- return true;
- }
- /*
- ============
- idBounds::RayIntersection
- Returns true if the ray intersects the bounds.
- The ray can intersect the bounds in both directions from the start point.
- If start is inside the bounds it is considered an intersection with scale = 0
- ============
- */
- bool idBounds::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const {
- int i, ax0, ax1, ax2, side, inside;
- float f;
- idVec3 hit;
- ax0 = -1;
- inside = 0;
- for ( i = 0; i < 3; i++ ) {
- if ( start[i] < b[0][i] ) {
- side = 0;
- }
- else if ( start[i] > b[1][i] ) {
- side = 1;
- }
- else {
- inside++;
- continue;
- }
- if ( dir[i] == 0.0f ) {
- continue;
- }
- f = ( start[i] - b[side][i] );
- if ( ax0 < 0 || idMath::Fabs( f ) > idMath::Fabs( scale * dir[i] ) ) {
- scale = - ( f / dir[i] );
- ax0 = i;
- }
- }
- if ( ax0 < 0 ) {
- scale = 0.0f;
- // return true if the start point is inside the bounds
- return ( inside == 3 );
- }
- ax1 = (ax0+1)%3;
- ax2 = (ax0+2)%3;
- hit[ax1] = start[ax1] + scale * dir[ax1];
- hit[ax2] = start[ax2] + scale * dir[ax2];
- return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&
- hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );
- }
- /*
- ============
- idBounds::FromTransformedBounds
- ============
- */
- void idBounds::FromTransformedBounds( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis ) {
- int i;
- idVec3 center, extents, rotatedExtents;
- center = (bounds[0] + bounds[1]) * 0.5f;
- extents = bounds[1] - center;
- for ( i = 0; i < 3; i++ ) {
- rotatedExtents[i] = idMath::Fabs( extents[0] * axis[0][i] ) +
- idMath::Fabs( extents[1] * axis[1][i] ) +
- idMath::Fabs( extents[2] * axis[2][i] );
- }
- center = origin + center * axis;
- b[0] = center - rotatedExtents;
- b[1] = center + rotatedExtents;
- }
- /*
- ============
- idBounds::FromPoints
- Most tight bounds for a point set.
- ============
- */
- void idBounds::FromPoints( const idVec3 *points, const int numPoints ) {
- SIMDProcessor->MinMax( b[0], b[1], points, numPoints );
- }
- /*
- ============
- idBounds::FromPointTranslation
- Most tight bounds for the translational movement of the given point.
- ============
- */
- void idBounds::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
- int i;
- for ( i = 0; i < 3; i++ ) {
- if ( translation[i] < 0.0f ) {
- b[0][i] = point[i] + translation[i];
- b[1][i] = point[i];
- }
- else {
- b[0][i] = point[i];
- b[1][i] = point[i] + translation[i];
- }
- }
- }
- /*
- ============
- idBounds::FromBoundsTranslation
- Most tight bounds for the translational movement of the given bounds.
- ============
- */
- void idBounds::FromBoundsTranslation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation ) {
- int i;
- if ( axis.IsRotated() ) {
- FromTransformedBounds( bounds, origin, axis );
- }
- else {
- b[0] = bounds[0] + origin;
- b[1] = bounds[1] + origin;
- }
- for ( i = 0; i < 3; i++ ) {
- if ( translation[i] < 0.0f ) {
- b[0][i] += translation[i];
- }
- else {
- b[1][i] += translation[i];
- }
- }
- }
- /*
- ================
- BoundsForPointRotation
- only for rotations < 180 degrees
- ================
- */
- idBounds BoundsForPointRotation( const idVec3 &start, const idRotation &rotation ) {
- int i;
- float radiusSqr;
- idVec3 v1, v2;
- idVec3 origin, axis, end;
- idBounds bounds;
- end = start * rotation;
- axis = rotation.GetVec();
- origin = rotation.GetOrigin() + axis * ( axis * ( start - rotation.GetOrigin() ) );
- radiusSqr = ( start - origin ).LengthSqr();
- v1 = ( start - origin ).Cross( axis );
- v2 = ( end - origin ).Cross( axis );
- for ( i = 0; i < 3; i++ ) {
- // if the derivative changes sign along this axis during the rotation from start to end
- if ( ( v1[i] > 0.0f && v2[i] < 0.0f ) || ( v1[i] < 0.0f && v2[i] > 0.0f ) ) {
- if ( ( 0.5f * (start[i] + end[i]) - origin[i] ) > 0.0f ) {
- bounds[0][i] = Min( start[i], end[i] );
- bounds[1][i] = origin[i] + idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
- }
- else {
- bounds[0][i] = origin[i] - idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
- bounds[1][i] = Max( start[i], end[i] );
- }
- }
- else if ( start[i] > end[i] ) {
- bounds[0][i] = end[i];
- bounds[1][i] = start[i];
- }
- else {
- bounds[0][i] = start[i];
- bounds[1][i] = end[i];
- }
- }
- return bounds;
- }
- /*
- ============
- idBounds::FromPointRotation
- Most tight bounds for the rotational movement of the given point.
- ============
- */
- void idBounds::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
- float radius;
- if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
- (*this) = BoundsForPointRotation( point, rotation );
- }
- else {
- radius = ( point - rotation.GetOrigin() ).Length();
- // FIXME: these bounds are usually way larger
- b[0].Set( -radius, -radius, -radius );
- b[1].Set( radius, radius, radius );
- }
- }
- /*
- ============
- idBounds::FromBoundsRotation
- Most tight bounds for the rotational movement of the given bounds.
- ============
- */
- void idBounds::FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation ) {
- int i;
- float radius;
- idVec3 point;
- idBounds rBounds;
- if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
- (*this) = BoundsForPointRotation( bounds[0] * axis + origin, rotation );
- for ( i = 1; i < 8; i++ ) {
- point[0] = bounds[(i^(i>>1))&1][0];
- point[1] = bounds[(i>>1)&1][1];
- point[2] = bounds[(i>>2)&1][2];
- (*this) += BoundsForPointRotation( point * axis + origin, rotation );
- }
- }
- else {
- point = (bounds[1] - bounds[0]) * 0.5f;
- radius = (bounds[1] - point).Length() + (point - rotation.GetOrigin()).Length();
- // FIXME: these bounds are usually way larger
- b[0].Set( -radius, -radius, -radius );
- b[1].Set( radius, radius, radius );
- }
- }
- /*
- ============
- idBounds::ToPoints
- ============
- */
- void idBounds::ToPoints( idVec3 points[8] ) const {
- for ( int i = 0; i < 8; i++ ) {
- points[i][0] = b[(i^(i>>1))&1][0];
- points[i][1] = b[(i>>1)&1][1];
- points[i][2] = b[(i>>2)&1][2];
- }
- }
|