hello world

This commit is contained in:
Timothee 'TTimo' Besset
2011-11-22 15:28:15 -06:00
commit fb1609f554
2155 changed files with 1017022 additions and 0 deletions

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

@@ -0,0 +1,424 @@
/*
===========================================================================
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 &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 {
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];
}
}

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

@@ -0,0 +1,409 @@
/*
===========================================================================
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.
===========================================================================
*/
#ifndef __BV_BOUNDS_H__
#define __BV_BOUNDS_H__
/*
===============================================================================
Axis Aligned Bounding Box
===============================================================================
*/
class idBounds {
public:
idBounds( void );
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( void ); // inside out bounds
void Zero( void ); // single point at origin
idVec3 GetCenter( void ) const; // returns center of bounds
float GetRadius( void ) 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( void ) const; // returns the volume of the bounds
bool IsCleared( void ) 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( void ) 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;
private:
idVec3 b[2];
};
extern idBounds bounds_zero;
ID_INLINE idBounds::idBounds( void ) {
}
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( void ) {
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( void ) {
b[0][0] = b[0][1] = b[0][2] =
b[1][0] = b[1][1] = b[1][2] = 0;
}
ID_INLINE idVec3 idBounds::GetCenter( void ) 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( void ) 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( void ) 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( void ) 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;
}
#endif /* !__BV_BOUNDS_H__ */

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

