Initial commit

This commit is contained in:
Brian Harris
2012-11-26 12:58:24 -06:00
parent a5214f79ef
commit 5016f605b8
1115 changed files with 587266 additions and 0 deletions

425
neo/idlib/bv/Bounds.cpp Normal file
View File

@@ -0,0 +1,425 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#pragma hdrstop
#include "../precompiled.h"
idBounds bounds_zero( vec3_zero, vec3_zero );
idBounds bounds_zeroOneCube( idVec3( 0.0f ), idVec3( 1.0f ) );
idBounds bounds_unitCube( idVec3( -1.0f ), idVec3( 1.0f ) );
/*
============
idBounds::GetRadius
============
*/
float idBounds::GetRadius() 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 &center ) 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 {
const idVec3 center = ( b[0] + b[1] ) * 0.5f;
const idVec3 extents = b[1] - center;
const idVec3 lineDir = 0.5f * ( end - start );
const idVec3 lineCenter = start + lineDir;
const idVec3 dir = lineCenter - center;
const float ld0 = idMath::Fabs( lineDir[0] );
if ( idMath::Fabs( dir[0] ) > extents[0] + ld0 ) {
return false;
}
const float ld1 = idMath::Fabs( lineDir[1] );
if ( idMath::Fabs( dir[1] ) > extents[1] + ld1 ) {
return false;
}
const float ld2 = idMath::Fabs( lineDir[2] );
if ( idMath::Fabs( dir[2] ) > extents[2] + ld2 ) {
return false;
}
const idVec3 cross = lineDir.Cross( dir );
if ( idMath::Fabs( cross[0] ) > extents[1] * ld2 + extents[2] * ld1 ) {
return false;
}
if ( idMath::Fabs( cross[1] ) > extents[0] * ld2 + extents[2] * ld0 ) {
return false;
}
if ( idMath::Fabs( cross[2] ) > extents[0] * ld1 + extents[1] * ld0 ) {
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];
}
}

428
neo/idlib/bv/Bounds.h Normal file
View File

