mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-12-02 17:22:32 +00:00
736ec20d4d
Don't include the lazy precompiled.h everywhere, only what's required for the compilation unit. platform.h needs to be included instead to provide all essential defines and types. All includes use the relative path to the neo or the game specific root. Move all idlib related includes from idlib/Lib.h to precompiled.h. precompiled.h still exists for the MFC stuff in tools/. Add some missing header guards.
850 lines
22 KiB
C++
850 lines
22 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
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 "sys/platform.h"
|
|
|
|
#include "idlib/bv/Box.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 = 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];
|
|
}
|