@@ -0,0 +1,849 @@
/*
===========================================================================
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
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 = FLOATSIGNBITNOTSET( f );
f = dir2 * axis[0];
planeBits |= FLOATSIGNBITSET( f ) << 1;
f = dir1 * axis[1];
planeBits |= FLOATSIGNBITNOTSET( f ) << 2;
f = dir2 * axis[1];
planeBits |= FLOATSIGNBITSET( f ) << 3;
f = dir1 * axis[2];
planeBits |= FLOATSIGNBITNOTSET( f ) << 4;
f = dir2 * axis[2];
planeBits |= FLOATSIGNBITSET( 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 ( FLOATNOTZERO( f ) ) {
planeBits = 1 << FLOATSIGNBITSET( f );
}
f = projectionDir * axis[1];
if ( FLOATNOTZERO( f ) ) {
planeBits |= 4 << FLOATSIGNBITSET( f );
}
f = projectionDir * axis[2];
if ( FLOATNOTZERO( f ) ) {
planeBits |= 16 << FLOATSIGNBITSET( 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 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.
===========================================================================
*/
#ifndef __BV_BOX_H__
#define __BV_BOX_H__
/*
===============================================================================
Oriented Bounding Box
===============================================================================
*/
class idBox {
public:
idBox( void );
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( void ); // inside out box
void Zero( void ); // single point at origin
const idVec3 & GetCenter( void ) const; // returns center of the box
const idVec3 & GetExtents( void ) const; // returns extents of the box
const idMat3 & GetAxis( void ) const; // returns the axis of the box
float GetVolume( void ) const; // returns the volume of the box
bool IsCleared( void ) 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( void ) 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( void ) {
}
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( void ) {
center.Zero();
extents[0] = extents[1] = extents[2] = -idMath::INFINITY;
axis.Identity();
}
ID_INLINE void idBox::Zero( void ) {
center.Zero();
extents.Zero();
axis.Identity();
}
ID_INLINE const idVec3 &idBox::GetCenter( void ) const {
return center;
}
ID_INLINE const idVec3 &idBox::GetExtents( void ) const {
return extents;
}
ID_INLINE const idMat3 &idBox::GetAxis( void ) const {
return axis;
}
ID_INLINE float idBox::GetVolume( void ) const {
return ( extents * 2.0f ).LengthSqr();
}
ID_INLINE bool idBox::IsCleared( void ) 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( void ) 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__ */

2843
neo/idlib/bv/Frustum.cpp Normal file

File diff suppressed because it is too large Load Diff

265
neo/idlib/bv/Frustum.h Normal file
View File

@@ -0,0 +1,265 @@
/*
===========================================================================
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.
===========================================================================
*/
#ifndef __BV_FRUSTUM_H__
#define __BV_FRUSTUM_H__
/*
===============================================================================
Orthogonal Frustum
===============================================================================
*/
class idFrustum {
public:
idFrustum( void );
void SetOrigin( const idVec3 &origin );
void SetAxis( const idMat3 &axis );
void SetSize( float dNear, float dFar, float dLeft, float dUp );
void SetPyramid( float dNear, float dFar );
void MoveNearDistance( float dNear );
void MoveFarDistance( float dFar );
const idVec3 & GetOrigin( void ) const; // returns frustum origin
const idMat3 & GetAxis( void ) const; // returns frustum orientation
idVec3 GetCenter( void ) const; // returns center of frustum
bool IsValid( void ) const; // returns true if the frustum is valid
float GetNearDistance( void ) const; // returns distance to near plane
float GetFarDistance( void ) const; // returns distance to far plane
float GetLeft( void ) const; // returns left vector length
float GetUp( void ) const; // returns up vector length
idFrustum Expand( const float d ) const; // returns frustum expanded in all directions with the given value
idFrustum & ExpandSelf( const float d ); // expands frustum in all directions with the given value
idFrustum Translate( const idVec3 &translation ) const; // returns translated frustum
idFrustum & TranslateSelf( const idVec3 &translation ); // translates frustum
idFrustum Rotate( const idMat3 &rotation ) const; // returns rotated frustum
idFrustum & RotateSelf( const idMat3 &rotation ); // rotates frustum
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
// fast culling but might not cull everything outside the frustum
bool CullPoint( const idVec3 &point ) const;
bool CullBounds( const idBounds &bounds ) const;
bool CullBox( const idBox &box ) const;
bool CullSphere( const idSphere &sphere ) const;
bool CullFrustum( const idFrustum &frustum ) const;
bool CullWinding( const class idWinding &winding ) const;
// exact intersection tests
bool ContainsPoint( const idVec3 &point ) const;
bool IntersectsBounds( const idBounds &bounds ) const;
bool IntersectsBox( const idBox &box ) const;
bool IntersectsSphere( const idSphere &sphere ) const;
bool IntersectsFrustum( const idFrustum &frustum ) const;
bool IntersectsWinding( const idWinding &winding ) const;
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
// returns true if the projection origin is far enough away from the bounding volume to create a valid frustum
bool FromProjection( const idBounds &bounds, const idVec3 &projectionOrigin, const float dFar );
bool FromProjection( const idBox &box, const idVec3 &projectionOrigin, const float dFar );
bool FromProjection( const idSphere &sphere, const idVec3 &projectionOrigin, const float dFar );
// moves the far plane so it extends just beyond the bounding volume
bool ConstrainToBounds( const idBounds &bounds );
bool ConstrainToBox( const idBox &box );
bool ConstrainToSphere( const idSphere &sphere );
bool ConstrainToFrustum( const idFrustum &frustum );
void ToPlanes( idPlane planes[6] ) const; // planes point outwards
void ToPoints( idVec3 points[8] ) const; // 8 corners of the frustum
// calculates the projection of this frustum onto the given axis
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
void AxisProjection( const idMat3 &ax, idBounds &bounds ) const;
// calculates the bounds for the projection in this frustum
bool ProjectionBounds( const idBounds &bounds, idBounds &projectionBounds ) const;
bool ProjectionBounds( const idBox &box, idBounds &projectionBounds ) const;
bool ProjectionBounds( const idSphere &sphere, idBounds &projectionBounds ) const;
bool ProjectionBounds( const idFrustum &frustum, idBounds &projectionBounds ) const;
bool ProjectionBounds( const idWinding &winding, idBounds &projectionBounds ) const;
// calculates the bounds for the projection in this frustum of the given frustum clipped to the given box
bool ClippedProjectionBounds( const idFrustum &frustum, const idBox &clipBox, idBounds &projectionBounds ) const;
private:
idVec3 origin; // frustum origin
idMat3 axis; // frustum orientation
float dNear; // distance of near plane, dNear >= 0.0f
float dFar; // distance of far plane, dFar > dNear
float dLeft; // half the width at the far plane
float dUp; // half the height at the far plane
float invFar; // 1.0f / dFar
private:
bool CullLocalBox( const idVec3 &localOrigin, const idVec3 &extents, const idMat3 &localAxis ) const;
bool CullLocalFrustum( const idFrustum &localFrustum, const idVec3 indexPoints[8], const idVec3 cornerVecs[4] ) const;
bool CullLocalWinding( const idVec3 *points, const int numPoints, int *pointCull ) const;
bool BoundsCullLocalFrustum( const idBounds &bounds, const idFrustum &localFrustum, const idVec3 indexPoints[8], const idVec3 cornerVecs[4] ) const;
bool LocalLineIntersection( const idVec3 &start, const idVec3 &end ) const;
bool LocalRayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
bool LocalFrustumIntersectsFrustum( const idVec3 points[8], const bool testFirstSide ) const;
bool LocalFrustumIntersectsBounds( const idVec3 points[8], const idBounds &bounds ) const;
void ToClippedPoints( const float fractions[4], idVec3 points[8] ) const;
void ToIndexPoints( idVec3 indexPoints[8] ) const;
void ToIndexPointsAndCornerVecs( idVec3 indexPoints[8], idVec3 cornerVecs[4] ) const;
void AxisProjection( const idVec3 indexPoints[8], const idVec3 cornerVecs[4], const idVec3 &dir, float &min, float &max ) const;
void AddLocalLineToProjectionBoundsSetCull( const idVec3 &start, const idVec3 &end, int &startCull, int &endCull, idBounds &bounds ) const;
void AddLocalLineToProjectionBoundsUseCull( const idVec3 &start, const idVec3 &end, int startCull, int endCull, idBounds &bounds ) const;
bool AddLocalCapsToProjectionBounds( const idVec3 endPoints[4], const int endPointCull[4], const idVec3 &point, int pointCull, int pointClip, idBounds &projectionBounds ) const;
bool BoundsRayIntersection( const idBounds &bounds, const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
void ClipFrustumToBox( const idBox &box, float clipFractions[4], int clipPlanes[4] ) const;
bool ClipLine( const idVec3 localPoints[8], const idVec3 points[8], int startIndex, int endIndex, idVec3 &start, idVec3 &end, int &startClip, int &endClip ) const;
};
ID_INLINE idFrustum::idFrustum( void ) {
dNear = dFar = 0.0f;
}
ID_INLINE void idFrustum::SetOrigin( const idVec3 &origin ) {
this->origin = origin;
}
ID_INLINE void idFrustum::SetAxis( const idMat3 &axis ) {
this->axis = axis;
}
ID_INLINE void idFrustum::SetSize( float dNear, float dFar, float dLeft, float dUp ) {
assert( dNear >= 0.0f && dFar > dNear && dLeft > 0.0f && dUp > 0.0f );
this->dNear = dNear;
this->dFar = dFar;
this->dLeft = dLeft;
this->dUp = dUp;
this->invFar = 1.0f / dFar;
}
ID_INLINE void idFrustum::SetPyramid( float dNear, float dFar ) {
assert( dNear >= 0.0f && dFar > dNear );
this->dNear = dNear;
this->dFar = dFar;
this->dLeft = dFar;
this->dUp = dFar;
this->invFar = 1.0f / dFar;
}
ID_INLINE void idFrustum::MoveNearDistance( float dNear ) {
assert( dNear >= 0.0f );
this->dNear = dNear;
}
ID_INLINE void idFrustum::MoveFarDistance( float dFar ) {
assert( dFar > this->dNear );
float scale = dFar / this->dFar;
this->dFar = dFar;
this->dLeft *= scale;
this->dUp *= scale;
this->invFar = 1.0f / dFar;
}
ID_INLINE const idVec3 &idFrustum::GetOrigin( void ) const {
return origin;
}
ID_INLINE const idMat3 &idFrustum::GetAxis( void ) const {
return axis;
}
ID_INLINE idVec3 idFrustum::GetCenter( void ) const {
return ( origin + axis[0] * ( ( dFar - dNear ) * 0.5f ) );
}
ID_INLINE bool idFrustum::IsValid( void ) const {
return ( dFar > dNear );
}
ID_INLINE float idFrustum::GetNearDistance( void ) const {
return dNear;
}
ID_INLINE float idFrustum::GetFarDistance( void ) const {
return dFar;
}
ID_INLINE float idFrustum::GetLeft( void ) const {
return dLeft;
}
ID_INLINE float idFrustum::GetUp( void ) const {
return dUp;
}
ID_INLINE idFrustum idFrustum::Expand( const float d ) const {
idFrustum f = *this;
f.origin -= d * f.axis[0];
f.dFar += 2.0f * d;
f.dLeft = f.dFar * dLeft * invFar;
f.dUp = f.dFar * dUp * invFar;
f.invFar = 1.0f / dFar;
return f;
}
ID_INLINE idFrustum &idFrustum::ExpandSelf( const float d ) {
origin -= d * axis[0];
dFar += 2.0f * d;
dLeft = dFar * dLeft * invFar;
dUp = dFar * dUp * invFar;
invFar = 1.0f / dFar;
return *this;
}
ID_INLINE idFrustum idFrustum::Translate( const idVec3 &translation ) const {
idFrustum f = *this;
f.origin += translation;
return f;
}
ID_INLINE idFrustum &idFrustum::TranslateSelf( const idVec3 &translation ) {
origin += translation;
return *this;
}
ID_INLINE idFrustum idFrustum::Rotate( const idMat3 &rotation ) const {
idFrustum f = *this;
f.axis *= rotation;
return f;
}
ID_INLINE idFrustum &idFrustum::RotateSelf( const idMat3 &rotation ) {
axis *= rotation;
return *this;
}
#endif /* !__BV_FRUSTUM_H__ */

View File

@@ -0,0 +1,143 @@
/*
===========================================================================
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"
void BoxToPoints( const idVec3 &center, const idVec3 &extents, const idMat3 &axis, idVec3 points[8] );
/*
============
idFrustum::ProjectionBounds
============
*/
bool idFrustum::ProjectionBounds( const idBox &box, idBounds &projectionBounds ) const {
int i, p1, p2, pointCull[8], culled, outside;
float scale1, scale2;
idFrustum localFrustum;
idVec3 points[8], localOrigin;
idMat3 localAxis, localScaled;
idBounds bounds( -box.GetExtents(), box.GetExtents() );
// if the frustum origin is inside the bounds
if ( bounds.ContainsPoint( ( origin - box.GetCenter() ) * box.GetAxis().Transpose() ) ) {
// bounds that cover the whole frustum
float boxMin, boxMax, base;
base = origin * axis[0];
box.AxisProjection( axis[0], boxMin, boxMax );
projectionBounds[0].x = boxMin - base;
projectionBounds[1].x = boxMax - base;
projectionBounds[0].y = projectionBounds[0].z = -1.0f;
projectionBounds[1].y = projectionBounds[1].z = 1.0f;
return true;
}
projectionBounds.Clear();
// transform the bounds into the space of this frustum
localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
localAxis = box.GetAxis() * axis.Transpose();
BoxToPoints( localOrigin, box.GetExtents(), localAxis, points );
// test outer four edges of the bounds
culled = -1;
outside = 0;
for ( i = 0; i < 4; i++ ) {
p1 = i;
p2 = 4 + i;
AddLocalLineToProjectionBoundsSetCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
culled &= pointCull[p1] & pointCull[p2];
outside |= pointCull[p1] | pointCull[p2];
}
// if the bounds are completely outside this frustum
if ( culled ) {
return false;
}
// if the bounds are completely inside this frustum
if ( !outside ) {
return true;
}
// test the remaining edges of the bounds
for ( i = 0; i < 4; i++ ) {
p1 = i;
p2 = (i+1)&3;
AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
}
for ( i = 0; i < 4; i++ ) {
p1 = 4 + i;
p2 = 4 + ((i+1)&3);
AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
}
// if the bounds extend beyond two or more boundaries of this frustum
if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
localOrigin = ( origin - box.GetCenter() ) * box.GetAxis().Transpose();
localScaled = axis * box.GetAxis().Transpose();
localScaled[0] *= dFar;
localScaled[1] *= dLeft;
localScaled[2] *= dUp;
// test the outer edges of this frustum for intersection with the bounds
if ( (outside & 2) && (outside & 8) ) {
BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] - localScaled[2], scale1, scale2 );
if ( scale1 <= scale2 && scale1 >= 0.0f ) {
projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, -1.0f ) );
projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, -1.0f ) );
}
}
if ( (outside & 2) && (outside & 4) ) {
BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] + localScaled[2], scale1, scale2 );
if ( scale1 <= scale2 && scale1 >= 0.0f ) {
projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, 1.0f ) );
projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, 1.0f ) );
}
}
if ( (outside & 1) && (outside & 8) ) {
BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] - localScaled[2], scale1, scale2 );
if ( scale1 <= scale2 && scale1 >= 0.0f ) {
projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, -1.0f ) );
projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, -1.0f ) );
}
}
if ( (outside & 1) && (outside & 2) ) {
BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] + localScaled[2], scale1, scale2 );
if ( scale1 <= scale2 && scale1 >= 0.0f ) {
projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, 1.0f ) );
projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, 1.0f ) );
}
}
}
return true;
}

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

@@ -0,0 +1,155 @@
/*
===========================================================================
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
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 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.
===========================================================================
*/
#ifndef __BV_SPHERE_H__
#define __BV_SPHERE_H__
/*
===============================================================================
Sphere
===============================================================================
*/
class idSphere {
public:
idSphere( void );
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( void ); // inside out sphere
void Zero( void ); // single point at origin
void SetOrigin( const idVec3 &o ); // set origin of sphere
void SetRadius( const float r ); // set square radius
const idVec3 & GetOrigin( void ) const; // returns origin of sphere
float GetRadius( void ) const; // returns sphere radius
bool IsCleared( void ) 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( void ) {
}
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( void ) {
origin.Zero();
radius = -1.0f;
}
ID_INLINE void idSphere::Zero( void ) {
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( void ) const {
return origin;
}
ID_INLINE float idSphere::GetRadius( void ) const {
return radius;
}
ID_INLINE bool idSphere::IsCleared( void ) 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__ */