@@ -0,0 +1,428 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#ifndef __BV_BOUNDS_H__
#define __BV_BOUNDS_H__
/*
===============================================================================
Axis Aligned Bounding Box
===============================================================================
*/
class idBounds {
public:
idBounds();
explicit idBounds( const idVec3 &mins, const idVec3 &maxs );
explicit idBounds( const idVec3 &point );
const idVec3 & operator[]( const int index ) const;
idVec3 & operator[]( const int index );
idBounds operator+( const idVec3 &t ) const; // returns translated bounds
idBounds & operator+=( const idVec3 &t ); // translate the bounds
idBounds operator*( const idMat3 &r ) const; // returns rotated bounds
idBounds & operator*=( const idMat3 &r ); // rotate the bounds
idBounds operator+( const idBounds &a ) const;
idBounds & operator+=( const idBounds &a );
idBounds operator-( const idBounds &a ) const;
idBounds & operator-=( const idBounds &a );
bool Compare( const idBounds &a ) const; // exact compare, no epsilon
bool Compare( const idBounds &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idBounds &a ) const; // exact compare, no epsilon
bool operator!=( const idBounds &a ) const; // exact compare, no epsilon
void Clear(); // inside out bounds
void Zero(); // single point at origin
idVec3 GetCenter() const; // returns center of bounds
float GetRadius() const; // returns the radius relative to the bounds origin
float GetRadius( const idVec3 &center ) const; // returns the radius relative to the given center
float GetVolume() const; // returns the volume of the bounds
bool IsCleared() const; // returns true if bounds are inside out
bool AddPoint( const idVec3 &v ); // add the point, returns true if the bounds expanded
bool AddBounds( const idBounds &a ); // add the bounds, returns true if the bounds expanded
idBounds Intersect( const idBounds &a ) const; // return intersection of this bounds with the given bounds
idBounds & IntersectSelf( const idBounds &a ); // intersect this bounds with the given bounds
idBounds Expand( const float d ) const; // return bounds expanded in all directions with the given value
idBounds & ExpandSelf( const float d ); // expand bounds in all directions with the given value
idBounds Translate( const idVec3 &translation ) const; // return translated bounds
idBounds & TranslateSelf( const idVec3 &translation ); // translate this bounds
idBounds Rotate( const idMat3 &rotation ) const; // return rotated bounds
idBounds & RotateSelf( const idMat3 &rotation ); // rotate this bounds
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool ContainsPoint( const idVec3 &p ) const; // includes touching
bool IntersectsBounds( const idBounds &a ) const; // includes touching
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
// intersection point is start + dir * scale
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const;
// most tight bounds for the given transformed bounds
void FromTransformedBounds( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis );
// most tight bounds for a point set
void FromPoints( const idVec3 *points, const int numPoints );
// most tight bounds for a translation
void FromPointTranslation( const idVec3 &point, const idVec3 &translation );
void FromBoundsTranslation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation );
// most tight bounds for a rotation
void FromPointRotation( const idVec3 &point, const idRotation &rotation );
void FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation );
void ToPoints( idVec3 points[8] ) const;
idSphere ToSphere() const;
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
void AxisProjection( const idVec3 &origin, const idMat3 &axis, const idVec3 &dir, float &min, float &max ) const;
int GetDimension() const;
const float * ToFloatPtr() const;
float * ToFloatPtr();
private:
idVec3 b[2];
};
extern idBounds bounds_zero;
extern idBounds bounds_zeroOneCube;
extern idBounds bounds_unitCube;
ID_INLINE idBounds::idBounds() {
}
ID_INLINE idBounds::idBounds( const idVec3 &mins, const idVec3 &maxs ) {
b[0] = mins;
b[1] = maxs;
}
ID_INLINE idBounds::idBounds( const idVec3 &point ) {
b[0] = point;
b[1] = point;
}
ID_INLINE const idVec3 &idBounds::operator[]( const int index ) const {
return b[index];
}
ID_INLINE idVec3 &idBounds::operator[]( const int index ) {
return b[index];
}
ID_INLINE idBounds idBounds::operator+( const idVec3 &t ) const {
return idBounds( b[0] + t, b[1] + t );
}
ID_INLINE idBounds &idBounds::operator+=( const idVec3 &t ) {
b[0] += t;
b[1] += t;
return *this;
}
ID_INLINE idBounds idBounds::operator*( const idMat3 &r ) const {
idBounds bounds;
bounds.FromTransformedBounds( *this, vec3_origin, r );
return bounds;
}
ID_INLINE idBounds &idBounds::operator*=( const idMat3 &r ) {
this->FromTransformedBounds( *this, vec3_origin, r );
return *this;
}
ID_INLINE idBounds idBounds::operator+( const idBounds &a ) const {
idBounds newBounds;
newBounds = *this;
newBounds.AddBounds( a );
return newBounds;
}
ID_INLINE idBounds &idBounds::operator+=( const idBounds &a ) {
idBounds::AddBounds( a );
return *this;
}
ID_INLINE idBounds idBounds::operator-( const idBounds &a ) const {
assert( b[1][0] - b[0][0] > a.b[1][0] - a.b[0][0] &&
b[1][1] - b[0][1] > a.b[1][1] - a.b[0][1] &&
b[1][2] - b[0][2] > a.b[1][2] - a.b[0][2] );
return idBounds( idVec3( b[0][0] + a.b[1][0], b[0][1] + a.b[1][1], b[0][2] + a.b[1][2] ),
idVec3( b[1][0] + a.b[0][0], b[1][1] + a.b[0][1], b[1][2] + a.b[0][2] ) );
}
ID_INLINE idBounds &idBounds::operator-=( const idBounds &a ) {
assert( b[1][0] - b[0][0] > a.b[1][0] - a.b[0][0] &&
b[1][1] - b[0][1] > a.b[1][1] - a.b[0][1] &&
b[1][2] - b[0][2] > a.b[1][2] - a.b[0][2] );
b[0] += a.b[1];
b[1] += a.b[0];
return *this;
}
ID_INLINE bool idBounds::Compare( const idBounds &a ) const {
return ( b[0].Compare( a.b[0] ) && b[1].Compare( a.b[1] ) );
}
ID_INLINE bool idBounds::Compare( const idBounds &a, const float epsilon ) const {
return ( b[0].Compare( a.b[0], epsilon ) && b[1].Compare( a.b[1], epsilon ) );
}
ID_INLINE bool idBounds::operator==( const idBounds &a ) const {
return Compare( a );
}
ID_INLINE bool idBounds::operator!=( const idBounds &a ) const {
return !Compare( a );
}
ID_INLINE void idBounds::Clear() {
b[0][0] = b[0][1] = b[0][2] = idMath::INFINITY;
b[1][0] = b[1][1] = b[1][2] = -idMath::INFINITY;
}
ID_INLINE void idBounds::Zero() {
b[0][0] = b[0][1] = b[0][2] =
b[1][0] = b[1][1] = b[1][2] = 0;
}
ID_INLINE idVec3 idBounds::GetCenter() const {
return idVec3( ( b[1][0] + b[0][0] ) * 0.5f, ( b[1][1] + b[0][1] ) * 0.5f, ( b[1][2] + b[0][2] ) * 0.5f );
}
ID_INLINE float idBounds::GetVolume() const {
if ( b[0][0] >= b[1][0] || b[0][1] >= b[1][1] || b[0][2] >= b[1][2] ) {
return 0.0f;
}
return ( ( b[1][0] - b[0][0] ) * ( b[1][1] - b[0][1] ) * ( b[1][2] - b[0][2] ) );
}
ID_INLINE bool idBounds::IsCleared() const {
return b[0][0] > b[1][0];
}
ID_INLINE bool idBounds::AddPoint( const idVec3 &v ) {
bool expanded = false;
if ( v[0] < b[0][0]) {
b[0][0] = v[0];
expanded = true;
}
if ( v[0] > b[1][0]) {
b[1][0] = v[0];
expanded = true;
}
if ( v[1] < b[0][1] ) {
b[0][1] = v[1];
expanded = true;
}
if ( v[1] > b[1][1]) {
b[1][1] = v[1];
expanded = true;
}
if ( v[2] < b[0][2] ) {
b[0][2] = v[2];
expanded = true;
}
if ( v[2] > b[1][2]) {
b[1][2] = v[2];
expanded = true;
}
return expanded;
}
ID_INLINE bool idBounds::AddBounds( const idBounds &a ) {
bool expanded = false;
if ( a.b[0][0] < b[0][0] ) {
b[0][0] = a.b[0][0];
expanded = true;
}
if ( a.b[0][1] < b[0][1] ) {
b[0][1] = a.b[0][1];
expanded = true;
}
if ( a.b[0][2] < b[0][2] ) {
b[0][2] = a.b[0][2];
expanded = true;
}
if ( a.b[1][0] > b[1][0] ) {
b[1][0] = a.b[1][0];
expanded = true;
}
if ( a.b[1][1] > b[1][1] ) {
b[1][1] = a.b[1][1];
expanded = true;
}
if ( a.b[1][2] > b[1][2] ) {
b[1][2] = a.b[1][2];
expanded = true;
}
return expanded;
}
ID_INLINE idBounds idBounds::Intersect( const idBounds &a ) const {
idBounds n;
n.b[0][0] = ( a.b[0][0] > b[0][0] ) ? a.b[0][0] : b[0][0];
n.b[0][1] = ( a.b[0][1] > b[0][1] ) ? a.b[0][1] : b[0][1];
n.b[0][2] = ( a.b[0][2] > b[0][2] ) ? a.b[0][2] : b[0][2];
n.b[1][0] = ( a.b[1][0] < b[1][0] ) ? a.b[1][0] : b[1][0];
n.b[1][1] = ( a.b[1][1] < b[1][1] ) ? a.b[1][1] : b[1][1];
n.b[1][2] = ( a.b[1][2] < b[1][2] ) ? a.b[1][2] : b[1][2];
return n;
}
ID_INLINE idBounds &idBounds::IntersectSelf( const idBounds &a ) {
if ( a.b[0][0] > b[0][0] ) {
b[0][0] = a.b[0][0];
}
if ( a.b[0][1] > b[0][1] ) {
b[0][1] = a.b[0][1];
}
if ( a.b[0][2] > b[0][2] ) {
b[0][2] = a.b[0][2];
}
if ( a.b[1][0] < b[1][0] ) {
b[1][0] = a.b[1][0];
}
if ( a.b[1][1] < b[1][1] ) {
b[1][1] = a.b[1][1];
}
if ( a.b[1][2] < b[1][2] ) {
b[1][2] = a.b[1][2];
}
return *this;
}
ID_INLINE idBounds idBounds::Expand( const float d ) const {
return idBounds( idVec3( b[0][0] - d, b[0][1] - d, b[0][2] - d ),
idVec3( b[1][0] + d, b[1][1] + d, b[1][2] + d ) );
}
ID_INLINE idBounds &idBounds::ExpandSelf( const float d ) {
b[0][0] -= d;
b[0][1] -= d;
b[0][2] -= d;
b[1][0] += d;
b[1][1] += d;
b[1][2] += d;
return *this;
}
ID_INLINE idBounds idBounds::Translate( const idVec3 &translation ) const {
return idBounds( b[0] + translation, b[1] + translation );
}
ID_INLINE idBounds &idBounds::TranslateSelf( const idVec3 &translation ) {
b[0] += translation;
b[1] += translation;
return *this;
}
ID_INLINE idBounds idBounds::Rotate( const idMat3 &rotation ) const {
idBounds bounds;
bounds.FromTransformedBounds( *this, vec3_origin, rotation );
return bounds;
}
ID_INLINE idBounds &idBounds::RotateSelf( const idMat3 &rotation ) {
FromTransformedBounds( *this, vec3_origin, rotation );
return *this;
}
ID_INLINE bool idBounds::ContainsPoint( const idVec3 &p ) const {
if ( p[0] < b[0][0] || p[1] < b[0][1] || p[2] < b[0][2]
|| p[0] > b[1][0] || p[1] > b[1][1] || p[2] > b[1][2] ) {
return false;
}
return true;
}
ID_INLINE bool idBounds::IntersectsBounds( const idBounds &a ) const {
if ( a.b[1][0] < b[0][0] || a.b[1][1] < b[0][1] || a.b[1][2] < b[0][2]
|| a.b[0][0] > b[1][0] || a.b[0][1] > b[1][1] || a.b[0][2] > b[1][2] ) {
return false;
}
return true;
}
ID_INLINE idSphere idBounds::ToSphere() const {
idSphere sphere;
sphere.SetOrigin( ( b[0] + b[1] ) * 0.5f );
sphere.SetRadius( ( b[1] - sphere.GetOrigin() ).Length() );
return sphere;
}
ID_INLINE void idBounds::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
float d1, d2;
idVec3 center, extents;
center = ( b[0] + b[1] ) * 0.5f;
extents = b[1] - center;
d1 = dir * center;
d2 = idMath::Fabs( extents[0] * dir[0] ) +
idMath::Fabs( extents[1] * dir[1] ) +
idMath::Fabs( extents[2] * dir[2] );
min = d1 - d2;
max = d1 + d2;
}
ID_INLINE void idBounds::AxisProjection( const idVec3 &origin, const idMat3 &axis, const idVec3 &dir, float &min, float &max ) const {
float d1, d2;
idVec3 center, extents;
center = ( b[0] + b[1] ) * 0.5f;
extents = b[1] - center;
center = origin + center * axis;
d1 = dir * center;
d2 = idMath::Fabs( extents[0] * ( dir * axis[0] ) ) +
idMath::Fabs( extents[1] * ( dir * axis[1] ) ) +
idMath::Fabs( extents[2] * ( dir * axis[2] ) );
min = d1 - d2;
max = d1 + d2;
}
ID_INLINE int idBounds::GetDimension() const {
return 6;
}
ID_INLINE const float *idBounds::ToFloatPtr() const {
return &b[0].x;
}
ID_INLINE float *idBounds::ToFloatPtr() {
return &b[0].x;
}
#endif /* !__BV_BOUNDS_H__ */

849
neo/idlib/bv/Box.cpp Normal file
View File

@@ -0,0 +1,849 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#pragma hdrstop
#include "../precompiled.h"
idBox box_zero( vec3_zero, vec3_zero, mat3_identity );
/*
4---{4}---5
+ /| /|
Z {7} {8} {5} |
- / | / {9}
7--{6}----6 |
| | | |
{11} 0---|-{0}-1
| / | / -
| {3} {10} {1} Y
|/ |/ +
3---{2}---2
- X +
plane bits:
0 = min x
1 = max x
2 = min y
3 = max y
4 = min z
5 = max z
*/
/*
static int boxVertPlanes[8] = {
( (1<<0) | (1<<2) | (1<<4) ),
( (1<<1) | (1<<2) | (1<<4) ),
( (1<<1) | (1<<3) | (1<<4) ),
( (1<<0) | (1<<3) | (1<<4) ),
( (1<<0) | (1<<2) | (1<<5) ),
( (1<<1) | (1<<2) | (1<<5) ),
( (1<<1) | (1<<3) | (1<<5) ),
( (1<<0) | (1<<3) | (1<<5) )
};
static int boxVertEdges[8][3] = {
// bottom
{ 3, 0, 8 },
{ 0, 1, 9 },
{ 1, 2, 10 },
{ 2, 3, 11 },
// top
{ 7, 4, 8 },
{ 4, 5, 9 },
{ 5, 6, 10 },
{ 6, 7, 11 }
};
static int boxEdgePlanes[12][2] = {
// bottom
{ 4, 2 },
{ 4, 1 },
{ 4, 3 },
{ 4, 0 },
// top
{ 5, 2 },
{ 5, 1 },
{ 5, 3 },
{ 5, 0 },
// sides
{ 0, 2 },
{ 2, 1 },
{ 1, 3 },
{ 3, 0 }
};
static int boxEdgeVerts[12][2] = {
// bottom
{ 0, 1 },
{ 1, 2 },
{ 2, 3 },
{ 3, 0 },
// top
{ 4, 5 },
{ 5, 6 },
{ 6, 7 },
{ 7, 4 },
// sides
{ 0, 4 },
{ 1, 5 },
{ 2, 6 },
{ 3, 7 }
};
*/
static int boxPlaneBitsSilVerts[64][7] = {
{ 0, 0, 0, 0, 0, 0, 0 }, // 000000 = 0
{ 4, 7, 4, 0, 3, 0, 0 }, // 000001 = 1
{ 4, 5, 6, 2, 1, 0, 0 }, // 000010 = 2
{ 0, 0, 0, 0, 0, 0, 0 }, // 000011 = 3
{ 4, 4, 5, 1, 0, 0, 0 }, // 000100 = 4
{ 6, 3, 7, 4, 5, 1, 0 }, // 000101 = 5
{ 6, 4, 5, 6, 2, 1, 0 }, // 000110 = 6
{ 0, 0, 0, 0, 0, 0, 0 }, // 000111 = 7
{ 4, 6, 7, 3, 2, 0, 0 }, // 001000 = 8
{ 6, 6, 7, 4, 0, 3, 2 }, // 001001 = 9
{ 6, 5, 6, 7, 3, 2, 1 }, // 001010 = 10
{ 0, 0, 0, 0, 0, 0, 0 }, // 001011 = 11
{ 0, 0, 0, 0, 0, 0, 0 }, // 001100 = 12
{ 0, 0, 0, 0, 0, 0, 0 }, // 001101 = 13
{ 0, 0, 0, 0, 0, 0, 0 }, // 001110 = 14
{ 0, 0, 0, 0, 0, 0, 0 }, // 001111 = 15
{ 4, 0, 1, 2, 3, 0, 0 }, // 010000 = 16
{ 6, 0, 1, 2, 3, 7, 4 }, // 010001 = 17
{ 6, 3, 2, 6, 5, 1, 0 }, // 010010 = 18
{ 0, 0, 0, 0, 0, 0, 0 }, // 010011 = 19
{ 6, 1, 2, 3, 0, 4, 5 }, // 010100 = 20
{ 6, 1, 2, 3, 7, 4, 5 }, // 010101 = 21
{ 6, 2, 3, 0, 4, 5, 6 }, // 010110 = 22
{ 0, 0, 0, 0, 0, 0, 0 }, // 010111 = 23
{ 6, 0, 1, 2, 6, 7, 3 }, // 011000 = 24
{ 6, 0, 1, 2, 6, 7, 4 }, // 011001 = 25
{ 6, 0, 1, 5, 6, 7, 3 }, // 011010 = 26
{ 0, 0, 0, 0, 0, 0, 0 }, // 011011 = 27
{ 0, 0, 0, 0, 0, 0, 0 }, // 011100 = 28
{ 0, 0, 0, 0, 0, 0, 0 }, // 011101 = 29
{ 0, 0, 0, 0, 0, 0, 0 }, // 011110 = 30
{ 0, 0, 0, 0, 0, 0, 0 }, // 011111 = 31
{ 4, 7, 6, 5, 4, 0, 0 }, // 100000 = 32
{ 6, 7, 6, 5, 4, 0, 3 }, // 100001 = 33
{ 6, 5, 4, 7, 6, 2, 1 }, // 100010 = 34
{ 0, 0, 0, 0, 0, 0, 0 }, // 100011 = 35
{ 6, 4, 7, 6, 5, 1, 0 }, // 100100 = 36
{ 6, 3, 7, 6, 5, 1, 0 }, // 100101 = 37
{ 6, 4, 7, 6, 2, 1, 0 }, // 100110 = 38
{ 0, 0, 0, 0, 0, 0, 0 }, // 100111 = 39
{ 6, 6, 5, 4, 7, 3, 2 }, // 101000 = 40
{ 6, 6, 5, 4, 0, 3, 2 }, // 101001 = 41
{ 6, 5, 4, 7, 3, 2, 1 }, // 101010 = 42
{ 0, 0, 0, 0, 0, 0, 0 }, // 101011 = 43
{ 0, 0, 0, 0, 0, 0, 0 }, // 101100 = 44
{ 0, 0, 0, 0, 0, 0, 0 }, // 101101 = 45
{ 0, 0, 0, 0, 0, 0, 0 }, // 101110 = 46
{ 0, 0, 0, 0, 0, 0, 0 }, // 101111 = 47
{ 0, 0, 0, 0, 0, 0, 0 }, // 110000 = 48
{ 0, 0, 0, 0, 0, 0, 0 }, // 110001 = 49
{ 0, 0, 0, 0, 0, 0, 0 }, // 110010 = 50
{ 0, 0, 0, 0, 0, 0, 0 }, // 110011 = 51
{ 0, 0, 0, 0, 0, 0, 0 }, // 110100 = 52
{ 0, 0, 0, 0, 0, 0, 0 }, // 110101 = 53
{ 0, 0, 0, 0, 0, 0, 0 }, // 110110 = 54
{ 0, 0, 0, 0, 0, 0, 0 }, // 110111 = 55
{ 0, 0, 0, 0, 0, 0, 0 }, // 111000 = 56
{ 0, 0, 0, 0, 0, 0, 0 }, // 111001 = 57
{ 0, 0, 0, 0, 0, 0, 0 }, // 111010 = 58
{ 0, 0, 0, 0, 0, 0, 0 }, // 111011 = 59
{ 0, 0, 0, 0, 0, 0, 0 }, // 111100 = 60
{ 0, 0, 0, 0, 0, 0, 0 }, // 111101 = 61
{ 0, 0, 0, 0, 0, 0, 0 }, // 111110 = 62
{ 0, 0, 0, 0, 0, 0, 0 }, // 111111 = 63
};
/*
============
idBox::AddPoint
============
*/
bool idBox::AddPoint( const idVec3 &v ) {
idMat3 axis2;
idBounds bounds1, bounds2;
if ( extents[0] < 0.0f ) {
extents.Zero();
center = v;
axis.Identity();
return true;
}
bounds1[0][0] = bounds1[1][0] = center * axis[0];
bounds1[0][1] = bounds1[1][1] = center * axis[1];
bounds1[0][2] = bounds1[1][2] = center * axis[2];
bounds1[0] -= extents;
bounds1[1] += extents;
if ( !bounds1.AddPoint( idVec3( v * axis[0], v * axis[1], v * axis[2] ) ) ) {
// point is contained in the box
return false;
}
axis2[0] = v - center;
axis2[0].Normalize();
axis2[1] = axis[ Min3Index( axis2[0] * axis[0], axis2[0] * axis[1], axis2[0] * axis[2] ) ];
axis2[1] = axis2[1] - ( axis2[1] * axis2[0] ) * axis2[0];
axis2[1].Normalize();
axis2[2].Cross( axis2[0], axis2[1] );
AxisProjection( axis2, bounds2 );
bounds2.AddPoint( idVec3( v * axis2[0], v * axis2[1], v * axis2[2] ) );
// create new box based on the smallest bounds
if ( bounds1.GetVolume() < bounds2.GetVolume() ) {
center = ( bounds1[0] + bounds1[1] ) * 0.5f;
extents = bounds1[1] - center;
center *= axis;
}
else {
center = ( bounds2[0] + bounds2[1] ) * 0.5f;
extents = bounds2[1] - center;
center *= axis2;
axis = axis2;
}
return true;
}
/*
============
idBox::AddBox
============
*/
bool idBox::AddBox( const idBox &a ) {
int i, besti;
float v, bestv;
idVec3 dir;
idMat3 ax[4];
idBounds bounds[4], b;
if ( a.extents[0] < 0.0f ) {
return false;
}
if ( extents[0] < 0.0f ) {
center = a.center;
extents = a.extents;
axis = a.axis;
return true;
}
// test axis of this box
ax[0] = axis;
bounds[0][0][0] = bounds[0][1][0] = center * ax[0][0];
bounds[0][0][1] = bounds[0][1][1] = center * ax[0][1];
bounds[0][0][2] = bounds[0][1][2] = center * ax[0][2];
bounds[0][0] -= extents;
bounds[0][1] += extents;
a.AxisProjection( ax[0], b );
if ( !bounds[0].AddBounds( b ) ) {
// the other box is contained in this box
return false;
}
// test axis of other box
ax[1] = a.axis;
bounds[1][0][0] = bounds[1][1][0] = a.center * ax[1][0];
bounds[1][0][1] = bounds[1][1][1] = a.center * ax[1][1];
bounds[1][0][2] = bounds[1][1][2] = a.center * ax[1][2];
bounds[1][0] -= a.extents;
bounds[1][1] += a.extents;
AxisProjection( ax[1], b );
if ( !bounds[1].AddBounds( b ) ) {
// this box is contained in the other box
center = a.center;
extents = a.extents;
axis = a.axis;
return true;
}
// test axes aligned with the vector between the box centers and one of the box axis
dir = a.center - center;
dir.Normalize();
for ( i = 2; i < 4; i++ ) {
ax[i][0] = dir;
ax[i][1] = ax[i-2][ Min3Index( dir * ax[i-2][0], dir * ax[i-2][1], dir * ax[i-2][2] ) ];
ax[i][1] = ax[i][1] - ( ax[i][1] * dir ) * dir;
ax[i][1].Normalize();
ax[i][2].Cross( dir, ax[i][1] );
AxisProjection( ax[i], bounds[i] );
a.AxisProjection( ax[i], b );
bounds[i].AddBounds( b );
}
// get the bounds with the smallest volume
bestv = idMath::INFINITY;
besti = 0;
for ( i = 0; i < 4; i++ ) {
v = bounds[i].GetVolume();
if ( v < bestv ) {
bestv = v;
besti = i;
}
}
// create a box from the smallest bounds axis pair
center = ( bounds[besti][0] + bounds[besti][1] ) * 0.5f;
extents = bounds[besti][1] - center;
center *= ax[besti];
axis = ax[besti];
return false;
}
/*
================
idBox::PlaneDistance
================
*/
float idBox::PlaneDistance( const idPlane &plane ) const {
float d1, d2;
d1 = plane.Distance( center );
d2 = idMath::Fabs( extents[0] * plane.Normal()[0] ) +
idMath::Fabs( extents[1] * plane.Normal()[1] ) +
idMath::Fabs( extents[2] * plane.Normal()[2] );
if ( d1 - d2 > 0.0f ) {
return d1 - d2;
}
if ( d1 + d2 < 0.0f ) {
return d1 + d2;
}
return 0.0f;
}
/*
================
idBox::PlaneSide
================
*/
int idBox::PlaneSide( const idPlane &plane, const float epsilon ) const {
float d1, d2;
d1 = plane.Distance( center );
d2 = idMath::Fabs( extents[0] * plane.Normal()[0] ) +
idMath::Fabs( extents[1] * plane.Normal()[1] ) +
idMath::Fabs( extents[2] * plane.Normal()[2] );
if ( d1 - d2 > epsilon ) {
return PLANESIDE_FRONT;
}
if ( d1 + d2 < -epsilon ) {
return PLANESIDE_BACK;
}
return PLANESIDE_CROSS;
}
/*
============
idBox::IntersectsBox
============
*/
bool idBox::IntersectsBox( const idBox &a ) const {
idVec3 dir; // vector between centers
float c[3][3]; // matrix c = axis.Transpose() * a.axis
float ac[3][3]; // absolute values of c
float axisdir[3]; // axis[i] * dir
float d, e0, e1; // distance between centers and projected extents
dir = a.center - center;
// axis C0 + t * A0
c[0][0] = axis[0] * a.axis[0];
c[0][1] = axis[0] * a.axis[1];
c[0][2] = axis[0] * a.axis[2];
axisdir[0] = axis[0] * dir;
ac[0][0] = idMath::Fabs( c[0][0] );
ac[0][1] = idMath::Fabs( c[0][1] );
ac[0][2] = idMath::Fabs( c[0][2] );
d = idMath::Fabs( axisdir[0] );
e0 = extents[0];
e1 = a.extents[0] * ac[0][0] + a.extents[1] * ac[0][1] + a.extents[2] * ac[0][2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1
c[1][0] = axis[1] * a.axis[0];
c[1][1] = axis[1] * a.axis[1];
c[1][2] = axis[1] * a.axis[2];
axisdir[1] = axis[1] * dir;
ac[1][0] = idMath::Fabs( c[1][0] );
ac[1][1] = idMath::Fabs( c[1][1] );
ac[1][2] = idMath::Fabs( c[1][2] );
d = idMath::Fabs( axisdir[1] );
e0 = extents[1];
e1 = a.extents[0] * ac[1][0] + a.extents[1] * ac[1][1] + a.extents[2] * ac[1][2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2
c[2][0] = axis[2] * a.axis[0];
c[2][1] = axis[2] * a.axis[1];
c[2][2] = axis[2] * a.axis[2];
axisdir[2] = axis[2] * dir;
ac[2][0] = idMath::Fabs( c[2][0] );
ac[2][1] = idMath::Fabs( c[2][1] );
ac[2][2] = idMath::Fabs( c[2][2] );
d = idMath::Fabs( axisdir[2] );
e0 = extents[2];
e1 = a.extents[0] * ac[2][0] + a.extents[1] * ac[2][1] + a.extents[2] * ac[2][2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * B0
d = idMath::Fabs( a.axis[0] * dir );
e0 = extents[0] * ac[0][0] + extents[1] * ac[1][0] + extents[2] * ac[2][0];
e1 = a.extents[0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * B1
d = idMath::Fabs( a.axis[1] * dir );
e0 = extents[0] * ac[0][1] + extents[1] * ac[1][1] + extents[2] * ac[2][1];
e1 = a.extents[1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * B2
d = idMath::Fabs( a.axis[2] * dir );
e0 = extents[0] * ac[0][2] + extents[1] * ac[1][2] + extents[2] * ac[2][2];
e1 = a.extents[2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A0xB0
d = idMath::Fabs( axisdir[2] * c[1][0] - axisdir[1] * c[2][0] );
e0 = extents[1] * ac[2][0] + extents[2] * ac[1][0];
e1 = a.extents[1] * ac[0][2] + a.extents[2] * ac[0][1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A0xB1
d = idMath::Fabs( axisdir[2] * c[1][1] - axisdir[1] * c[2][1] );
e0 = extents[1] * ac[2][1] + extents[2] * ac[1][1];
e1 = a.extents[0] * ac[0][2] + a.extents[2] * ac[0][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A0xB2
d = idMath::Fabs( axisdir[2] * c[1][2] - axisdir[1] * c[2][2] );
e0 = extents[1] * ac[2][2] + extents[2] * ac[1][2];
e1 = a.extents[0] * ac[0][1] + a.extents[1] * ac[0][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1xB0
d = idMath::Fabs( axisdir[0] * c[2][0] - axisdir[2] * c[0][0] );
e0 = extents[0] * ac[2][0] + extents[2] * ac[0][0];
e1 = a.extents[1] * ac[1][2] + a.extents[2] * ac[1][1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1xB1
d = idMath::Fabs( axisdir[0] * c[2][1] - axisdir[2] * c[0][1] );
e0 = extents[0] * ac[2][1] + extents[2] * ac[0][1];
e1 = a.extents[0] * ac[1][2] + a.extents[2] * ac[1][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1xB2
d = idMath::Fabs( axisdir[0] * c[2][2] - axisdir[2] * c[0][2] );
e0 = extents[0] * ac[2][2] + extents[2] * ac[0][2];
e1 = a.extents[0] * ac[1][1] + a.extents[1] * ac[1][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2xB0
d = idMath::Fabs( axisdir[1] * c[0][0] - axisdir[0] * c[1][0] );
e0 = extents[0] * ac[1][0] + extents[1] * ac[0][0];
e1 = a.extents[1] * ac[2][2] + a.extents[2] * ac[2][1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2xB1
d = idMath::Fabs( axisdir[1] * c[0][1] - axisdir[0] * c[1][1] );
e0 = extents[0] * ac[1][1] + extents[1] * ac[0][1];
e1 = a.extents[0] * ac[2][2] + a.extents[2] * ac[2][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2xB2
d = idMath::Fabs( axisdir[1] * c[0][2] - axisdir[0] * c[1][2] );
e0 = extents[0] * ac[1][2] + extents[1] * ac[0][2];
e1 = a.extents[0] * ac[2][1] + a.extents[1] * ac[2][0];
if ( d > e0 + e1 ) {
return false;
}
return true;
}
/*
============
idBox::LineIntersection
Returns true if the line intersects the box between the start and end point.
============
*/
bool idBox::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
float ld[3];
idVec3 lineDir = 0.5f * ( end - start );
idVec3 lineCenter = start + lineDir;
idVec3 dir = lineCenter - center;
ld[0] = idMath::Fabs( lineDir * axis[0] );
if ( idMath::Fabs( dir * axis[0] ) > extents[0] + ld[0] ) {
return false;
}
ld[1] = idMath::Fabs( lineDir * axis[1] );
if ( idMath::Fabs( dir * axis[1] ) > extents[1] + ld[1] ) {
return false;
}
ld[2] = idMath::Fabs( lineDir * axis[2] );
if ( idMath::Fabs( dir * axis[2] ) > extents[2] + ld[2] ) {
return false;
}
idVec3 cross = lineDir.Cross( dir );
if ( idMath::Fabs( cross * axis[0] ) > extents[1] * ld[2] + extents[2] * ld[1] ) {
return false;
}
if ( idMath::Fabs( cross * axis[1] ) > extents[0] * ld[2] + extents[2] * ld[0] ) {
return false;
}
if ( idMath::Fabs( cross * axis[2] ) > extents[0] * ld[1] + extents[1] * ld[0] ) {
return false;
}
return true;
}
/*
============
BoxPlaneClip
============
*/
static bool BoxPlaneClip( const float denom, const float numer, float &scale0, float &scale1 ) {
if ( denom > 0.0f ) {
if ( numer > denom * scale1 ) {
return false;
}
if ( numer > denom * scale0 ) {
scale0 = numer / denom;
}
return true;
}
else if ( denom < 0.0f ) {
if ( numer > denom * scale0 ) {
return false;
}
if ( numer > denom * scale1 ) {
scale1 = numer / denom;
}
return true;
}
else {
return ( numer <= 0.0f );
}
}
/*
============
idBox::RayIntersection
Returns true if the ray intersects the box.
The ray can intersect the box in both directions from the start point.
If start is inside the box then scale1 < 0 and scale2 > 0.
============
*/
bool idBox::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
idVec3 localStart, localDir;
localStart = ( start - center ) * axis.Transpose();
localDir = dir * axis.Transpose();
scale1 = -idMath::INFINITY;
scale2 = idMath::INFINITY;
return BoxPlaneClip( localDir.x, -localStart.x - extents[0], scale1, scale2 ) &&
BoxPlaneClip( -localDir.x, localStart.x - extents[0], scale1, scale2 ) &&
BoxPlaneClip( localDir.y, -localStart.y - extents[1], scale1, scale2 ) &&
BoxPlaneClip( -localDir.y, localStart.y - extents[1], scale1, scale2 ) &&
BoxPlaneClip( localDir.z, -localStart.z - extents[2], scale1, scale2 ) &&
BoxPlaneClip( -localDir.z, localStart.z - extents[2], scale1, scale2 );
}
/*
============
idBox::FromPoints
Tight box for a collection of points.
============
*/
void idBox::FromPoints( const idVec3 *points, const int numPoints ) {
int i;
float invNumPoints, sumXX, sumXY, sumXZ, sumYY, sumYZ, sumZZ;
idVec3 dir;
idBounds bounds;
idMatX eigenVectors;
idVecX eigenValues;
// compute mean of points
center = points[0];
for ( i = 1; i < numPoints; i++ ) {
center += points[i];
}
invNumPoints = 1.0f / numPoints;
center *= invNumPoints;
// compute covariances of points
sumXX = 0.0f; sumXY = 0.0f; sumXZ = 0.0f;
sumYY = 0.0f; sumYZ = 0.0f; sumZZ = 0.0f;
for ( i = 0; i < numPoints; i++ ) {
dir = points[i] - center;
sumXX += dir.x * dir.x;
sumXY += dir.x * dir.y;
sumXZ += dir.x * dir.z;
sumYY += dir.y * dir.y;
sumYZ += dir.y * dir.z;
sumZZ += dir.z * dir.z;
}
sumXX *= invNumPoints;
sumXY *= invNumPoints;
sumXZ *= invNumPoints;
sumYY *= invNumPoints;
sumYZ *= invNumPoints;
sumZZ *= invNumPoints;
// compute eigenvectors for covariance matrix
eigenValues.SetData( 3, VECX_ALLOCA( 3 ) );
eigenVectors.SetData( 3, 3, MATX_ALLOCA( 3 * 3 ) );
eigenVectors[0][0] = sumXX;
eigenVectors[0][1] = sumXY;
eigenVectors[0][2] = sumXZ;
eigenVectors[1][0] = sumXY;
eigenVectors[1][1] = sumYY;
eigenVectors[1][2] = sumYZ;
eigenVectors[2][0] = sumXZ;
eigenVectors[2][1] = sumYZ;
eigenVectors[2][2] = sumZZ;
eigenVectors.Eigen_SolveSymmetric( eigenValues );
eigenVectors.Eigen_SortIncreasing( eigenValues );
axis[0][0] = eigenVectors[0][0];
axis[0][1] = eigenVectors[0][1];
axis[0][2] = eigenVectors[0][2];
axis[1][0] = eigenVectors[1][0];
axis[1][1] = eigenVectors[1][1];
axis[1][2] = eigenVectors[1][2];
axis[2][0] = eigenVectors[2][0];
axis[2][1] = eigenVectors[2][1];
axis[2][2] = eigenVectors[2][2];
extents[0] = eigenValues[0];
extents[1] = eigenValues[0];
extents[2] = eigenValues[0];
// refine by calculating the bounds of the points projected onto the axis and adjusting the center and extents
bounds.Clear();
for ( i = 0; i < numPoints; i++ ) {
bounds.AddPoint( idVec3( points[i] * axis[0], points[i] * axis[1], points[i] * axis[2] ) );
}
center = ( bounds[0] + bounds[1] ) * 0.5f;
extents = bounds[1] - center;
center *= axis;
}
/*
============
idBox::FromPointTranslation
Most tight box for the translational movement of the given point.
============
*/
void idBox::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
// FIXME: implement
}
/*
============
idBox::FromBoxTranslation
Most tight box for the translational movement of the given box.
============
*/
void idBox::FromBoxTranslation( const idBox &box, const idVec3 &translation ) {
// FIXME: implement
}
/*
============
idBox::FromPointRotation
Most tight bounds for the rotational movement of the given point.
============
*/
void idBox::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
// FIXME: implement
}
/*
============
idBox::FromBoxRotation
Most tight box for the rotational movement of the given box.
============
*/
void idBox::FromBoxRotation( const idBox &box, const idRotation &rotation ) {
// FIXME: implement
}
/*
============
idBox::ToPoints
============
*/
void idBox::ToPoints( idVec3 points[8] ) const {
idMat3 ax;
idVec3 temp[4];
ax[0] = extents[0] * axis[0];
ax[1] = extents[1] * axis[1];
ax[2] = extents[2] * axis[2];
temp[0] = center - ax[0];
temp[1] = center + ax[0];
temp[2] = ax[1] - ax[2];
temp[3] = ax[1] + ax[2];
points[0] = temp[0] - temp[3];
points[1] = temp[1] - temp[3];
points[2] = temp[1] + temp[2];
points[3] = temp[0] + temp[2];
points[4] = temp[0] - temp[2];
points[5] = temp[1] - temp[2];
points[6] = temp[1] + temp[3];
points[7] = temp[0] + temp[3];
}
/*
============
idBox::GetProjectionSilhouetteVerts
============
*/
int idBox::GetProjectionSilhouetteVerts( const idVec3 &projectionOrigin, idVec3 silVerts[6] ) const {
float f;
int i, planeBits, *index;
idVec3 points[8], dir1, dir2;
ToPoints( points );
dir1 = points[0] - projectionOrigin;
dir2 = points[6] - projectionOrigin;
f = dir1 * axis[0];
planeBits = IEEE_FLT_SIGNBITNOTSET( f );
f = dir2 * axis[0];
planeBits |= IEEE_FLT_SIGNBITSET( f ) << 1;
f = dir1 * axis[1];
planeBits |= IEEE_FLT_SIGNBITNOTSET( f ) << 2;
f = dir2 * axis[1];
planeBits |= IEEE_FLT_SIGNBITSET( f ) << 3;
f = dir1 * axis[2];
planeBits |= IEEE_FLT_SIGNBITNOTSET( f ) << 4;
f = dir2 * axis[2];
planeBits |= IEEE_FLT_SIGNBITSET( f ) << 5;
index = boxPlaneBitsSilVerts[planeBits];
for ( i = 0; i < index[0]; i++ ) {
silVerts[i] = points[index[i+1]];
}
return index[0];
}
/*
============
idBox::GetParallelProjectionSilhouetteVerts
============
*/
int idBox::GetParallelProjectionSilhouetteVerts( const idVec3 &projectionDir, idVec3 silVerts[6] ) const {
float f;
int i, planeBits, *index;
idVec3 points[8];
ToPoints( points );
planeBits = 0;
f = projectionDir * axis[0];
if ( IEEE_FLT_ISNOTZERO( f ) ) {
planeBits = 1 << IEEE_FLT_SIGNBITSET( f );
}
f = projectionDir * axis[1];
if ( IEEE_FLT_ISNOTZERO( f ) ) {
planeBits |= 4 << IEEE_FLT_SIGNBITSET( f );
}
f = projectionDir * axis[2];
if ( IEEE_FLT_ISNOTZERO( f ) ) {
planeBits |= 16 << IEEE_FLT_SIGNBITSET( f );
}
index = boxPlaneBitsSilVerts[planeBits];
for ( i = 0; i < index[0]; i++ ) {
silVerts[i] = points[index[i+1]];
}
return index[0];
}

297
neo/idlib/bv/Box.h Normal file
View File

@@ -0,0 +1,297 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#ifndef __BV_BOX_H__
#define __BV_BOX_H__
/*
===============================================================================
Oriented Bounding Box
===============================================================================
*/
class idBox {
public:
idBox();
explicit idBox( const idVec3 &center, const idVec3 &extents, const idMat3 &axis );
explicit idBox( const idVec3 &point );
explicit idBox( const idBounds &bounds );
explicit idBox( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis );
idBox operator+( const idVec3 &t ) const; // returns translated box
idBox & operator+=( const idVec3 &t ); // translate the box
idBox operator*( const idMat3 &r ) const; // returns rotated box
idBox & operator*=( const idMat3 &r ); // rotate the box
idBox operator+( const idBox &a ) const;
idBox & operator+=( const idBox &a );
idBox operator-( const idBox &a ) const;
idBox & operator-=( const idBox &a );
bool Compare( const idBox &a ) const; // exact compare, no epsilon
bool Compare( const idBox &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idBox &a ) const; // exact compare, no epsilon
bool operator!=( const idBox &a ) const; // exact compare, no epsilon
void Clear(); // inside out box
void Zero(); // single point at origin
const idVec3 & GetCenter() const; // returns center of the box
const idVec3 & GetExtents() const; // returns extents of the box
const idMat3 & GetAxis() const; // returns the axis of the box
float GetVolume() const; // returns the volume of the box
bool IsCleared() const; // returns true if box are inside out
bool AddPoint( const idVec3 &v ); // add the point, returns true if the box expanded
bool AddBox( const idBox &a ); // add the box, returns true if the box expanded
idBox Expand( const float d ) const; // return box expanded in all directions with the given value
idBox & ExpandSelf( const float d ); // expand box in all directions with the given value
idBox Translate( const idVec3 &translation ) const; // return translated box
idBox & TranslateSelf( const idVec3 &translation ); // translate this box
idBox Rotate( const idMat3 &rotation ) const; // return rotated box
idBox & RotateSelf( const idMat3 &rotation ); // rotate this box
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool ContainsPoint( const idVec3 &p ) const; // includes touching
bool IntersectsBox( const idBox &a ) const; // includes touching
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
// intersection points are (start + dir * scale1) and (start + dir * scale2)
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
// tight box for a collection of points
void FromPoints( const idVec3 *points, const int numPoints );
// most tight box for a translation
void FromPointTranslation( const idVec3 &point, const idVec3 &translation );
void FromBoxTranslation( const idBox &box, const idVec3 &translation );
// most tight box for a rotation
void FromPointRotation( const idVec3 &point, const idRotation &rotation );
void FromBoxRotation( const idBox &box, const idRotation &rotation );
void ToPoints( idVec3 points[8] ) const;
idSphere ToSphere() const;
// calculates the projection of this box onto the given axis
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
void AxisProjection( const idMat3 &ax, idBounds &bounds ) const;
// calculates the silhouette of the box
int GetProjectionSilhouetteVerts( const idVec3 &projectionOrigin, idVec3 silVerts[6] ) const;
int GetParallelProjectionSilhouetteVerts( const idVec3 &projectionDir, idVec3 silVerts[6] ) const;
private:
idVec3 center;
idVec3 extents;
idMat3 axis;
};
extern idBox box_zero;
ID_INLINE idBox::idBox() {
}
ID_INLINE idBox::idBox( const idVec3 &center, const idVec3 &extents, const idMat3 &axis ) {
this->center = center;
this->extents = extents;
this->axis = axis;
}
ID_INLINE idBox::idBox( const idVec3 &point ) {
this->center = point;
this->extents.Zero();
this->axis.Identity();
}
ID_INLINE idBox::idBox( const idBounds &bounds ) {
this->center = ( bounds[0] + bounds[1] ) * 0.5f;
this->extents = bounds[1] - this->center;
this->axis.Identity();
}
ID_INLINE idBox::idBox( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis ) {
this->center = ( bounds[0] + bounds[1] ) * 0.5f;
this->extents = bounds[1] - this->center;
this->center = origin + this->center * axis;
this->axis = axis;
}
ID_INLINE idBox idBox::operator+( const idVec3 &t ) const {
return idBox( center + t, extents, axis );
}
ID_INLINE idBox &idBox::operator+=( const idVec3 &t ) {
center += t;
return *this;
}
ID_INLINE idBox idBox::operator*( const idMat3 &r ) const {
return idBox( center * r, extents, axis * r );
}
ID_INLINE idBox &idBox::operator*=( const idMat3 &r ) {
center *= r;
axis *= r;
return *this;
}
ID_INLINE idBox idBox::operator+( const idBox &a ) const {
idBox newBox;
newBox = *this;
newBox.AddBox( a );
return newBox;
}
ID_INLINE idBox &idBox::operator+=( const idBox &a ) {
idBox::AddBox( a );
return *this;
}
ID_INLINE idBox idBox::operator-( const idBox &a ) const {
return idBox( center, extents - a.extents, axis );
}
ID_INLINE idBox &idBox::operator-=( const idBox &a ) {
extents -= a.extents;
return *this;
}
ID_INLINE bool idBox::Compare( const idBox &a ) const {
return ( center.Compare( a.center ) && extents.Compare( a.extents ) && axis.Compare( a.axis ) );
}
ID_INLINE bool idBox::Compare( const idBox &a, const float epsilon ) const {
return ( center.Compare( a.center, epsilon ) && extents.Compare( a.extents, epsilon ) && axis.Compare( a.axis, epsilon ) );
}
ID_INLINE bool idBox::operator==( const idBox &a ) const {
return Compare( a );
}
ID_INLINE bool idBox::operator!=( const idBox &a ) const {
return !Compare( a );
}
ID_INLINE void idBox::Clear() {
center.Zero();
extents[0] = extents[1] = extents[2] = -idMath::INFINITY;
axis.Identity();
}
ID_INLINE void idBox::Zero() {
center.Zero();
extents.Zero();
axis.Identity();
}
ID_INLINE const idVec3 &idBox::GetCenter() const {
return center;
}
ID_INLINE const idVec3 &idBox::GetExtents() const {
return extents;
}
ID_INLINE const idMat3 &idBox::GetAxis() const {
return axis;
}
ID_INLINE float idBox::GetVolume() const {
return ( extents * 2.0f ).LengthSqr();
}
ID_INLINE bool idBox::IsCleared() const {
return extents[0] < 0.0f;
}
ID_INLINE idBox idBox::Expand( const float d ) const {
return idBox( center, extents + idVec3( d, d, d ), axis );
}
ID_INLINE idBox &idBox::ExpandSelf( const float d ) {
extents[0] += d;
extents[1] += d;
extents[2] += d;
return *this;
}
ID_INLINE idBox idBox::Translate( const idVec3 &translation ) const {
return idBox( center + translation, extents, axis );
}
ID_INLINE idBox &idBox::TranslateSelf( const idVec3 &translation ) {
center += translation;
return *this;
}
ID_INLINE idBox idBox::Rotate( const idMat3 &rotation ) const {
return idBox( center * rotation, extents, axis * rotation );
}
ID_INLINE idBox &idBox::RotateSelf( const idMat3 &rotation ) {
center *= rotation;
axis *= rotation;
return *this;
}
ID_INLINE bool idBox::ContainsPoint( const idVec3 &p ) const {
idVec3 lp = p - center;
if ( idMath::Fabs( lp * axis[0] ) > extents[0] ||
idMath::Fabs( lp * axis[1] ) > extents[1] ||
idMath::Fabs( lp * axis[2] ) > extents[2] ) {
return false;
}
return true;
}
ID_INLINE idSphere idBox::ToSphere() const {
return idSphere( center, extents.Length() );
}
ID_INLINE void idBox::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
float d1 = dir * center;
float d2 = idMath::Fabs( extents[0] * ( dir * axis[0] ) ) +
idMath::Fabs( extents[1] * ( dir * axis[1] ) ) +
idMath::Fabs( extents[2] * ( dir * axis[2] ) );
min = d1 - d2;
max = d1 + d2;
}
ID_INLINE void idBox::AxisProjection( const idMat3 &ax, idBounds &bounds ) const {
for ( int i = 0; i < 3; i++ ) {
float d1 = ax[i] * center;
float d2 = idMath::Fabs( extents[0] * ( ax[i] * axis[0] ) ) +
idMath::Fabs( extents[1] * ( ax[i] * axis[1] ) ) +
idMath::Fabs( extents[2] * ( ax[i] * axis[2] ) );
bounds[0][i] = d1 - d2;
bounds[1][i] = d1 + d2;
}
}
#endif /* !__BV_BOX_H__ */

155
neo/idlib/bv/Sphere.cpp Normal file
View File

@@ -0,0 +1,155 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#pragma hdrstop
#include "../precompiled.h"
idSphere sphere_zero( vec3_zero, 0.0f );
/*
================
idSphere::PlaneDistance
================
*/
float idSphere::PlaneDistance( const idPlane &plane ) const {
float d;
d = plane.Distance( origin );
if ( d > radius ) {
return d - radius;
}
if ( d < -radius ) {
return d + radius;
}
return 0.0f;
}
/*
================
idSphere::PlaneSide
================
*/
int idSphere::PlaneSide( const idPlane &plane, const float epsilon ) const {
float d;
d = plane.Distance( origin );
if ( d > radius + epsilon ) {
return PLANESIDE_FRONT;
}
if ( d < -radius - epsilon ) {
return PLANESIDE_BACK;
}
return PLANESIDE_CROSS;
}
/*
============
idSphere::LineIntersection
Returns true if the line intersects the sphere between the start and end point.
============
*/
bool idSphere::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
idVec3 r, s, e;
float a;
s = start - origin;
e = end - origin;
r = e - s;
a = -s * r;
if ( a <= 0 ) {
return ( s * s < radius * radius );
}
else if ( a >= r * r ) {
return ( e * e < radius * radius );
}
else {
r = s + ( a / ( r * r ) ) * r;
return ( r * r < radius * radius );
}
}
/*
============
idSphere::RayIntersection
Returns true if the ray intersects the sphere.
The ray can intersect the sphere in both directions from the start point.
If start is inside the sphere then scale1 < 0 and scale2 > 0.
============
*/
bool idSphere::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
double a, b, c, d, sqrtd;
idVec3 p;
p = start - origin;
a = dir * dir;
b = dir * p;
c = p * p - radius * radius;
d = b * b - c * a;
if ( d < 0.0f ) {
return false;
}
sqrtd = idMath::Sqrt( d );
a = 1.0f / a;
scale1 = ( -b + sqrtd ) * a;
scale2 = ( -b - sqrtd ) * a;
return true;
}
/*
============
idSphere::FromPoints
Tight sphere for a point set.
============
*/
void idSphere::FromPoints( const idVec3 *points, const int numPoints ) {
int i;
float radiusSqr, dist;
idVec3 mins, maxs;
SIMDProcessor->MinMax( mins, maxs, points, numPoints );
origin = ( mins + maxs ) * 0.5f;
radiusSqr = 0.0f;
for ( i = 0; i < numPoints; i++ ) {
dist = ( points[i] - origin ).LengthSqr();
if ( dist > radiusSqr ) {
radiusSqr = dist;
}
}
radius = idMath::Sqrt( radiusSqr );
}

275
neo/idlib/bv/Sphere.h Normal file
View File

@@ -0,0 +1,275 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#ifndef __BV_SPHERE_H__
#define __BV_SPHERE_H__
/*
===============================================================================
Sphere
===============================================================================
*/
class idSphere {
public:
idSphere();
explicit idSphere( const idVec3 &point );
explicit idSphere( const idVec3 &point, const float r );
float operator[]( const int index ) const;
float & operator[]( const int index );
idSphere operator+( const idVec3 &t ) const; // returns tranlated sphere
idSphere & operator+=( const idVec3 &t ); // translate the sphere
idSphere operator+( const idSphere &s ) const;
idSphere & operator+=( const idSphere &s );
bool Compare( const idSphere &a ) const; // exact compare, no epsilon
bool Compare( const idSphere &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idSphere &a ) const; // exact compare, no epsilon
bool operator!=( const idSphere &a ) const; // exact compare, no epsilon
void Clear(); // inside out sphere
void Zero(); // single point at origin
void SetOrigin( const idVec3 &o ); // set origin of sphere
void SetRadius( const float r ); // set square radius
const idVec3 & GetOrigin() const; // returns origin of sphere
float GetRadius() const; // returns sphere radius
bool IsCleared() const; // returns true if sphere is inside out
bool AddPoint( const idVec3 &p ); // add the point, returns true if the sphere expanded
bool AddSphere( const idSphere &s ); // add the sphere, returns true if the sphere expanded
idSphere Expand( const float d ) const; // return bounds expanded in all directions with the given value
idSphere & ExpandSelf( const float d ); // expand bounds in all directions with the given value
idSphere Translate( const idVec3 &translation ) const;
idSphere & TranslateSelf( const idVec3 &translation );
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool ContainsPoint( const idVec3 &p ) const; // includes touching
bool IntersectsSphere( const idSphere &s ) const; // includes touching
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
// intersection points are (start + dir * scale1) and (start + dir * scale2)
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
// Tight sphere for a point set.
void FromPoints( const idVec3 *points, const int numPoints );
// Most tight sphere for a translation.
void FromPointTranslation( const idVec3 &point, const idVec3 &translation );
void FromSphereTranslation( const idSphere &sphere, const idVec3 &start, const idVec3 &translation );
// Most tight sphere for a rotation.
void FromPointRotation( const idVec3 &point, const idRotation &rotation );
void FromSphereRotation( const idSphere &sphere, const idVec3 &start, const idRotation &rotation );
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
private:
idVec3 origin;
float radius;
};
extern idSphere sphere_zero;
ID_INLINE idSphere::idSphere() {
}
ID_INLINE idSphere::idSphere( const idVec3 &point ) {
origin = point;
radius = 0.0f;
}
ID_INLINE idSphere::idSphere( const idVec3 &point, const float r ) {
origin = point;
radius = r;
}
ID_INLINE float idSphere::operator[]( const int index ) const {
return ((float *) &origin)[index];
}
ID_INLINE float &idSphere::operator[]( const int index ) {
return ((float *) &origin)[index];
}
ID_INLINE idSphere idSphere::operator+( const idVec3 &t ) const {
return idSphere( origin + t, radius );
}
ID_INLINE idSphere &idSphere::operator+=( const idVec3 &t ) {
origin += t;
return *this;
}
ID_INLINE bool idSphere::Compare( const idSphere &a ) const {
return ( origin.Compare( a.origin ) && radius == a.radius );
}
ID_INLINE bool idSphere::Compare( const idSphere &a, const float epsilon ) const {
return ( origin.Compare( a.origin, epsilon ) && idMath::Fabs( radius - a.radius ) <= epsilon );
}
ID_INLINE bool idSphere::operator==( const idSphere &a ) const {
return Compare( a );
}
ID_INLINE bool idSphere::operator!=( const idSphere &a ) const {
return !Compare( a );
}
ID_INLINE void idSphere::Clear() {
origin.Zero();
radius = -1.0f;
}
ID_INLINE void idSphere::Zero() {
origin.Zero();
radius = 0.0f;
}
ID_INLINE void idSphere::SetOrigin( const idVec3 &o ) {
origin = o;
}
ID_INLINE void idSphere::SetRadius( const float r ) {
radius = r;
}
ID_INLINE const idVec3 &idSphere::GetOrigin() const {
return origin;
}
ID_INLINE float idSphere::GetRadius() const {
return radius;
}
ID_INLINE bool idSphere::IsCleared() const {
return ( radius < 0.0f );
}
ID_INLINE bool idSphere::AddPoint( const idVec3 &p ) {
if ( radius < 0.0f ) {
origin = p;
radius = 0.0f;
return true;
}
else {
float r = ( p - origin ).LengthSqr();
if ( r > radius * radius ) {
r = idMath::Sqrt( r );
origin += ( p - origin ) * 0.5f * (1.0f - radius / r );
radius += 0.5f * ( r - radius );
return true;
}
return false;
}
}
ID_INLINE bool idSphere::AddSphere( const idSphere &s ) {
if ( radius < 0.0f ) {
origin = s.origin;
radius = s.radius;
return true;
}
else {
float r = ( s.origin - origin ).LengthSqr();
if ( r > ( radius + s.radius ) * ( radius + s.radius ) ) {
r = idMath::Sqrt( r );
origin += ( s.origin - origin ) * 0.5f * (1.0f - radius / ( r + s.radius ) );
radius += 0.5f * ( ( r + s.radius ) - radius );
return true;
}
return false;
}
}
ID_INLINE idSphere idSphere::Expand( const float d ) const {
return idSphere( origin, radius + d );
}
ID_INLINE idSphere &idSphere::ExpandSelf( const float d ) {
radius += d;
return *this;
}
ID_INLINE idSphere idSphere::Translate( const idVec3 &translation ) const {
return idSphere( origin + translation, radius );
}
ID_INLINE idSphere &idSphere::TranslateSelf( const idVec3 &translation ) {
origin += translation;
return *this;
}
ID_INLINE bool idSphere::ContainsPoint( const idVec3 &p ) const {
if ( ( p - origin ).LengthSqr() > radius * radius ) {
return false;
}
return true;
}
ID_INLINE bool idSphere::IntersectsSphere( const idSphere &s ) const {
float r = s.radius + radius;
if ( ( s.origin - origin ).LengthSqr() > r * r ) {
return false;
}
return true;
}
ID_INLINE void idSphere::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
origin = point + 0.5f * translation;
radius = idMath::Sqrt( 0.5f * translation.LengthSqr() );
}
ID_INLINE void idSphere::FromSphereTranslation( const idSphere &sphere, const idVec3 &start, const idVec3 &translation ) {
origin = start + sphere.origin + 0.5f * translation;
radius = idMath::Sqrt( 0.5f * translation.LengthSqr() ) + sphere.radius;
}
ID_INLINE void idSphere::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
idVec3 end = rotation * point;
origin = ( point + end ) * 0.5f;
radius = idMath::Sqrt( 0.5f * ( end - point ).LengthSqr() );
}
ID_INLINE void idSphere::FromSphereRotation( const idSphere &sphere, const idVec3 &start, const idRotation &rotation ) {
idVec3 end = rotation * sphere.origin;
origin = start + ( sphere.origin + end ) * 0.5f;
radius = idMath::Sqrt( 0.5f * ( end - sphere.origin ).LengthSqr() ) + sphere.radius;
}
ID_INLINE void idSphere::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
float d;
d = dir * origin;
min = d - radius;
max = d + radius;
}
#endif /* !__BV_SPHERE_H__ */