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

View File

@@ -0,0 +1,44 @@
/*
===========================================================================
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
/*
=============
idDrawVert::Normalize
=============
*/
void idDrawVert::Normalize( void ) {
normal.Normalize();
tangents[1].Cross( normal, tangents[0] );
tangents[1].Normalize();
tangents[0].Cross( tangents[1], normal );
tangents[0].Normalize();
}

View File

@@ -0,0 +1,107 @@
/*
===========================================================================
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 __DRAWVERT_H__
#define __DRAWVERT_H__
/*
===============================================================================
Draw Vertex.
===============================================================================
*/
class idDrawVert {
public:
idVec3 xyz;
idVec2 st;
idVec3 normal;
idVec3 tangents[2];
byte color[4];
#if 0 // was MACOS_X see comments concerning DRAWVERT_PADDED in Simd_Altivec.h
float padding;
#endif
float operator[]( const int index ) const;
float & operator[]( const int index );
void Clear( void );
void Lerp( const idDrawVert &a, const idDrawVert &b, const float f );
void LerpAll( const idDrawVert &a, const idDrawVert &b, const float f );
void Normalize( void );
void SetColor( dword color );
dword GetColor( void ) const;
};
ID_INLINE float idDrawVert::operator[]( const int index ) const {
assert( index >= 0 && index < 5 );
return ((float *)(&xyz))[index];
}
ID_INLINE float &idDrawVert::operator[]( const int index ) {
assert( index >= 0 && index < 5 );
return ((float *)(&xyz))[index];
}
ID_INLINE void idDrawVert::Clear( void ) {
xyz.Zero();
st.Zero();
normal.Zero();
tangents[0].Zero();
tangents[1].Zero();
color[0] = color[1] = color[2] = color[3] = 0;
}
ID_INLINE void idDrawVert::Lerp( const idDrawVert &a, const idDrawVert &b, const float f ) {
xyz = a.xyz + f * ( b.xyz - a.xyz );
st = a.st + f * ( b.st - a.st );
}
ID_INLINE void idDrawVert::LerpAll( const idDrawVert &a, const idDrawVert &b, const float f ) {
xyz = a.xyz + f * ( b.xyz - a.xyz );
st = a.st + f * ( b.st - a.st );
normal = a.normal + f * ( b.normal - a.normal );
tangents[0] = a.tangents[0] + f * ( b.tangents[0] - a.tangents[0] );
tangents[1] = a.tangents[1] + f * ( b.tangents[1] - a.tangents[1] );
color[0] = (byte)( a.color[0] + f * ( b.color[0] - a.color[0] ) );
color[1] = (byte)( a.color[1] + f * ( b.color[1] - a.color[1] ) );
color[2] = (byte)( a.color[2] + f * ( b.color[2] - a.color[2] ) );
color[3] = (byte)( a.color[3] + f * ( b.color[3] - a.color[3] ) );
}
ID_INLINE void idDrawVert::SetColor( dword color ) {
*reinterpret_cast<dword *>(this->color) = color;
}
ID_INLINE dword idDrawVert::GetColor( void ) const {
return *reinterpret_cast<const dword *>(this->color);
}
#endif /* !__DRAWVERT_H__ */

View File

@@ -0,0 +1,87 @@
/*
===========================================================================
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
/*
=============
idJointMat::ToJointQuat
=============
*/
idJointQuat idJointMat::ToJointQuat( void ) const {
idJointQuat jq;
float trace;
float s;
float t;
int i;
int j;
int k;
static int next[3] = { 1, 2, 0 };
trace = mat[0 * 4 + 0] + mat[1 * 4 + 1] + mat[2 * 4 + 2];
if ( trace > 0.0f ) {
t = trace + 1.0f;
s = idMath::InvSqrt( t ) * 0.5f;
jq.q[3] = s * t;
jq.q[0] = ( mat[1 * 4 + 2] - mat[2 * 4 + 1] ) * s;
jq.q[1] = ( mat[2 * 4 + 0] - mat[0 * 4 + 2] ) * s;
jq.q[2] = ( mat[0 * 4 + 1] - mat[1 * 4 + 0] ) * s;
} else {
i = 0;
if ( mat[1 * 4 + 1] > mat[0 * 4 + 0] ) {
i = 1;
}
if ( mat[2 * 4 + 2] > mat[i * 4 + i] ) {
i = 2;
}
j = next[i];
k = next[j];
t = ( mat[i * 4 + i] - ( mat[j * 4 + j] + mat[k * 4 + k] ) ) + 1.0f;
s = idMath::InvSqrt( t ) * 0.5f;
jq.q[i] = s * t;
jq.q[3] = ( mat[j * 4 + k] - mat[k * 4 + j] ) * s;
jq.q[j] = ( mat[i * 4 + j] + mat[j * 4 + i] ) * s;
jq.q[k] = ( mat[i * 4 + k] + mat[k * 4 + i] ) * s;
}
jq.t[0] = mat[0 * 4 + 3];
jq.t[1] = mat[1 * 4 + 3];
jq.t[2] = mat[2 * 4 + 3];
return jq;
}

View File

@@ -0,0 +1,245 @@
/*
===========================================================================
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 __JOINTTRANSFORM_H__
#define __JOINTTRANSFORM_H__
/*
===============================================================================
Joint Quaternion
===============================================================================
*/
class idJointQuat {
public:
idQuat q;
idVec3 t;
};
/*
===============================================================================
Joint Matrix
idMat3 m;
idVec3 t;
m[0][0], m[1][0], m[2][0], t[0]
m[0][1], m[1][1], m[2][1], t[1]
m[0][2], m[1][2], m[2][2], t[2]
===============================================================================
*/
class idJointMat {
public:
void SetRotation( const idMat3 &m );
void SetTranslation( const idVec3 &t );
idVec3 operator*( const idVec3 &v ) const; // only rotate
idVec3 operator*( const idVec4 &v ) const; // rotate and translate
idJointMat & operator*=( const idJointMat &a ); // transform
idJointMat & operator/=( const idJointMat &a ); // untransform
bool Compare( const idJointMat &a ) const; // exact compare, no epsilon
bool Compare( const idJointMat &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idJointMat &a ) const; // exact compare, no epsilon
bool operator!=( const idJointMat &a ) const; // exact compare, no epsilon
idMat3 ToMat3( void ) const;
idVec3 ToVec3( void ) const;
idJointQuat ToJointQuat( void ) const;
const float * ToFloatPtr( void ) const;
float * ToFloatPtr( void );
private:
float mat[3*4];
};
ID_INLINE void idJointMat::SetRotation( const idMat3 &m ) {
// NOTE: idMat3 is transposed because it is column-major
mat[0 * 4 + 0] = m[0][0];
mat[0 * 4 + 1] = m[1][0];
mat[0 * 4 + 2] = m[2][0];
mat[1 * 4 + 0] = m[0][1];
mat[1 * 4 + 1] = m[1][1];
mat[1 * 4 + 2] = m[2][1];
mat[2 * 4 + 0] = m[0][2];
mat[2 * 4 + 1] = m[1][2];
mat[2 * 4 + 2] = m[2][2];
}
ID_INLINE void idJointMat::SetTranslation( const idVec3 &t ) {
mat[0 * 4 + 3] = t[0];
mat[1 * 4 + 3] = t[1];
mat[2 * 4 + 3] = t[2];
}
ID_INLINE idVec3 idJointMat::operator*( const idVec3 &v ) const {
return idVec3( mat[0 * 4 + 0] * v[0] + mat[0 * 4 + 1] * v[1] + mat[0 * 4 + 2] * v[2],
mat[1 * 4 + 0] * v[0] + mat[1 * 4 + 1] * v[1] + mat[1 * 4 + 2] * v[2],
mat[2 * 4 + 0] * v[0] + mat[2 * 4 + 1] * v[1] + mat[2 * 4 + 2] * v[2] );
}
ID_INLINE idVec3 idJointMat::operator*( const idVec4 &v ) const {
return idVec3( mat[0 * 4 + 0] * v[0] + mat[0 * 4 + 1] * v[1] + mat[0 * 4 + 2] * v[2] + mat[0 * 4 + 3] * v[3],
mat[1 * 4 + 0] * v[0] + mat[1 * 4 + 1] * v[1] + mat[1 * 4 + 2] * v[2] + mat[1 * 4 + 3] * v[3],
mat[2 * 4 + 0] * v[0] + mat[2 * 4 + 1] * v[1] + mat[2 * 4 + 2] * v[2] + mat[2 * 4 + 3] * v[3] );
}
ID_INLINE idJointMat &idJointMat::operator*=( const idJointMat &a ) {
float dst[3];
dst[0] = mat[0 * 4 + 0] * a.mat[0 * 4 + 0] + mat[1 * 4 + 0] * a.mat[0 * 4 + 1] + mat[2 * 4 + 0] * a.mat[0 * 4 + 2];
dst[1] = mat[0 * 4 + 0] * a.mat[1 * 4 + 0] + mat[1 * 4 + 0] * a.mat[1 * 4 + 1] + mat[2 * 4 + 0] * a.mat[1 * 4 + 2];
dst[2] = mat[0 * 4 + 0] * a.mat[2 * 4 + 0] + mat[1 * 4 + 0] * a.mat[2 * 4 + 1] + mat[2 * 4 + 0] * a.mat[2 * 4 + 2];
mat[0 * 4 + 0] = dst[0];
mat[1 * 4 + 0] = dst[1];
mat[2 * 4 + 0] = dst[2];
dst[0] = mat[0 * 4 + 1] * a.mat[0 * 4 + 0] + mat[1 * 4 + 1] * a.mat[0 * 4 + 1] + mat[2 * 4 + 1] * a.mat[0 * 4 + 2];
dst[1] = mat[0 * 4 + 1] * a.mat[1 * 4 + 0] + mat[1 * 4 + 1] * a.mat[1 * 4 + 1] + mat[2 * 4 + 1] * a.mat[1 * 4 + 2];
dst[2] = mat[0 * 4 + 1] * a.mat[2 * 4 + 0] + mat[1 * 4 + 1] * a.mat[2 * 4 + 1] + mat[2 * 4 + 1] * a.mat[2 * 4 + 2];
mat[0 * 4 + 1] = dst[0];
mat[1 * 4 + 1] = dst[1];
mat[2 * 4 + 1] = dst[2];
dst[0] = mat[0 * 4 + 2] * a.mat[0 * 4 + 0] + mat[1 * 4 + 2] * a.mat[0 * 4 + 1] + mat[2 * 4 + 2] * a.mat[0 * 4 + 2];
dst[1] = mat[0 * 4 + 2] * a.mat[1 * 4 + 0] + mat[1 * 4 + 2] * a.mat[1 * 4 + 1] + mat[2 * 4 + 2] * a.mat[1 * 4 + 2];
dst[2] = mat[0 * 4 + 2] * a.mat[2 * 4 + 0] + mat[1 * 4 + 2] * a.mat[2 * 4 + 1] + mat[2 * 4 + 2] * a.mat[2 * 4 + 2];
mat[0 * 4 + 2] = dst[0];
mat[1 * 4 + 2] = dst[1];
mat[2 * 4 + 2] = dst[2];
dst[0] = mat[0 * 4 + 3] * a.mat[0 * 4 + 0] + mat[1 * 4 + 3] * a.mat[0 * 4 + 1] + mat[2 * 4 + 3] * a.mat[0 * 4 + 2];
dst[1] = mat[0 * 4 + 3] * a.mat[1 * 4 + 0] + mat[1 * 4 + 3] * a.mat[1 * 4 + 1] + mat[2 * 4 + 3] * a.mat[1 * 4 + 2];
dst[2] = mat[0 * 4 + 3] * a.mat[2 * 4 + 0] + mat[1 * 4 + 3] * a.mat[2 * 4 + 1] + mat[2 * 4 + 3] * a.mat[2 * 4 + 2];
mat[0 * 4 + 3] = dst[0];
mat[1 * 4 + 3] = dst[1];
mat[2 * 4 + 3] = dst[2];
mat[0 * 4 + 3] += a.mat[0 * 4 + 3];
mat[1 * 4 + 3] += a.mat[1 * 4 + 3];
mat[2 * 4 + 3] += a.mat[2 * 4 + 3];
return *this;
}
ID_INLINE idJointMat &idJointMat::operator/=( const idJointMat &a ) {
float dst[3];
mat[0 * 4 + 3] -= a.mat[0 * 4 + 3];
mat[1 * 4 + 3] -= a.mat[1 * 4 + 3];
mat[2 * 4 + 3] -= a.mat[2 * 4 + 3];
dst[0] = mat[0 * 4 + 0] * a.mat[0 * 4 + 0] + mat[1 * 4 + 0] * a.mat[1 * 4 + 0] + mat[2 * 4 + 0] * a.mat[2 * 4 + 0];
dst[1] = mat[0 * 4 + 0] * a.mat[0 * 4 + 1] + mat[1 * 4 + 0] * a.mat[1 * 4 + 1] + mat[2 * 4 + 0] * a.mat[2 * 4 + 1];
dst[2] = mat[0 * 4 + 0] * a.mat[0 * 4 + 2] + mat[1 * 4 + 0] * a.mat[1 * 4 + 2] + mat[2 * 4 + 0] * a.mat[2 * 4 + 2];
mat[0 * 4 + 0] = dst[0];
mat[1 * 4 + 0] = dst[1];
mat[2 * 4 + 0] = dst[2];
dst[0] = mat[0 * 4 + 1] * a.mat[0 * 4 + 0] + mat[1 * 4 + 1] * a.mat[1 * 4 + 0] + mat[2 * 4 + 1] * a.mat[2 * 4 + 0];
dst[1] = mat[0 * 4 + 1] * a.mat[0 * 4 + 1] + mat[1 * 4 + 1] * a.mat[1 * 4 + 1] + mat[2 * 4 + 1] * a.mat[2 * 4 + 1];
dst[2] = mat[0 * 4 + 1] * a.mat[0 * 4 + 2] + mat[1 * 4 + 1] * a.mat[1 * 4 + 2] + mat[2 * 4 + 1] * a.mat[2 * 4 + 2];
mat[0 * 4 + 1] = dst[0];
mat[1 * 4 + 1] = dst[1];
mat[2 * 4 + 1] = dst[2];
dst[0] = mat[0 * 4 + 2] * a.mat[0 * 4 + 0] + mat[1 * 4 + 2] * a.mat[1 * 4 + 0] + mat[2 * 4 + 2] * a.mat[2 * 4 + 0];
dst[1] = mat[0 * 4 + 2] * a.mat[0 * 4 + 1] + mat[1 * 4 + 2] * a.mat[1 * 4 + 1] + mat[2 * 4 + 2] * a.mat[2 * 4 + 1];
dst[2] = mat[0 * 4 + 2] * a.mat[0 * 4 + 2] + mat[1 * 4 + 2] * a.mat[1 * 4 + 2] + mat[2 * 4 + 2] * a.mat[2 * 4 + 2];
mat[0 * 4 + 2] = dst[0];
mat[1 * 4 + 2] = dst[1];
mat[2 * 4 + 2] = dst[2];
dst[0] = mat[0 * 4 + 3] * a.mat[0 * 4 + 0] + mat[1 * 4 + 3] * a.mat[1 * 4 + 0] + mat[2 * 4 + 3] * a.mat[2 * 4 + 0];
dst[1] = mat[0 * 4 + 3] * a.mat[0 * 4 + 1] + mat[1 * 4 + 3] * a.mat[1 * 4 + 1] + mat[2 * 4 + 3] * a.mat[2 * 4 + 1];
dst[2] = mat[0 * 4 + 3] * a.mat[0 * 4 + 2] + mat[1 * 4 + 3] * a.mat[1 * 4 + 2] + mat[2 * 4 + 3] * a.mat[2 * 4 + 2];
mat[0 * 4 + 3] = dst[0];
mat[1 * 4 + 3] = dst[1];
mat[2 * 4 + 3] = dst[2];
return *this;
}
ID_INLINE bool idJointMat::Compare( const idJointMat &a ) const {
int i;
for ( i = 0; i < 12; i++ ) {
if ( mat[i] != a.mat[i] ) {
return false;
}
}
return true;
}
ID_INLINE bool idJointMat::Compare( const idJointMat &a, const float epsilon ) const {
int i;
for ( i = 0; i < 12; i++ ) {
if ( idMath::Fabs( mat[i] - a.mat[i] ) > epsilon ) {
return false;
}
}
return true;
}
ID_INLINE bool idJointMat::operator==( const idJointMat &a ) const {
return Compare( a );
}
ID_INLINE bool idJointMat::operator!=( const idJointMat &a ) const {
return !Compare( a );
}
ID_INLINE idMat3 idJointMat::ToMat3( void ) const {
return idMat3( mat[0 * 4 + 0], mat[1 * 4 + 0], mat[2 * 4 + 0],
mat[0 * 4 + 1], mat[1 * 4 + 1], mat[2 * 4 + 1],
mat[0 * 4 + 2], mat[1 * 4 + 2], mat[2 * 4 + 2] );
}
ID_INLINE idVec3 idJointMat::ToVec3( void ) const {
return idVec3( mat[0 * 4 + 3], mat[1 * 4 + 3], mat[2 * 4 + 3] );
}
ID_INLINE const float *idJointMat::ToFloatPtr( void ) const {
return mat;
}
ID_INLINE float *idJointMat::ToFloatPtr( void ) {
return mat;
}
#endif /* !__JOINTTRANSFORM_H__ */

View File

@@ -0,0 +1,930 @@
/*
===========================================================================
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
/*
=================
UpdateVertexIndex
=================
*/
ID_INLINE int UpdateVertexIndex( int vertexIndexNum[2], int *vertexRemap, int *vertexCopyIndex, int vertNum ) {
int s = INTSIGNBITSET( vertexRemap[vertNum] );
vertexIndexNum[0] = vertexRemap[vertNum];
vertexRemap[vertNum] = vertexIndexNum[s];
vertexIndexNum[1] += s;
vertexCopyIndex[vertexRemap[vertNum]] = vertNum;
return vertexRemap[vertNum];
}
/*
=================
idSurface::Split
=================
*/
int idSurface::Split( const idPlane &plane, const float epsilon, idSurface **front, idSurface **back, int *frontOnPlaneEdges, int *backOnPlaneEdges ) const {
float * dists;
float f;
byte * sides;
int counts[3];
int * edgeSplitVertex;
int numEdgeSplitVertexes;
int * vertexRemap[2];
int vertexIndexNum[2][2];
int * vertexCopyIndex[2];
int * indexPtr[2];
int indexNum[2];
int * index;
int * onPlaneEdges[2];
int numOnPlaneEdges[2];
int maxOnPlaneEdges;
int i;
idSurface * surface[2];
idDrawVert v;
dists = (float *) _alloca( verts.Num() * sizeof( float ) );
sides = (byte *) _alloca( verts.Num() * sizeof( byte ) );
counts[0] = counts[1] = counts[2] = 0;
// determine side for each vertex
for ( i = 0; i < verts.Num(); i++ ) {
dists[i] = f = plane.Distance( verts[i].xyz );
if ( f > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( f < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
*front = *back = NULL;
// if coplanar, put on the front side if the normals match
if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
f = ( verts[indexes[1]].xyz - verts[indexes[0]].xyz ).Cross( verts[indexes[0]].xyz - verts[indexes[2]].xyz ) * plane.Normal();
if ( FLOATSIGNBITSET( f ) ) {
*back = new idSurface( *this );
return SIDE_BACK;
} else {
*front = new idSurface( *this );
return SIDE_FRONT;
}
}
// if nothing at the front of the clipping plane
if ( !counts[SIDE_FRONT] ) {
*back = new idSurface( *this );
return SIDE_BACK;
}
// if nothing at the back of the clipping plane
if ( !counts[SIDE_BACK] ) {
*front = new idSurface( *this );
return SIDE_FRONT;
}
// allocate front and back surface
*front = surface[0] = new idSurface();
*back = surface[1] = new idSurface();
edgeSplitVertex = (int *) _alloca( edges.Num() * sizeof( int ) );
numEdgeSplitVertexes = 0;
maxOnPlaneEdges = 4 * counts[SIDE_ON];
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
// split edges
for ( i = 0; i < edges.Num(); i++ ) {
int v0 = edges[i].verts[0];
int v1 = edges[i].verts[1];
int sidesOr = ( sides[v0] | sides[v1] );
// if both vertexes are on the same side or one is on the clipping plane
if ( !( sides[v0] ^ sides[v1] ) || ( sidesOr & SIDE_ON ) ) {
edgeSplitVertex[i] = -1;
counts[sidesOr & SIDE_BACK]++;
counts[SIDE_ON] += ( sidesOr & SIDE_ON ) >> 1;
} else {
f = dists[v0] / ( dists[v0] - dists[v1] );
v.LerpAll( verts[v0], verts[v1], f );
edgeSplitVertex[i] = numEdgeSplitVertexes++;
surface[0]->verts.Append( v );
surface[1]->verts.Append( v );
}
}
// each edge is shared by at most two triangles, as such there can never be more indexes than twice the number of edges
surface[0]->indexes.Resize( ( ( counts[SIDE_FRONT] + counts[SIDE_ON] ) * 2 ) + ( numEdgeSplitVertexes * 4 ) );
surface[1]->indexes.Resize( ( ( counts[SIDE_BACK] + counts[SIDE_ON] ) * 2 ) + ( numEdgeSplitVertexes * 4 ) );
// allocate indexes to construct the triangle indexes for the front and back surface
vertexRemap[0] = (int *) _alloca( verts.Num() * sizeof( int ) );
memset( vertexRemap[0], -1, verts.Num() * sizeof( int ) );
vertexRemap[1] = (int *) _alloca( verts.Num() * sizeof( int ) );
memset( vertexRemap[1], -1, verts.Num() * sizeof( int ) );
vertexCopyIndex[0] = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
vertexCopyIndex[1] = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
vertexIndexNum[0][0] = vertexIndexNum[1][0] = 0;
vertexIndexNum[0][1] = vertexIndexNum[1][1] = numEdgeSplitVertexes;
indexPtr[0] = surface[0]->indexes.Ptr();
indexPtr[1] = surface[1]->indexes.Ptr();
indexNum[0] = surface[0]->indexes.Num();
indexNum[1] = surface[1]->indexes.Num();
maxOnPlaneEdges += 4 * numEdgeSplitVertexes;
// allocate one more in case no triangles are actually split which may happen for a disconnected surface
onPlaneEdges[0] = (int *) _alloca( ( maxOnPlaneEdges + 1 ) * sizeof( int ) );
onPlaneEdges[1] = (int *) _alloca( ( maxOnPlaneEdges + 1 ) * sizeof( int ) );
numOnPlaneEdges[0] = numOnPlaneEdges[1] = 0;
// split surface triangles
for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
int e0, e1, e2, v0, v1, v2, s, n;
e0 = abs( edgeIndexes[i+0] );
e1 = abs( edgeIndexes[i+1] );
e2 = abs( edgeIndexes[i+2] );
v0 = indexes[i+0];
v1 = indexes[i+1];
v2 = indexes[i+2];
switch( ( INTSIGNBITSET( edgeSplitVertex[e0] ) | ( INTSIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INTSIGNBITSET( edgeSplitVertex[e2] ) << 2 ) ) ^ 7 ) {
case 0: { // no edges split
if ( ( sides[v0] & sides[v1] & sides[v2] ) & SIDE_ON ) {
// coplanar
f = ( verts[v1].xyz - verts[v0].xyz ).Cross( verts[v0].xyz - verts[v2].xyz ) * plane.Normal();
s = FLOATSIGNBITSET( f );
} else {
s = ( sides[v0] | sides[v1] | sides[v2] ) & SIDE_BACK;
}
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]] = n;
numOnPlaneEdges[s] += ( sides[v0] & sides[v1] ) >> 1;
onPlaneEdges[s][numOnPlaneEdges[s]] = n+1;
numOnPlaneEdges[s] += ( sides[v1] & sides[v2] ) >> 1;
onPlaneEdges[s][numOnPlaneEdges[s]] = n+2;
numOnPlaneEdges[s] += ( sides[v2] & sides[v0] ) >> 1;
index = indexPtr[s];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
indexNum[s] = n;
break;
}
case 1: { // first edge split
s = sides[v0] & SIDE_BACK;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e0];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
indexNum[s] = n;
s ^= 1;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
index[n++] = edgeSplitVertex[e0];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
indexNum[s] = n;
break;
}
case 2: { // second edge split
s = sides[v1] & SIDE_BACK;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e1];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
indexNum[s] = n;
s ^= 1;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
index[n++] = edgeSplitVertex[e1];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
indexNum[s] = n;
break;
}
case 3: { // first and second edge split
s = sides[v1] & SIDE_BACK;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e1];
index[n++] = edgeSplitVertex[e0];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
indexNum[s] = n;
s ^= 1;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e0];
index[n++] = edgeSplitVertex[e1];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
index[n++] = edgeSplitVertex[e1];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
indexNum[s] = n;
break;
}
case 4: { // third edge split
s = sides[v2] & SIDE_BACK;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e2];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
indexNum[s] = n;
s ^= 1;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = edgeSplitVertex[e2];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
indexNum[s] = n;
break;
}
case 5: { // first and third edge split
s = sides[v0] & SIDE_BACK;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e0];
index[n++] = edgeSplitVertex[e2];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
indexNum[s] = n;
s ^= 1;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e2];
index[n++] = edgeSplitVertex[e0];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
index[n++] = edgeSplitVertex[e2];
indexNum[s] = n;
break;
}
case 6: { // second and third edge split
s = sides[v2] & SIDE_BACK;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e2];
index[n++] = edgeSplitVertex[e1];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
indexNum[s] = n;
s ^= 1;
n = indexNum[s];
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
index = indexPtr[s];
index[n++] = edgeSplitVertex[e1];
index[n++] = edgeSplitVertex[e2];
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
index[n++] = edgeSplitVertex[e2];
indexNum[s] = n;
break;
}
}
}
surface[0]->indexes.SetNum( indexNum[0], false );
surface[1]->indexes.SetNum( indexNum[1], false );
// copy vertexes
surface[0]->verts.SetNum( vertexIndexNum[0][1], false );
index = vertexCopyIndex[0];
for ( i = numEdgeSplitVertexes; i < surface[0]->verts.Num(); i++ ) {
surface[0]->verts[i] = verts[index[i]];
}
surface[1]->verts.SetNum( vertexIndexNum[1][1], false );
index = vertexCopyIndex[1];
for ( i = numEdgeSplitVertexes; i < surface[1]->verts.Num(); i++ ) {
surface[1]->verts[i] = verts[index[i]];
}
// generate edge indexes
surface[0]->GenerateEdgeIndexes();
surface[1]->GenerateEdgeIndexes();
if ( frontOnPlaneEdges ) {
memcpy( frontOnPlaneEdges, onPlaneEdges[0], numOnPlaneEdges[0] * sizeof( int ) );
frontOnPlaneEdges[numOnPlaneEdges[0]] = -1;
}
if ( backOnPlaneEdges ) {
memcpy( backOnPlaneEdges, onPlaneEdges[1], numOnPlaneEdges[1] * sizeof( int ) );
backOnPlaneEdges[numOnPlaneEdges[1]] = -1;
}
return SIDE_CROSS;
}
/*
=================
idSurface::ClipInPlace
=================
*/
bool idSurface::ClipInPlace( const idPlane &plane, const float epsilon, const bool keepOn ) {
float * dists;
float f;
byte * sides;
int counts[3];
int i;
int * edgeSplitVertex;
int * vertexRemap;
int vertexIndexNum[2];
int * vertexCopyIndex;
int * indexPtr;
int indexNum;
int numEdgeSplitVertexes;
idDrawVert v;
idList<idDrawVert> newVerts;
idList<int> newIndexes;
dists = (float *) _alloca( verts.Num() * sizeof( float ) );
sides = (byte *) _alloca( verts.Num() * sizeof( byte ) );
counts[0] = counts[1] = counts[2] = 0;
// determine side for each vertex
for ( i = 0; i < verts.Num(); i++ ) {
dists[i] = f = plane.Distance( verts[i].xyz );
if ( f > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( f < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
// if coplanar, put on the front side if the normals match
if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
f = ( verts[indexes[1]].xyz - verts[indexes[0]].xyz ).Cross( verts[indexes[0]].xyz - verts[indexes[2]].xyz ) * plane.Normal();
if ( FLOATSIGNBITSET( f ) ) {
Clear();
return false;
} else {
return true;
}
}
// if nothing at the front of the clipping plane
if ( !counts[SIDE_FRONT] ) {
Clear();
return false;
}
// if nothing at the back of the clipping plane
if ( !counts[SIDE_BACK] ) {
return true;
}
edgeSplitVertex = (int *) _alloca( edges.Num() * sizeof( int ) );
numEdgeSplitVertexes = 0;
counts[SIDE_FRONT] = counts[SIDE_BACK] = 0;
// split edges
for ( i = 0; i < edges.Num(); i++ ) {
int v0 = edges[i].verts[0];
int v1 = edges[i].verts[1];
// if both vertexes are on the same side or one is on the clipping plane
if ( !( sides[v0] ^ sides[v1] ) || ( ( sides[v0] | sides[v1] ) & SIDE_ON ) ) {
edgeSplitVertex[i] = -1;
counts[(sides[v0]|sides[v1]) & SIDE_BACK]++;
} else {
f = dists[v0] / ( dists[v0] - dists[v1] );
v.LerpAll( verts[v0], verts[v1], f );
edgeSplitVertex[i] = numEdgeSplitVertexes++;
newVerts.Append( v );
}
}
// each edge is shared by at most two triangles, as such there can never be
// more indexes than twice the number of edges
newIndexes.Resize( ( counts[SIDE_FRONT] << 1 ) + ( numEdgeSplitVertexes << 2 ) );
// allocate indexes to construct the triangle indexes for the front and back surface
vertexRemap = (int *) _alloca( verts.Num() * sizeof( int ) );
memset( vertexRemap, -1, verts.Num() * sizeof( int ) );
vertexCopyIndex = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
vertexIndexNum[0] = 0;
vertexIndexNum[1] = numEdgeSplitVertexes;
indexPtr = newIndexes.Ptr();
indexNum = newIndexes.Num();
// split surface triangles
for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
int e0, e1, e2, v0, v1, v2;
e0 = abs( edgeIndexes[i+0] );
e1 = abs( edgeIndexes[i+1] );
e2 = abs( edgeIndexes[i+2] );
v0 = indexes[i+0];
v1 = indexes[i+1];
v2 = indexes[i+2];
switch( ( INTSIGNBITSET( edgeSplitVertex[e0] ) | ( INTSIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INTSIGNBITSET( edgeSplitVertex[e2] ) << 2 ) ) ^ 7 ) {
case 0: { // no edges split
if ( ( sides[v0] | sides[v1] | sides[v2] ) & SIDE_BACK ) {
break;
}
if ( ( sides[v0] & sides[v1] & sides[v2] ) & SIDE_ON ) {
// coplanar
if ( !keepOn ) {
break;
}
f = ( verts[v1].xyz - verts[v0].xyz ).Cross( verts[v0].xyz - verts[v2].xyz ) * plane.Normal();
if ( FLOATSIGNBITSET( f ) ) {
break;
}
}
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
break;
}
case 1: { // first edge split
if ( !( sides[v0] & SIDE_BACK ) ) {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
indexPtr[indexNum++] = edgeSplitVertex[e0];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
} else {
indexPtr[indexNum++] = edgeSplitVertex[e0];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
}
break;
}
case 2: { // second edge split
if ( !( sides[v1] & SIDE_BACK ) ) {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = edgeSplitVertex[e1];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
} else {
indexPtr[indexNum++] = edgeSplitVertex[e1];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
}
break;
}
case 3: { // first and second edge split
if ( !( sides[v1] & SIDE_BACK ) ) {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = edgeSplitVertex[e1];
indexPtr[indexNum++] = edgeSplitVertex[e0];
} else {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
indexPtr[indexNum++] = edgeSplitVertex[e0];
indexPtr[indexNum++] = edgeSplitVertex[e1];
indexPtr[indexNum++] = edgeSplitVertex[e1];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
}
break;
}
case 4: { // third edge split
if ( !( sides[v2] & SIDE_BACK ) ) {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
indexPtr[indexNum++] = edgeSplitVertex[e2];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
} else {
indexPtr[indexNum++] = edgeSplitVertex[e2];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
}
break;
}
case 5: { // first and third edge split
if ( !( sides[v0] & SIDE_BACK ) ) {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
indexPtr[indexNum++] = edgeSplitVertex[e0];
indexPtr[indexNum++] = edgeSplitVertex[e2];
} else {
indexPtr[indexNum++] = edgeSplitVertex[e0];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = edgeSplitVertex[e2];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
indexPtr[indexNum++] = edgeSplitVertex[e2];
}
break;
}
case 6: { // second and third edge split
if ( !( sides[v2] & SIDE_BACK ) ) {
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
indexPtr[indexNum++] = edgeSplitVertex[e2];
indexPtr[indexNum++] = edgeSplitVertex[e1];
} else {
indexPtr[indexNum++] = edgeSplitVertex[e2];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = edgeSplitVertex[e1];
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
indexPtr[indexNum++] = edgeSplitVertex[e2];
}
break;
}
}
}
newIndexes.SetNum( indexNum, false );
// copy vertexes
newVerts.SetNum( vertexIndexNum[1], false );
for ( i = numEdgeSplitVertexes; i < newVerts.Num(); i++ ) {
newVerts[i] = verts[vertexCopyIndex[i]];
}
// copy back to this surface
indexes = newIndexes;
verts = newVerts;
GenerateEdgeIndexes();
return true;
}
/*
=============
idSurface::IsConnected
=============
*/
bool idSurface::IsConnected( void ) const {
int i, j, numIslands, numTris;
int queueStart, queueEnd;
int *queue, *islandNum;
int curTri, nextTri, edgeNum;
const int *index;
numIslands = 0;
numTris = indexes.Num() / 3;
islandNum = (int *) _alloca16( numTris * sizeof( int ) );
memset( islandNum, -1, numTris * sizeof( int ) );
queue = (int *) _alloca16( numTris * sizeof( int ) );
for ( i = 0; i < numTris; i++ ) {
if ( islandNum[i] != -1 ) {
continue;
}
queueStart = 0;
queueEnd = 1;
queue[0] = i;
islandNum[i] = numIslands;
for ( curTri = queue[queueStart]; queueStart < queueEnd; curTri = queue[++queueStart] ) {
index = &edgeIndexes[curTri * 3];
for ( j = 0; j < 3; j++ ) {
edgeNum = index[j];
nextTri = edges[abs(edgeNum)].tris[INTSIGNBITNOTSET(edgeNum)];
if ( nextTri == -1 ) {
continue;
}
nextTri /= 3;
if ( islandNum[nextTri] != -1 ) {
continue;
}
queue[queueEnd++] = nextTri;
islandNum[nextTri] = numIslands;
}
}
numIslands++;
}
return ( numIslands == 1 );
}
/*
=================
idSurface::IsClosed
=================
*/
bool idSurface::IsClosed( void ) const {
for ( int i = 0; i < edges.Num(); i++ ) {
if ( edges[i].tris[0] < 0 || edges[i].tris[1] < 0 ) {
return false;
}
}
return true;
}
/*
=============
idSurface::IsPolytope
=============
*/
bool idSurface::IsPolytope( const float epsilon ) const {
int i, j;
idPlane plane;
if ( !IsClosed() ) {
return false;
}
for ( i = 0; i < indexes.Num(); i += 3 ) {
plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
for ( j = 0; j < verts.Num(); j++ ) {
if ( plane.Side( verts[j].xyz, epsilon ) == SIDE_FRONT ) {
return false;
}
}
}
return true;
}
/*
=============
idSurface::PlaneDistance
=============
*/
float idSurface::PlaneDistance( const idPlane &plane ) const {
int i;
float d, min, max;
min = idMath::INFINITY;
max = -min;
for ( i = 0; i < verts.Num(); i++ ) {
d = plane.Distance( verts[i].xyz );
if ( d < min ) {
min = d;
if ( FLOATSIGNBITSET( min ) & FLOATSIGNBITNOTSET( max ) ) {
return 0.0f;
}
}
if ( d > max ) {
max = d;
if ( FLOATSIGNBITSET( min ) & FLOATSIGNBITNOTSET( max ) ) {
return 0.0f;
}
}
}
if ( FLOATSIGNBITNOTSET( min ) ) {
return min;
}
if ( FLOATSIGNBITSET( max ) ) {
return max;
}
return 0.0f;
}
/*
=============
idSurface::PlaneSide
=============
*/
int idSurface::PlaneSide( const idPlane &plane, const float epsilon ) const {
bool front, back;
int i;
float d;
front = false;
back = false;
for ( i = 0; i < verts.Num(); i++ ) {
d = plane.Distance( verts[i].xyz );
if ( d < -epsilon ) {
if ( front ) {
return SIDE_CROSS;
}
back = true;
continue;
}
else if ( d > epsilon ) {
if ( back ) {
return SIDE_CROSS;
}
front = true;
continue;
}
}
if ( back ) {
return SIDE_BACK;
}
if ( front ) {
return SIDE_FRONT;
}
return SIDE_ON;
}
/*
=================
idSurface::LineIntersection
=================
*/
bool idSurface::LineIntersection( const idVec3 &start, const idVec3 &end, bool backFaceCull ) const {
float scale;
RayIntersection( start, end - start, scale, false );
return ( scale >= 0.0f && scale <= 1.0f );
}
/*
=================
idSurface::RayIntersection
=================
*/
bool idSurface::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull ) const {
int i, i0, i1, i2, s0, s1, s2;
float d, s;
byte *sidedness;
idPluecker rayPl, pl;
idPlane plane;
sidedness = (byte *)_alloca( edges.Num() * sizeof(byte) );
scale = idMath::INFINITY;
rayPl.FromRay( start, dir );
// ray sidedness for edges
for ( i = 0; i < edges.Num(); i++ ) {
pl.FromLine( verts[ edges[i].verts[1] ].xyz, verts[ edges[i].verts[0] ].xyz );
d = pl.PermutedInnerProduct( rayPl );
sidedness[ i ] = FLOATSIGNBITSET( d );
}
// test triangles
for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
i0 = edgeIndexes[i+0];
i1 = edgeIndexes[i+1];
i2 = edgeIndexes[i+2];
s0 = sidedness[abs(i0)] ^ INTSIGNBITSET( i0 );
s1 = sidedness[abs(i1)] ^ INTSIGNBITSET( i1 );
s2 = sidedness[abs(i2)] ^ INTSIGNBITSET( i2 );
if ( s0 & s1 & s2 ) {
plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
plane.RayIntersection( start, dir, s );
if ( idMath::Fabs( s ) < idMath::Fabs( scale ) ) {
scale = s;
}
} else if ( !backFaceCull && !(s0 | s1 | s2) ) {
plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
plane.RayIntersection( start, dir, s );
if ( idMath::Fabs( s ) < idMath::Fabs( scale ) ) {
scale = s;
}
}
}
if ( idMath::Fabs( scale ) < idMath::INFINITY ) {
return true;
}
return false;
}
/*
=================
idSurface::GenerateEdgeIndexes
Assumes each edge is shared by at most two triangles.
=================
*/
void idSurface::GenerateEdgeIndexes( void ) {
int i, j, i0, i1, i2, s, v0, v1, edgeNum;
int *index, *vertexEdges, *edgeChain;
surfaceEdge_t e[3];
vertexEdges = (int *) _alloca16( verts.Num() * sizeof( int ) );
memset( vertexEdges, -1, verts.Num() * sizeof( int ) );
edgeChain = (int *) _alloca16( indexes.Num() * sizeof( int ) );
edgeIndexes.SetNum( indexes.Num(), true );
edges.Clear();
// the first edge is a dummy
e[0].verts[0] = e[0].verts[1] = e[0].tris[0] = e[0].tris[1] = 0;
edges.Append( e[0] );
for ( i = 0; i < indexes.Num(); i += 3 ) {
index = indexes.Ptr() + i;
// vertex numbers
i0 = index[0];
i1 = index[1];
i2 = index[2];
// setup edges each with smallest vertex number first
s = INTSIGNBITSET(i1 - i0);
e[0].verts[0] = index[s];
e[0].verts[1] = index[s^1];
s = INTSIGNBITSET(i2 - i1) + 1;
e[1].verts[0] = index[s];
e[1].verts[1] = index[s^3];
s = INTSIGNBITSET(i2 - i0) << 1;
e[2].verts[0] = index[s];
e[2].verts[1] = index[s^2];
// get edges
for ( j = 0; j < 3; j++ ) {
v0 = e[j].verts[0];
v1 = e[j].verts[1];
for ( edgeNum = vertexEdges[v0]; edgeNum >= 0; edgeNum = edgeChain[edgeNum] ) {
if ( edges[edgeNum].verts[1] == v1 ) {
break;
}
}
// if the edge does not yet exist
if ( edgeNum < 0 ) {
e[j].tris[0] = e[j].tris[1] = -1;
edgeNum = edges.Append( e[j] );
edgeChain[edgeNum] = vertexEdges[v0];
vertexEdges[v0] = edgeNum;
}
// update edge index and edge tri references
if ( index[j] == v0 ) {
assert( edges[edgeNum].tris[0] == -1 ); // edge may not be shared by more than two triangles
edges[edgeNum].tris[0] = i;
edgeIndexes[i+j] = edgeNum;
} else {
assert( edges[edgeNum].tris[1] == -1 ); // edge may not be shared by more than two triangles
edges[edgeNum].tris[1] = i;
edgeIndexes[i+j] = -edgeNum;
}
}
}
}
/*
=================
idSurface::FindEdge
=================
*/
int idSurface::FindEdge( int v1, int v2 ) const {
int i, firstVert, secondVert;
if ( v1 < v2 ) {
firstVert = v1;
secondVert = v2;
} else {
firstVert = v2;
secondVert = v1;
}
for ( i = 1; i < edges.Num(); i++ ) {
if ( edges[i].verts[0] == firstVert ) {
if ( edges[i].verts[1] == secondVert ) {
break;
}
}
}
if ( i < edges.Num() ) {
return v1 < v2 ? i : -i;
}
return 0;
}

View File

@@ -0,0 +1,233 @@
/*
===========================================================================
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 __SURFACE_H__
#define __SURFACE_H__
/*
===============================================================================
Surface base class.
A surface is tesselated to a triangle mesh with each edge shared by
at most two triangles.
===============================================================================
*/
typedef struct surfaceEdge_s {
int verts[2]; // edge vertices always with ( verts[0] < verts[1] )
int tris[2]; // edge triangles
} surfaceEdge_t;
class idSurface {
public:
idSurface( void );
explicit idSurface( const idSurface &surf );
explicit idSurface( const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes );
~idSurface( void );
const idDrawVert & operator[]( const int index ) const;
idDrawVert & operator[]( const int index );
idSurface & operator+=( const idSurface &surf );
int GetNumIndexes( void ) const { return indexes.Num(); }
const int * GetIndexes( void ) const { return indexes.Ptr(); }
int GetNumVertices( void ) const { return verts.Num(); }
const idDrawVert * GetVertices( void ) const { return verts.Ptr(); }
const int * GetEdgeIndexes( void ) const { return edgeIndexes.Ptr(); }
const surfaceEdge_t * GetEdges( void ) const { return edges.Ptr(); }
void Clear( void );
void SwapTriangles( idSurface &surf );
void TranslateSelf( const idVec3 &translation );
void RotateSelf( const idMat3 &rotation );
// splits the surface into a front and back surface, the surface itself stays unchanged
// frontOnPlaneEdges and backOnPlaneEdges optionally store the indexes to the edges that lay on the split plane
// returns a SIDE_?
int Split( const idPlane &plane, const float epsilon, idSurface **front, idSurface **back, int *frontOnPlaneEdges = NULL, int *backOnPlaneEdges = NULL ) const;
// cuts off the part at the back side of the plane, returns true if some part was at the front
// if there is nothing at the front the number of points is set to zero
bool ClipInPlace( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
// returns true if each triangle can be reached from any other triangle by a traversal
bool IsConnected( void ) const;
// returns true if the surface is closed
bool IsClosed( void ) const;
// returns true if the surface is a convex hull
bool IsPolytope( const float epsilon = 0.1f ) const;
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
// returns true if the line intersects one of the surface triangles
bool LineIntersection( const idVec3 &start, const idVec3 &end, bool backFaceCull = false ) const;
// intersection point is start + dir * scale
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull = false ) const;
protected:
idList<idDrawVert> verts; // vertices
idList<int> indexes; // 3 references to vertices for each triangle
idList<surfaceEdge_t> edges; // edges
idList<int> edgeIndexes; // 3 references to edges for each triangle, may be negative for reversed edge
protected:
void GenerateEdgeIndexes( void );
int FindEdge( int v1, int v2 ) const;
};
/*
====================
idSurface::idSurface
====================
*/
ID_INLINE idSurface::idSurface( void ) {
}
/*
=================
idSurface::idSurface
=================
*/
ID_INLINE idSurface::idSurface( const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) {
assert( verts != NULL && indexes != NULL && numVerts > 0 && numIndexes > 0 );
this->verts.SetNum( numVerts );
memcpy( this->verts.Ptr(), verts, numVerts * sizeof( verts[0] ) );
this->indexes.SetNum( numIndexes );
memcpy( this->indexes.Ptr(), indexes, numIndexes * sizeof( indexes[0] ) );
GenerateEdgeIndexes();
}
/*
====================
idSurface::idSurface
====================
*/
ID_INLINE idSurface::idSurface( const idSurface &surf ) {
this->verts = surf.verts;
this->indexes = surf.indexes;
this->edges = surf.edges;
this->edgeIndexes = surf.edgeIndexes;
}
/*
====================
idSurface::~idSurface
====================
*/
ID_INLINE idSurface::~idSurface( void ) {
}
/*
=================
idSurface::operator[]
=================
*/
ID_INLINE const idDrawVert &idSurface::operator[]( const int index ) const {
return verts[ index ];
};
/*
=================
idSurface::operator[]
=================
*/
ID_INLINE idDrawVert &idSurface::operator[]( const int index ) {
return verts[ index ];
};
/*
=================
idSurface::operator+=
=================
*/
ID_INLINE idSurface &idSurface::operator+=( const idSurface &surf ) {
int i, m, n;
n = verts.Num();
m = indexes.Num();
verts.Append( surf.verts ); // merge verts where possible ?
indexes.Append( surf.indexes );
for ( i = m; i < indexes.Num(); i++ ) {
indexes[i] += n;
}
GenerateEdgeIndexes();
return *this;
}
/*
=================
idSurface::Clear
=================
*/
ID_INLINE void idSurface::Clear( void ) {
verts.Clear();
indexes.Clear();
edges.Clear();
edgeIndexes.Clear();
}
/*
=================
idSurface::SwapTriangles
=================
*/
ID_INLINE void idSurface::SwapTriangles( idSurface &surf ) {
verts.Swap( surf.verts );
indexes.Swap( surf.indexes );
edges.Swap( surf.edges );
edgeIndexes.Swap( surf.edgeIndexes );
}
/*
=================
idSurface::TranslateSelf
=================
*/
ID_INLINE void idSurface::TranslateSelf( const idVec3 &translation ) {
for ( int i = 0; i < verts.Num(); i++ ) {
verts[i].xyz += translation;
}
}
/*
=================
idSurface::RotateSelf
=================
*/
ID_INLINE void idSurface::RotateSelf( const idMat3 &rotation ) {
for ( int i = 0; i < verts.Num(); i++ ) {
verts[i].xyz *= rotation;
verts[i].normal *= rotation;
verts[i].tangents[0] *= rotation;
verts[i].tangents[1] *= rotation;
}
}
#endif /* !__SURFACE_H__ */

View File

@@ -0,0 +1,691 @@
/*
===========================================================================
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
/*
=================
idSurface_Patch::SetSize
=================
*/
void idSurface_Patch::SetSize( int patchWidth, int patchHeight ) {
if ( patchWidth < 1 || patchWidth > maxWidth ) {
idLib::common->FatalError("idSurface_Patch::SetSize: invalid patchWidth");
}
if ( patchHeight < 1 || patchHeight > maxHeight ) {
idLib::common->FatalError("idSurface_Patch::SetSize: invalid patchHeight");
}
width = patchWidth;
height = patchHeight;
verts.SetNum( width * height, false );
}
/*
=================
idSurface_Patch::PutOnCurve
Expects an expanded patch.
=================
*/
void idSurface_Patch::PutOnCurve( void ) {
int i, j;
idDrawVert prev, next;
assert( expanded == true );
// put all the approximating points on the curve
for ( i = 0; i < width; i++ ) {
for ( j = 1; j < height; j += 2 ) {
LerpVert( verts[j*maxWidth+i], verts[(j+1)*maxWidth+i], prev );
LerpVert( verts[j*maxWidth+i], verts[(j-1)*maxWidth+i], next );
LerpVert( prev, next, verts[j*maxWidth+i] );
}
}
for ( j = 0; j < height; j++ ) {
for ( i = 1; i < width; i += 2 ) {
LerpVert( verts[j*maxWidth+i], verts[j*maxWidth+i+1], prev );
LerpVert( verts[j*maxWidth+i], verts[j*maxWidth+i-1], next );
LerpVert( prev, next, verts[j*maxWidth+i] );
}
}
}
/*
================
idSurface_Patch::ProjectPointOntoVector
================
*/
void idSurface_Patch::ProjectPointOntoVector( const idVec3 &point, const idVec3 &vStart, const idVec3 &vEnd, idVec3 &vProj ) {
idVec3 pVec, vec;
pVec = point - vStart;
vec = vEnd - vStart;
vec.Normalize();
// project onto the directional vector for this segment
vProj = vStart + (pVec * vec) * vec;
}
/*
================
idSurface_Patch::RemoveLinearColumnsRows
Expects an expanded patch.
================
*/
void idSurface_Patch::RemoveLinearColumnsRows( void ) {
int i, j, k;
float len, maxLength;
idVec3 proj, dir;
assert( expanded == true );
for ( j = 1; j < width - 1; j++ ) {
maxLength = 0;
for ( i = 0; i < height; i++ ) {
idSurface_Patch::ProjectPointOntoVector( verts[i*maxWidth + j].xyz,
verts[i*maxWidth + j-1].xyz, verts[i*maxWidth + j+1].xyz, proj);
dir = verts[i*maxWidth + j].xyz - proj;
len = dir.LengthSqr();
if ( len > maxLength ) {
maxLength = len;
}
}
if ( maxLength < Square( 0.2f ) ) {
width--;
for ( i = 0; i < height; i++ ) {
for ( k = j; k < width; k++ ) {
verts[i*maxWidth + k] = verts[i*maxWidth + k+1];
}
}
j--;
}
}
for ( j = 1; j < height - 1; j++ ) {
maxLength = 0;
for ( i = 0; i < width; i++ ) {
idSurface_Patch::ProjectPointOntoVector( verts[j*maxWidth + i].xyz,
verts[(j-1)*maxWidth + i].xyz, verts[(j+1)*maxWidth + i].xyz, proj);
dir = verts[j*maxWidth + i].xyz - proj;
len = dir.LengthSqr();
if ( len > maxLength ) {
maxLength = len;
}
}
if ( maxLength < Square( 0.2f ) ) {
height--;
for ( i = 0; i < width; i++ ) {
for ( k = j; k < height; k++ ) {
verts[k*maxWidth + i] = verts[(k+1)*maxWidth + i];
}
}
j--;
}
}
}
/*
================
idSurface_Patch::ResizeExpanded
================
*/
void idSurface_Patch::ResizeExpanded( int newHeight, int newWidth ) {
int i, j;
assert( expanded == true );
if ( newHeight <= maxHeight && newWidth <= maxWidth ) {
return;
}
if ( newHeight * newWidth > maxHeight * maxWidth ) {
verts.SetNum( newHeight * newWidth );
}
// space out verts for new height and width
for ( j = maxHeight-1; j >= 0; j-- ) {
for ( i = maxWidth-1; i >= 0; i-- ) {
verts[j*newWidth + i] = verts[j*maxWidth + i];
}
}
maxHeight = newHeight;
maxWidth = newWidth;
}
/*
================
idSurface_Patch::Collapse
================
*/
void idSurface_Patch::Collapse( void ) {
int i, j;
if ( !expanded ) {
idLib::common->FatalError("idSurface_Patch::Collapse: patch not expanded");
}
expanded = false;
if ( width != maxWidth ) {
for ( j = 0; j < height; j++ ) {
for ( i = 0; i < width; i++ ) {
verts[j*width + i] = verts[j*maxWidth + i];
}
}
}
verts.SetNum( width * height, false );
}
/*
================
idSurface_Patch::Expand
================
*/
void idSurface_Patch::Expand( void ) {
int i, j;
if ( expanded ) {
idLib::common->FatalError("idSurface_Patch::Expand: patch alread expanded");
}
expanded = true;
verts.SetNum( maxWidth * maxHeight, false );
if ( width != maxWidth ) {
for ( j = height-1; j >= 0; j-- ) {
for ( i = width-1; i >= 0; i-- ) {
verts[j*maxWidth + i] = verts[j*width + i];
}
}
}
}
/*
============
idSurface_Patch::LerpVert
============
*/
void idSurface_Patch::LerpVert( const idDrawVert &a, const idDrawVert &b, idDrawVert &out ) const {
out.xyz[0] = 0.5f * ( a.xyz[0] + b.xyz[0] );
out.xyz[1] = 0.5f * ( a.xyz[1] + b.xyz[1] );
out.xyz[2] = 0.5f * ( a.xyz[2] + b.xyz[2] );
out.normal[0] = 0.5f * ( a.normal[0] + b.normal[0] );
out.normal[1] = 0.5f * ( a.normal[1] + b.normal[1] );
out.normal[2] = 0.5f * ( a.normal[2] + b.normal[2] );
out.st[0] = 0.5f * ( a.st[0] + b.st[0] );
out.st[1] = 0.5f * ( a.st[1] + b.st[1] );
}
/*
=================
idSurface_Patch::GenerateNormals
Handles all the complicated wrapping and degenerate cases
Expects a Not expanded patch.
=================
*/
#define COPLANAR_EPSILON 0.1f
void idSurface_Patch::GenerateNormals( void ) {
int i, j, k, dist;
idVec3 norm;
idVec3 sum;
int count;
idVec3 base;
idVec3 delta;
int x, y;
idVec3 around[8], temp;
bool good[8];
bool wrapWidth, wrapHeight;
static int neighbors[8][2] = {
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
};
assert( expanded == false );
//
// if all points are coplanar, set all normals to that plane
//
idVec3 extent[3];
float offset;
extent[0] = verts[width - 1].xyz - verts[0].xyz;
extent[1] = verts[(height-1) * width + width - 1].xyz - verts[0].xyz;
extent[2] = verts[(height-1) * width].xyz - verts[0].xyz;
norm = extent[0].Cross( extent[1] );
if ( norm.LengthSqr() == 0.0f ) {
norm = extent[0].Cross( extent[2] );
if ( norm.LengthSqr() == 0.0f ) {
norm = extent[1].Cross( extent[2] );
}
}
// wrapped patched may not get a valid normal here
if ( norm.Normalize() != 0.0f ) {
offset = verts[0].xyz * norm;
for ( i = 1; i < width * height; i++ ) {
float d = verts[i].xyz * norm;
if ( idMath::Fabs( d - offset ) > COPLANAR_EPSILON ) {
break;
}
}
if ( i == width * height ) {
// all are coplanar
for ( i = 0; i < width * height; i++ ) {
verts[i].normal = norm;
}
return;
}
}
// check for wrapped edge cases, which should smooth across themselves
wrapWidth = false;
for ( i = 0; i < height; i++ ) {
delta = verts[i * width].xyz - verts[i * width + width-1].xyz;
if ( delta.LengthSqr() > Square( 1.0f ) ) {
break;
}
}
if ( i == height ) {
wrapWidth = true;
}
wrapHeight = false;
for ( i = 0; i < width; i++ ) {
delta = verts[i].xyz - verts[(height-1) * width + i].xyz;
if ( delta.LengthSqr() > Square( 1.0f ) ) {
break;
}
}
if ( i == width ) {
wrapHeight = true;
}
for ( i = 0; i < width; i++ ) {
for ( j = 0; j < height; j++ ) {
count = 0;
base = verts[j * width + i].xyz;
for ( k = 0; k < 8; k++ ) {
around[k] = vec3_origin;
good[k] = false;
for ( dist = 1; dist <= 3; dist++ ) {
x = i + neighbors[k][0] * dist;
y = j + neighbors[k][1] * dist;
if ( wrapWidth ) {
if ( x < 0 ) {
x = width - 1 + x;
} else if ( x >= width ) {
x = 1 + x - width;
}
}
if ( wrapHeight ) {
if ( y < 0 ) {
y = height - 1 + y;
} else if ( y >= height ) {
y = 1 + y - height;
}
}
if ( x < 0 || x >= width || y < 0 || y >= height ) {
break; // edge of patch
}
temp = verts[y * width + x].xyz - base;
if ( temp.Normalize() == 0.0f ) {
continue; // degenerate edge, get more dist
} else {
good[k] = true;
around[k] = temp;
break; // good edge
}
}
}
sum = vec3_origin;
for ( k = 0; k < 8; k++ ) {
if ( !good[k] || !good[(k+1)&7] ) {
continue; // didn't get two points
}
norm = around[(k+1)&7].Cross( around[k] );
if ( norm.Normalize() == 0.0f ) {
continue;
}
sum += norm;
count++;
}
if ( count == 0 ) {
//idLib::common->Printf("bad normal\n");
count = 1;
}
verts[j * width + i].normal = sum;
verts[j * width + i].normal.Normalize();
}
}
}
/*
=================
idSurface_Patch::GenerateIndexes
=================
*/
void idSurface_Patch::GenerateIndexes( void ) {
int i, j, v1, v2, v3, v4, index;
indexes.SetNum( (width-1) * (height-1) * 2 * 3, false );
index = 0;
for ( i = 0; i < width - 1; i++ ) {
for ( j = 0; j < height - 1; j++ ) {
v1 = j * width + i;
v2 = v1 + 1;
v3 = v1 + width + 1;
v4 = v1 + width;
indexes[index++] = v1;
indexes[index++] = v3;
indexes[index++] = v2;
indexes[index++] = v1;
indexes[index++] = v4;
indexes[index++] = v3;
}
}
GenerateEdgeIndexes();
}
/*
===============
idSurface_Patch::SampleSinglePatchPoint
===============
*/
void idSurface_Patch::SampleSinglePatchPoint( const idDrawVert ctrl[3][3], float u, float v, idDrawVert *out ) const {
float vCtrl[3][8];
int vPoint;
int axis;
// find the control points for the v coordinate
for ( vPoint = 0; vPoint < 3; vPoint++ ) {
for ( axis = 0; axis < 8; axis++ ) {
float a, b, c;
float qA, qB, qC;
if ( axis < 3 ) {
a = ctrl[0][vPoint].xyz[axis];
b = ctrl[1][vPoint].xyz[axis];
c = ctrl[2][vPoint].xyz[axis];
} else if ( axis < 6 ) {
a = ctrl[0][vPoint].normal[axis-3];
b = ctrl[1][vPoint].normal[axis-3];
c = ctrl[2][vPoint].normal[axis-3];
} else {
a = ctrl[0][vPoint].st[axis-6];
b = ctrl[1][vPoint].st[axis-6];
c = ctrl[2][vPoint].st[axis-6];
}
qA = a - 2.0f * b + c;
qB = 2.0f * b - 2.0f * a;
qC = a;
vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
}
}
// interpolate the v value
for ( axis = 0; axis < 8; axis++ ) {
float a, b, c;
float qA, qB, qC;
a = vCtrl[0][axis];
b = vCtrl[1][axis];
c = vCtrl[2][axis];
qA = a - 2.0f * b + c;
qB = 2.0f * b - 2.0f * a;
qC = a;
if ( axis < 3 ) {
out->xyz[axis] = qA * v * v + qB * v + qC;
} else if ( axis < 6 ) {
out->normal[axis-3] = qA * v * v + qB * v + qC;
} else {
out->st[axis-6] = qA * v * v + qB * v + qC;
}
}
}
/*
===================
idSurface_Patch::SampleSinglePatch
===================
*/
void idSurface_Patch::SampleSinglePatch( const idDrawVert ctrl[3][3], int baseCol, int baseRow, int width, int horzSub, int vertSub, idDrawVert *outVerts ) const {
int i, j;
float u, v;
horzSub++;
vertSub++;
for ( i = 0; i < horzSub; i++ ) {
for ( j = 0; j < vertSub; j++ ) {
u = (float) i / ( horzSub - 1 );
v = (float) j / ( vertSub - 1 );
SampleSinglePatchPoint( ctrl, u, v, &outVerts[((baseRow + j) * width) + i + baseCol] );
}
}
}
/*
=================
idSurface_Patch::SubdivideExplicit
=================
*/
void idSurface_Patch::SubdivideExplicit( int horzSubdivisions, int vertSubdivisions, bool genNormals, bool removeLinear ) {
int i, j, k, l;
idDrawVert sample[3][3];
int outWidth = ((width - 1) / 2 * horzSubdivisions) + 1;
int outHeight = ((height - 1) / 2 * vertSubdivisions) + 1;
idDrawVert *dv = new idDrawVert[ outWidth * outHeight ];
// generate normals for the control mesh
if ( genNormals ) {
GenerateNormals();
}
int baseCol = 0;
for ( i = 0; i + 2 < width; i += 2 ) {
int baseRow = 0;
for ( j = 0; j + 2 < height; j += 2 ) {
for ( k = 0; k < 3; k++ ) {
for ( l = 0; l < 3; l++ ) {
sample[k][l] = verts[ ((j + l) * width) + i + k ];
}
}
SampleSinglePatch( sample, baseCol, baseRow, outWidth, horzSubdivisions, vertSubdivisions, dv );
baseRow += vertSubdivisions;
}
baseCol += horzSubdivisions;
}
verts.SetNum( outWidth * outHeight );
for ( i = 0; i < outWidth * outHeight; i++ ) {
verts[i] = dv[i];
}
delete[] dv;
width = maxWidth = outWidth;
height = maxHeight = outHeight;
expanded = false;
if ( removeLinear ) {
Expand();
RemoveLinearColumnsRows();
Collapse();
}
// normalize all the lerped normals
if ( genNormals ) {
for ( i = 0; i < width * height; i++ ) {
verts[i].normal.Normalize();
}
}
GenerateIndexes();
}
/*
=================
idSurface_Patch::Subdivide
=================
*/
void idSurface_Patch::Subdivide( float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals ) {
int i, j, k, l;
idDrawVert prev, next, mid;
idVec3 prevxyz, nextxyz, midxyz;
idVec3 delta;
float maxHorizontalErrorSqr, maxVerticalErrorSqr, maxLengthSqr;
// generate normals for the control mesh
if ( genNormals ) {
GenerateNormals();
}
maxHorizontalErrorSqr = Square( maxHorizontalError );
maxVerticalErrorSqr = Square( maxVerticalError );
maxLengthSqr = Square( maxLength );
Expand();
// horizontal subdivisions
for ( j = 0; j + 2 < width; j += 2 ) {
// check subdivided midpoints against control points
for ( i = 0; i < height; i++ ) {
for ( l = 0; l < 3; l++ ) {
prevxyz[l] = verts[i*maxWidth + j+1].xyz[l] - verts[i*maxWidth + j ].xyz[l];
nextxyz[l] = verts[i*maxWidth + j+2].xyz[l] - verts[i*maxWidth + j+1].xyz[l];
midxyz[l] = (verts[i*maxWidth + j ].xyz[l] + verts[i*maxWidth + j+1].xyz[l] * 2.0f +
verts[i*maxWidth + j+2].xyz[l] ) * 0.25f;
}
if ( maxLength > 0.0f ) {
// if the span length is too long, force a subdivision
if ( prevxyz.LengthSqr() > maxLengthSqr || nextxyz.LengthSqr() > maxLengthSqr ) {
break;
}
}
// see if this midpoint is off far enough to subdivide
delta = verts[i*maxWidth + j+1].xyz - midxyz;
if ( delta.LengthSqr() > maxHorizontalErrorSqr ) {
break;
}
}
if ( i == height ) {
continue; // didn't need subdivision
}
if ( width + 2 >= maxWidth ) {
ResizeExpanded( maxHeight, maxWidth + 4 );
}
// insert two columns and replace the peak
width += 2;
for ( i = 0; i < height; i++ ) {
idSurface_Patch::LerpVert( verts[i*maxWidth + j ], verts[i*maxWidth + j+1], prev );
idSurface_Patch::LerpVert( verts[i*maxWidth + j+1], verts[i*maxWidth + j+2], next );
idSurface_Patch::LerpVert( prev, next, mid );
for ( k = width - 1; k > j + 3; k-- ) {
verts[i*maxWidth + k] = verts[i*maxWidth + k-2];
}
verts[i*maxWidth + j+1] = prev;
verts[i*maxWidth + j+2] = mid;
verts[i*maxWidth + j+3] = next;
}
// back up and recheck this set again, it may need more subdivision
j -= 2;
}
// vertical subdivisions
for ( j = 0; j + 2 < height; j += 2 ) {
// check subdivided midpoints against control points
for ( i = 0; i < width; i++ ) {
for ( l = 0; l < 3; l++ ) {
prevxyz[l] = verts[(j+1)*maxWidth + i].xyz[l] - verts[j*maxWidth + i].xyz[l];
nextxyz[l] = verts[(j+2)*maxWidth + i].xyz[l] - verts[(j+1)*maxWidth + i].xyz[l];
midxyz[l] = (verts[j*maxWidth + i].xyz[l] + verts[(j+1)*maxWidth + i].xyz[l] * 2.0f +
verts[(j+2)*maxWidth + i].xyz[l] ) * 0.25f;
}
if ( maxLength > 0.0f ) {
// if the span length is too long, force a subdivision
if ( prevxyz.LengthSqr() > maxLengthSqr || nextxyz.LengthSqr() > maxLengthSqr ) {
break;
}
}
// see if this midpoint is off far enough to subdivide
delta = verts[(j+1)*maxWidth + i].xyz - midxyz;
if ( delta.LengthSqr() > maxVerticalErrorSqr ) {
break;
}
}
if ( i == width ) {
continue; // didn't need subdivision
}
if ( height + 2 >= maxHeight ) {
ResizeExpanded( maxHeight + 4, maxWidth );
}
// insert two columns and replace the peak
height += 2;
for ( i = 0; i < width; i++ ) {
LerpVert( verts[j*maxWidth + i], verts[(j+1)*maxWidth + i], prev );
LerpVert( verts[(j+1)*maxWidth + i], verts[(j+2)*maxWidth + i], next );
LerpVert( prev, next, mid );
for ( k = height - 1; k > j + 3; k-- ) {
verts[k*maxWidth + i] = verts[(k-2)*maxWidth + i];
}
verts[(j+1)*maxWidth + i] = prev;
verts[(j+2)*maxWidth + i] = mid;
verts[(j+3)*maxWidth + i] = next;
}
// back up and recheck this set again, it may need more subdivision
j -= 2;
}
PutOnCurve();
RemoveLinearColumnsRows();
Collapse();
// normalize all the lerped normals
if ( genNormals ) {
for ( i = 0; i < width * height; i++ ) {
verts[i].normal.Normalize();
}
}
GenerateIndexes();
}

View File

@@ -0,0 +1,146 @@
/*
===========================================================================
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 __SURFACE_PATCH_H__
#define __SURFACE_PATCH_H__
/*
===============================================================================
Bezier patch surface.
===============================================================================
*/
class idSurface_Patch : public idSurface {
public:
idSurface_Patch( void );
idSurface_Patch( int maxPatchWidth, int maxPatchHeight );
idSurface_Patch( const idSurface_Patch &patch );
~idSurface_Patch( void );
void SetSize( int patchWidth, int patchHeight );
int GetWidth( void ) const;
int GetHeight( void ) const;
// subdivide the patch mesh based on error
void Subdivide( float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals = false );
// subdivide the patch up to an explicit number of horizontal and vertical subdivisions
void SubdivideExplicit( int horzSubdivisions, int vertSubdivisions, bool genNormals, bool removeLinear = false );
protected:
int width; // width of patch
int height; // height of patch
int maxWidth; // maximum width allocated for
int maxHeight; // maximum height allocated for
bool expanded; // true if vertices are spaced out
private:
// put the approximation points on the curve
void PutOnCurve( void );
// remove columns and rows with all points on one line
void RemoveLinearColumnsRows( void );
// resize verts buffer
void ResizeExpanded( int height, int width );
// space points out over maxWidth * maxHeight buffer
void Expand( void );
// move all points to the start of the verts buffer
void Collapse( void );
// project a point onto a vector to calculate maximum curve error
void ProjectPointOntoVector( const idVec3 &point, const idVec3 &vStart, const idVec3 &vEnd, idVec3 &vProj );
// generate normals
void GenerateNormals( void );
// generate triangle indexes
void GenerateIndexes( void );
// lerp point from two patch point
void LerpVert( const idDrawVert &a, const idDrawVert &b, idDrawVert &out ) const;
// sample a single 3x3 patch
void SampleSinglePatchPoint( const idDrawVert ctrl[3][3], float u, float v, idDrawVert *out ) const;
void SampleSinglePatch( const idDrawVert ctrl[3][3], int baseCol, int baseRow, int width, int horzSub, int vertSub, idDrawVert *outVerts ) const;
};
/*
=================
idSurface_Patch::idSurface_Patch
=================
*/
ID_INLINE idSurface_Patch::idSurface_Patch( void ) {
height = width = maxHeight = maxWidth = 0;
expanded = false;
}
/*
=================
idSurface_Patch::idSurface_Patch
=================
*/
ID_INLINE idSurface_Patch::idSurface_Patch( int maxPatchWidth, int maxPatchHeight ) {
width = height = 0;
maxWidth = maxPatchWidth;
maxHeight = maxPatchHeight;
verts.SetNum( maxWidth * maxHeight );
expanded = false;
}
/*
=================
idSurface_Patch::idSurface_Patch
=================
*/
ID_INLINE idSurface_Patch::idSurface_Patch( const idSurface_Patch &patch ) {
(*this) = patch;
}
/*
=================
idSurface_Patch::~idSurface_Patch
=================
*/
ID_INLINE idSurface_Patch::~idSurface_Patch() {
}
/*
=================
idSurface_Patch::GetWidth
=================
*/
ID_INLINE int idSurface_Patch::GetWidth( void ) const {
return width;
}
/*
=================
idSurface_Patch::GetHeight
=================
*/
ID_INLINE int idSurface_Patch::GetHeight( void ) const {
return height;
}
#endif /* !__SURFACE_PATCH_H__ */

View File

@@ -0,0 +1,336 @@
/*
===========================================================================
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
#define POLYTOPE_VERTEX_EPSILON 0.1f
/*
====================
idSurface_Polytope::FromPlanes
====================
*/
void idSurface_Polytope::FromPlanes( const idPlane *planes, const int numPlanes ) {
int i, j, k, *windingVerts;
idFixedWinding w;
idDrawVert newVert;
windingVerts = (int *) _alloca( MAX_POINTS_ON_WINDING * sizeof( int ) );
memset( &newVert, 0, sizeof( newVert ) );
for ( i = 0; i < numPlanes; i++ ) {
w.BaseForPlane( planes[i] );
for ( j = 0; j < numPlanes; j++ ) {
if ( j == i ) {
continue;
}
if ( !w.ClipInPlace( -planes[j], ON_EPSILON, true ) ) {
break;
}
}
if ( !w.GetNumPoints() ) {
continue;
}
for ( j = 0; j < w.GetNumPoints(); j++ ) {
for ( k = 0; k < verts.Num(); j++ ) {
if ( verts[k].xyz.Compare( w[j].ToVec3(), POLYTOPE_VERTEX_EPSILON ) ) {
break;
}
}
if ( k >= verts.Num() ) {
newVert.xyz = w[j].ToVec3();
k = verts.Append( newVert );
}
windingVerts[j] = k;
}
for ( j = 2; j < w.GetNumPoints(); j++ ) {
indexes.Append( windingVerts[0] );
indexes.Append( windingVerts[j-1] );
indexes.Append( windingVerts[j] );
}
}
GenerateEdgeIndexes();
}
/*
====================
idSurface_Polytope::SetupTetrahedron
====================
*/
void idSurface_Polytope::SetupTetrahedron( const idBounds &bounds ) {
idVec3 center, scale;
float c1, c2, c3;
c1 = 0.4714045207f;
c2 = 0.8164965809f;
c3 = -0.3333333333f;
center = bounds.GetCenter();
scale = bounds[1] - center;
verts.SetNum( 4 );
verts[0].xyz = center + idVec3( 0.0f, 0.0f, scale.z );
verts[1].xyz = center + idVec3( 2.0f * c1 * scale.x, 0.0f, c3 * scale.z );
verts[2].xyz = center + idVec3( -c1 * scale.x, c2 * scale.y, c3 * scale.z );
verts[3].xyz = center + idVec3( -c1 * scale.x, -c2 * scale.y, c3 * scale.z );
indexes.SetNum( 4*3 );
indexes[0*3+0] = 0;
indexes[0*3+1] = 1;
indexes[0*3+2] = 2;
indexes[1*3+0] = 0;
indexes[1*3+1] = 2;
indexes[1*3+2] = 3;
indexes[2*3+0] = 0;
indexes[2*3+1] = 3;
indexes[2*3+2] = 1;
indexes[3*3+0] = 1;
indexes[3*3+1] = 3;
indexes[3*3+2] = 2;
GenerateEdgeIndexes();
}
/*
====================
idSurface_Polytope::SetupHexahedron
====================
*/
void idSurface_Polytope::SetupHexahedron( const idBounds &bounds ) {
idVec3 center, scale;
center = bounds.GetCenter();
scale = bounds[1] - center;
verts.SetNum( 8 );
verts[0].xyz = center + idVec3( -scale.x, -scale.y, -scale.z );
verts[1].xyz = center + idVec3( scale.x, -scale.y, -scale.z );
verts[2].xyz = center + idVec3( scale.x, scale.y, -scale.z );
verts[3].xyz = center + idVec3( -scale.x, scale.y, -scale.z );
verts[4].xyz = center + idVec3( -scale.x, -scale.y, scale.z );
verts[5].xyz = center + idVec3( scale.x, -scale.y, scale.z );
verts[6].xyz = center + idVec3( scale.x, scale.y, scale.z );
verts[7].xyz = center + idVec3( -scale.x, scale.y, scale.z );
indexes.SetNum( 12*3 );
indexes[ 0*3+0] = 0;
indexes[ 0*3+1] = 3;
indexes[ 0*3+2] = 2;
indexes[ 1*3+0] = 0;
indexes[ 1*3+1] = 2;
indexes[ 1*3+2] = 1;
indexes[ 2*3+0] = 0;
indexes[ 2*3+1] = 1;
indexes[ 2*3+2] = 5;
indexes[ 3*3+0] = 0;
indexes[ 3*3+1] = 5;
indexes[ 3*3+2] = 4;
indexes[ 4*3+0] = 0;
indexes[ 4*3+1] = 4;
indexes[ 4*3+2] = 7;
indexes[ 5*3+0] = 0;
indexes[ 5*3+1] = 7;
indexes[ 5*3+2] = 3;
indexes[ 6*3+0] = 6;
indexes[ 6*3+1] = 5;
indexes[ 6*3+2] = 1;
indexes[ 7*3+0] = 6;
indexes[ 7*3+1] = 1;
indexes[ 7*3+2] = 2;
indexes[ 8*3+0] = 6;
indexes[ 8*3+1] = 2;
indexes[ 8*3+2] = 3;
indexes[ 9*3+0] = 6;
indexes[ 9*3+1] = 3;
indexes[ 9*3+2] = 7;
indexes[10*3+0] = 6;
indexes[10*3+1] = 7;
indexes[10*3+2] = 4;
indexes[11*3+0] = 6;
indexes[11*3+1] = 4;
indexes[11*3+2] = 5;
GenerateEdgeIndexes();
}
/*
====================
idSurface_Polytope::SetupOctahedron
====================
*/
void idSurface_Polytope::SetupOctahedron( const idBounds &bounds ) {
idVec3 center, scale;
center = bounds.GetCenter();
scale = bounds[1] - center;
verts.SetNum( 6 );
verts[0].xyz = center + idVec3( scale.x, 0.0f, 0.0f );
verts[1].xyz = center + idVec3( -scale.x, 0.0f, 0.0f );
verts[2].xyz = center + idVec3( 0.0f, scale.y, 0.0f );
verts[3].xyz = center + idVec3( 0.0f, -scale.y, 0.0f );
verts[4].xyz = center + idVec3( 0.0f, 0.0f, scale.z );
verts[5].xyz = center + idVec3( 0.0f, 0.0f, -scale.z );
indexes.SetNum( 8*3 );
indexes[0*3+0] = 4;
indexes[0*3+1] = 0;
indexes[0*3+2] = 2;
indexes[1*3+0] = 4;
indexes[1*3+1] = 2;
indexes[1*3+2] = 1;
indexes[2*3+0] = 4;
indexes[2*3+1] = 1;
indexes[2*3+2] = 3;
indexes[3*3+0] = 4;
indexes[3*3+1] = 3;
indexes[3*3+2] = 0;
indexes[4*3+0] = 5;
indexes[4*3+1] = 2;
indexes[4*3+2] = 0;
indexes[5*3+0] = 5;
indexes[5*3+1] = 1;
indexes[5*3+2] = 2;
indexes[6*3+0] = 5;
indexes[6*3+1] = 3;
indexes[6*3+2] = 1;
indexes[7*3+0] = 5;
indexes[7*3+1] = 0;
indexes[7*3+2] = 3;
GenerateEdgeIndexes();
}
/*
====================
idSurface_Polytope::SetupDodecahedron
====================
*/
void idSurface_Polytope::SetupDodecahedron( const idBounds &bounds ) {
}
/*
====================
idSurface_Polytope::SetupIcosahedron
====================
*/
void idSurface_Polytope::SetupIcosahedron( const idBounds &bounds ) {
}
/*
====================
idSurface_Polytope::SetupCylinder
====================
*/
void idSurface_Polytope::SetupCylinder( const idBounds &bounds, const int numSides ) {
}
/*
====================
idSurface_Polytope::SetupCone
====================
*/
void idSurface_Polytope::SetupCone( const idBounds &bounds, const int numSides ) {
}
/*
====================
idSurface_Polytope::SplitPolytope
====================
*/
int idSurface_Polytope::SplitPolytope( const idPlane &plane, const float epsilon, idSurface_Polytope **front, idSurface_Polytope **back ) const {
int side, i, j, s, v0, v1, v2, edgeNum;
idSurface *surface[2];
idSurface_Polytope *polytopeSurfaces[2], *surf;
int *onPlaneEdges[2];
onPlaneEdges[0] = (int *) _alloca( indexes.Num() / 3 * sizeof( int ) );
onPlaneEdges[1] = (int *) _alloca( indexes.Num() / 3 * sizeof( int ) );
side = Split( plane, epsilon, &surface[0], &surface[1], onPlaneEdges[0], onPlaneEdges[1] );
*front = polytopeSurfaces[0] = new idSurface_Polytope;
*back = polytopeSurfaces[1] = new idSurface_Polytope;
for ( s = 0; s < 2; s++ ) {
if ( surface[s] ) {
polytopeSurfaces[s] = new idSurface_Polytope;
polytopeSurfaces[s]->SwapTriangles( *surface[s] );
delete surface[s];
surface[s] = NULL;
}
}
*front = polytopeSurfaces[0];
*back = polytopeSurfaces[1];
if ( side != SIDE_CROSS ) {
return side;
}
// add triangles to close off the front and back polytope
for ( s = 0; s < 2; s++ ) {
surf = polytopeSurfaces[s];
edgeNum = surf->edgeIndexes[onPlaneEdges[s][0]];
v0 = surf->edges[abs(edgeNum)].verts[INTSIGNBITSET(edgeNum)];
v1 = surf->edges[abs(edgeNum)].verts[INTSIGNBITNOTSET(edgeNum)];
for ( i = 1; onPlaneEdges[s][i] >= 0; i++ ) {
for ( j = i+1; onPlaneEdges[s][j] >= 0; j++ ) {
edgeNum = surf->edgeIndexes[onPlaneEdges[s][j]];
if ( v1 == surf->edges[abs(edgeNum)].verts[INTSIGNBITSET(edgeNum)] ) {
v1 = surf->edges[abs(edgeNum)].verts[INTSIGNBITNOTSET(edgeNum)];
idSwap( onPlaneEdges[s][i], onPlaneEdges[s][j] );
break;
}
}
}
for ( i = 2; onPlaneEdges[s][i] >= 0; i++ ) {
edgeNum = surf->edgeIndexes[onPlaneEdges[s][i]];
v1 = surf->edges[abs(edgeNum)].verts[INTSIGNBITNOTSET(edgeNum)];
v2 = surf->edges[abs(edgeNum)].verts[INTSIGNBITSET(edgeNum)];
surf->indexes.Append( v0 );
surf->indexes.Append( v1 );
surf->indexes.Append( v2 );
}
surf->GenerateEdgeIndexes();
}
return side;
}

View File

@@ -0,0 +1,70 @@
/*
===========================================================================
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 __SURFACE_POLYTOPE_H__
#define __SURFACE_POLYTOPE_H__
/*
===============================================================================
Polytope surface.
NOTE: vertexes are not duplicated for texture coordinates.
===============================================================================
*/
class idSurface_Polytope : public idSurface {
public:
idSurface_Polytope( void );
void FromPlanes( const idPlane *planes, const int numPlanes );
void SetupTetrahedron( const idBounds &bounds );
void SetupHexahedron( const idBounds &bounds );
void SetupOctahedron( const idBounds &bounds );
void SetupDodecahedron( const idBounds &bounds );
void SetupIcosahedron( const idBounds &bounds );
void SetupCylinder( const idBounds &bounds, const int numSides );
void SetupCone( const idBounds &bounds, const int numSides );
int SplitPolytope( const idPlane &plane, const float epsilon, idSurface_Polytope **front, idSurface_Polytope **back ) const;
protected:
};
/*
====================
idSurface_Polytope::idSurface_Polytope
====================
*/
ID_INLINE idSurface_Polytope::idSurface_Polytope( void ) {
}
#endif /* !__SURFACE_POLYTOPE_H__ */

View File

@@ -0,0 +1,223 @@
/*
===========================================================================
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
/*
====================
idSurface_SweptSpline::SetSpline
====================
*/
void idSurface_SweptSpline::SetSpline( idCurve_Spline<idVec4> *spline ) {
if ( this->spline ) {
delete this->spline;
}
this->spline = spline;
}
/*
====================
idSurface_SweptSpline::SetSweptSpline
====================
*/
void idSurface_SweptSpline::SetSweptSpline( idCurve_Spline<idVec4> *sweptSpline ) {
if ( this->sweptSpline ) {
delete this->sweptSpline;
}
this->sweptSpline = sweptSpline;
}
/*
====================
idSurface_SweptSpline::SetSweptCircle
Sets the swept spline to a NURBS circle.
====================
*/
void idSurface_SweptSpline::SetSweptCircle( const float radius ) {
idCurve_NURBS<idVec4> *nurbs = new idCurve_NURBS<idVec4>();
nurbs->Clear();
nurbs->AddValue( 0.0f, idVec4( radius, radius, 0.0f, 0.00f ) );
nurbs->AddValue( 100.0f, idVec4( -radius, radius, 0.0f, 0.25f ) );
nurbs->AddValue( 200.0f, idVec4( -radius, -radius, 0.0f, 0.50f ) );
nurbs->AddValue( 300.0f, idVec4( radius, -radius, 0.0f, 0.75f ) );
nurbs->SetBoundaryType( idCurve_NURBS<idVec4>::BT_CLOSED );
nurbs->SetCloseTime( 100.0f );
if ( sweptSpline ) {
delete sweptSpline;
}
sweptSpline = nurbs;
}
/*
====================
idSurface_SweptSpline::GetFrame
====================
*/
void idSurface_SweptSpline::GetFrame( const idMat3 &previousFrame, const idVec3 dir, idMat3 &newFrame ) {
float wx, wy, wz;
float xx, yy, yz;
float xy, xz, zz;
float x2, y2, z2;
float a, c, s, x, y, z;
idVec3 d, v;
idMat3 axis;
d = dir;
d.Normalize();
v = d.Cross( previousFrame[2] );
v.Normalize();
a = idMath::ACos( previousFrame[2] * d ) * 0.5f;
c = idMath::Cos( a );
s = idMath::Sqrt( 1.0f - c * c );
x = v[0] * s;
y = v[1] * s;
z = v[2] * s;
x2 = x + x;
y2 = y + y;
z2 = z + z;
xx = x * x2;
xy = x * y2;
xz = x * z2;
yy = y * y2;
yz = y * z2;
zz = z * z2;
wx = c * x2;
wy = c * y2;
wz = c * z2;
axis[0][0] = 1.0f - ( yy + zz );
axis[0][1] = xy - wz;
axis[0][2] = xz + wy;
axis[1][0] = xy + wz;
axis[1][1] = 1.0f - ( xx + zz );
axis[1][2] = yz - wx;
axis[2][0] = xz - wy;
axis[2][1] = yz + wx;
axis[2][2] = 1.0f - ( xx + yy );
newFrame = previousFrame * axis;
newFrame[2] = dir;
newFrame[2].Normalize();
newFrame[1].Cross( newFrame[ 2 ], newFrame[ 0 ] );
newFrame[1].Normalize();
newFrame[0].Cross( newFrame[ 1 ], newFrame[ 2 ] );
newFrame[0].Normalize();
}
/*
====================
idSurface_SweptSpline::Tessellate
tesselate the surface
====================
*/
void idSurface_SweptSpline::Tessellate( const int splineSubdivisions, const int sweptSplineSubdivisions ) {
int i, j, offset, baseOffset, splineDiv, sweptSplineDiv;
int i0, i1, j0, j1;
float totalTime, t;
idVec4 splinePos, splineD1;
idMat3 splineMat;
if ( !spline || !sweptSpline ) {
idSurface::Clear();
return;
}
verts.SetNum( splineSubdivisions * sweptSplineSubdivisions, false );
// calculate the points and first derivatives for the swept spline
totalTime = sweptSpline->GetTime( sweptSpline->GetNumValues() - 1 ) - sweptSpline->GetTime( 0 ) + sweptSpline->GetCloseTime();
sweptSplineDiv = sweptSpline->GetBoundaryType() == idCurve_Spline<idVec3>::BT_CLOSED ? sweptSplineSubdivisions : sweptSplineSubdivisions - 1;
baseOffset = (splineSubdivisions-1) * sweptSplineSubdivisions;
for ( i = 0; i < sweptSplineSubdivisions; i++ ) {
t = totalTime * i / sweptSplineDiv;
splinePos = sweptSpline->GetCurrentValue( t );
splineD1 = sweptSpline->GetCurrentFirstDerivative( t );
verts[baseOffset+i].xyz = splinePos.ToVec3();
verts[baseOffset+i].st[0] = splinePos.w;
verts[baseOffset+i].tangents[0] = splineD1.ToVec3();
}
// sweep the spline
totalTime = spline->GetTime( spline->GetNumValues() - 1 ) - spline->GetTime( 0 ) + spline->GetCloseTime();
splineDiv = spline->GetBoundaryType() == idCurve_Spline<idVec3>::BT_CLOSED ? splineSubdivisions : splineSubdivisions - 1;
splineMat.Identity();
for ( i = 0; i < splineSubdivisions; i++ ) {
t = totalTime * i / splineDiv;
splinePos = spline->GetCurrentValue( t );
splineD1 = spline->GetCurrentFirstDerivative( t );
GetFrame( splineMat, splineD1.ToVec3(), splineMat );
offset = i * sweptSplineSubdivisions;
for ( j = 0; j < sweptSplineSubdivisions; j++ ) {
idDrawVert *v = &verts[offset+j];
v->xyz = splinePos.ToVec3() + verts[baseOffset+j].xyz * splineMat;
v->st[0] = verts[baseOffset+j].st[0];
v->st[1] = splinePos.w;
v->tangents[0] = verts[baseOffset+j].tangents[0] * splineMat;
v->tangents[1] = splineD1.ToVec3();
v->normal = v->tangents[1].Cross( v->tangents[0] );
v->normal.Normalize();
v->color[0] = v->color[1] = v->color[2] = v->color[3] = 0;
}
}
indexes.SetNum( splineDiv * sweptSplineDiv * 2 * 3, false );
// create indexes for the triangles
for ( offset = i = 0; i < splineDiv; i++ ) {
i0 = (i+0) * sweptSplineSubdivisions;
i1 = (i+1) % splineSubdivisions * sweptSplineSubdivisions;
for ( j = 0; j < sweptSplineDiv; j++ ) {
j0 = (j+0);
j1 = (j+1) % sweptSplineSubdivisions;
indexes[offset++] = i0 + j0;
indexes[offset++] = i0 + j1;
indexes[offset++] = i1 + j1;
indexes[offset++] = i1 + j1;
indexes[offset++] = i1 + j0;
indexes[offset++] = i0 + j0;
}
}
GenerateEdgeIndexes();
}

View File

@@ -0,0 +1,93 @@
/*
===========================================================================
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 __SURFACE_SWEPTSPLINE_H__
#define __SURFACE_SWEPTSPLINE_H__
/*
===============================================================================
Swept Spline surface.
===============================================================================
*/
class idSurface_SweptSpline : public idSurface {
public:
idSurface_SweptSpline( void );
~idSurface_SweptSpline( void );
void SetSpline( idCurve_Spline<idVec4> *spline );
void SetSweptSpline( idCurve_Spline<idVec4> *sweptSpline );
void SetSweptCircle( const float radius );
void Tessellate( const int splineSubdivisions, const int sweptSplineSubdivisions );
void Clear( void );
protected:
idCurve_Spline<idVec4> *spline;
idCurve_Spline<idVec4> *sweptSpline;
void GetFrame( const idMat3 &previousFrame, const idVec3 dir, idMat3 &newFrame );
};
/*
====================
idSurface_SweptSpline::idSurface_SweptSpline
====================
*/
ID_INLINE idSurface_SweptSpline::idSurface_SweptSpline( void ) {
spline = NULL;
sweptSpline = NULL;
}
/*
====================
idSurface_SweptSpline::~idSurface_SweptSpline
====================
*/
ID_INLINE idSurface_SweptSpline::~idSurface_SweptSpline( void ) {
delete spline;
delete sweptSpline;
}
/*
====================
idSurface_SweptSpline::Clear
====================
*/
ID_INLINE void idSurface_SweptSpline::Clear( void ) {
idSurface::Clear();
delete spline;
spline = NULL;
delete sweptSpline;
sweptSpline = NULL;
}
#endif /* !__SURFACE_SWEPTSPLINE_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
/*
===========================================================================
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 __TRACEMODEL_H__
#define __TRACEMODEL_H__
/*
===============================================================================
A trace model is an arbitrary polygonal model which is used by the
collision detection system to find collisions, contacts or the contents
of a volume. For collision detection speed reasons the number of vertices
and edges are limited. The trace model can have any shape. However convex
models are usually preferred.
===============================================================================
*/
class idVec3;
class idMat3;
class idBounds;
// trace model type
typedef enum {
TRM_INVALID, // invalid trm
TRM_BOX, // box
TRM_OCTAHEDRON, // octahedron
TRM_DODECAHEDRON, // dodecahedron
TRM_CYLINDER, // cylinder approximation
TRM_CONE, // cone approximation
TRM_BONE, // two tetrahedrons attached to each other
TRM_POLYGON, // arbitrary convex polygon
TRM_POLYGONVOLUME, // volume for arbitrary convex polygon
TRM_CUSTOM // loaded from map model or ASE/LWO
} traceModel_t;
// these are bit cache limits
#define MAX_TRACEMODEL_VERTS 32
#define MAX_TRACEMODEL_EDGES 32
#define MAX_TRACEMODEL_POLYS 16
#define MAX_TRACEMODEL_POLYEDGES 16
typedef idVec3 traceModelVert_t;
typedef struct {
int v[2];
idVec3 normal;
} traceModelEdge_t;
typedef struct {
idVec3 normal;
float dist;
idBounds bounds;
int numEdges;
int edges[MAX_TRACEMODEL_POLYEDGES];
} traceModelPoly_t;
class idTraceModel {
public:
traceModel_t type;
int numVerts;
traceModelVert_t verts[MAX_TRACEMODEL_VERTS];
int numEdges;
traceModelEdge_t edges[MAX_TRACEMODEL_EDGES+1];
int numPolys;
traceModelPoly_t polys[MAX_TRACEMODEL_POLYS];
idVec3 offset; // offset to center of model
idBounds bounds; // bounds of model
bool isConvex; // true when model is convex
public:
idTraceModel( void );
// axial bounding box
idTraceModel( const idBounds &boxBounds );
// cylinder approximation
idTraceModel( const idBounds &cylBounds, const int numSides );
// bone
idTraceModel( const float length, const float width );
// axial box
void SetupBox( const idBounds &boxBounds );
void SetupBox( const float size );
// octahedron
void SetupOctahedron( const idBounds &octBounds );
void SetupOctahedron( const float size );
// dodecahedron
void SetupDodecahedron( const idBounds &dodBounds );
void SetupDodecahedron( const float size );
// cylinder approximation
void SetupCylinder( const idBounds &cylBounds, const int numSides );
void SetupCylinder( const float height, const float width, const int numSides );
// cone approximation
void SetupCone( const idBounds &coneBounds, const int numSides );
void SetupCone( const float height, const float width, const int numSides );
// two tetrahedrons attached to each other
void SetupBone( const float length, const float width );
// arbitrary convex polygon
void SetupPolygon( const idVec3 *v, const int count );
void SetupPolygon( const idWinding &w );
// generate edge normals
int GenerateEdgeNormals( void );
// translate the trm
void Translate( const idVec3 &translation );
// rotate the trm
void Rotate( const idMat3 &rotation );
// shrink the model m units on all sides
void Shrink( const float m );
// compare
bool Compare( const idTraceModel &trm ) const;
bool operator==( const idTraceModel &trm ) const;
bool operator!=( const idTraceModel &trm ) const;
// get the area of one of the polygons
float GetPolygonArea( int polyNum ) const;
// get the silhouette edges
int GetProjectionSilhouetteEdges( const idVec3 &projectionOrigin, int silEdges[MAX_TRACEMODEL_EDGES] ) const;
int GetParallelProjectionSilhouetteEdges( const idVec3 &projectionDir, int silEdges[MAX_TRACEMODEL_EDGES] ) const;
// calculate mass properties assuming an uniform density
void GetMassProperties( const float density, float &mass, idVec3 &centerOfMass, idMat3 &inertiaTensor ) const;
private:
void InitBox( void );
void InitOctahedron( void );
void InitDodecahedron( void );
void InitBone( void );
void ProjectionIntegrals( int polyNum, int a, int b, struct projectionIntegrals_s &integrals ) const;
void PolygonIntegrals( int polyNum, int a, int b, int c, struct polygonIntegrals_s &integrals ) const;
void VolumeIntegrals( struct volumeIntegrals_s &integrals ) const;
void VolumeFromPolygon( idTraceModel &trm, float thickness ) const;
int GetOrderedSilhouetteEdges( const int edgeIsSilEdge[MAX_TRACEMODEL_EDGES+1], int silEdges[MAX_TRACEMODEL_EDGES] ) const;
};
ID_INLINE idTraceModel::idTraceModel( void ) {
type = TRM_INVALID;
numVerts = numEdges = numPolys = 0;
bounds.Zero();
}
ID_INLINE idTraceModel::idTraceModel( const idBounds &boxBounds ) {
InitBox();
SetupBox( boxBounds );
}
ID_INLINE idTraceModel::idTraceModel( const idBounds &cylBounds, const int numSides ) {
SetupCylinder( cylBounds, numSides );
}
ID_INLINE idTraceModel::idTraceModel( const float length, const float width ) {
InitBone();
SetupBone( length, width );
}
ID_INLINE bool idTraceModel::operator==( const idTraceModel &trm ) const {
return Compare( trm );
}
ID_INLINE bool idTraceModel::operator!=( const idTraceModel &trm ) const {
return !Compare( trm );
}
#endif /* !__TRACEMODEL_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,401 @@
/*
===========================================================================
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 __WINDING_H__
#define __WINDING_H__
/*
===============================================================================
A winding is an arbitrary convex polygon defined by an array of points.
===============================================================================
*/
class idWinding {
public:
idWinding( void );
explicit idWinding( const int n ); // allocate for n points
explicit idWinding( const idVec3 *verts, const int n ); // winding from points
explicit idWinding( const idVec3 &normal, const float dist ); // base winding for plane
explicit idWinding( const idPlane &plane ); // base winding for plane
explicit idWinding( const idWinding &winding );
virtual ~idWinding( void );
idWinding & operator=( const idWinding &winding );
const idVec5 & operator[]( const int index ) const;
idVec5 & operator[]( const int index );
// add a point to the end of the winding point array
idWinding & operator+=( const idVec3 &v );
idWinding & operator+=( const idVec5 &v );
void AddPoint( const idVec3 &v );
void AddPoint( const idVec5 &v );
// number of points on winding
int GetNumPoints( void ) const;
void SetNumPoints( int n );
virtual void Clear( void );
// huge winding for plane, the points go counter clockwise when facing the front of the plane
void BaseForPlane( const idVec3 &normal, const float dist );
void BaseForPlane( const idPlane &plane );
// splits the winding into a front and back winding, the winding itself stays unchanged
// returns a SIDE_?
int Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const;
// returns the winding fragment at the front of the clipping plane,
// if there is nothing at the front the winding itself is destroyed and NULL is returned
idWinding * Clip( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
// cuts off the part at the back side of the plane, returns true if some part was at the front
// if there is nothing at the front the number of points is set to zero
bool ClipInPlace( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
// returns a copy of the winding
idWinding * Copy( void ) const;
idWinding * Reverse( void ) const;
void ReverseSelf( void );
void RemoveEqualPoints( const float epsilon = ON_EPSILON );
void RemoveColinearPoints( const idVec3 &normal, const float epsilon = ON_EPSILON );
void RemovePoint( int point );
void InsertPoint( const idVec3 &point, int spot );
bool InsertPointIfOnEdge( const idVec3 &point, const idPlane &plane, const float epsilon = ON_EPSILON );
// add a winding to the convex hull
void AddToConvexHull( const idWinding *winding, const idVec3 &normal, const float epsilon = ON_EPSILON );
// add a point to the convex hull
void AddToConvexHull( const idVec3 &point, const idVec3 &normal, const float epsilon = ON_EPSILON );
// tries to merge 'this' with the given winding, returns NULL if merge fails, both 'this' and 'w' stay intact
// 'keep' tells if the contacting points should stay even if they create colinear edges
idWinding * TryMerge( const idWinding &w, const idVec3 &normal, int keep = false ) const;
// check whether the winding is valid or not
bool Check( bool print = true ) const;
float GetArea( void ) const;
idVec3 GetCenter( void ) const;
float GetRadius( const idVec3 &center ) const;
void GetPlane( idVec3 &normal, float &dist ) const;
void GetPlane( idPlane &plane ) const;
void GetBounds( idBounds &bounds ) const;
bool IsTiny( void ) const;
bool IsHuge( void ) const; // base winding for a plane is typically huge
void Print( void ) const;
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool PlanesConcave( const idWinding &w2, const idVec3 &normal1, const idVec3 &normal2, float dist1, float dist2 ) const;
bool PointInside( const idVec3 &normal, const idVec3 &point, const float epsilon ) const;
// returns true if the line or ray intersects the winding
bool LineIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &end, bool backFaceCull = false ) const;
// intersection point is start + dir * scale
bool RayIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull = false ) const;
static float TriangleArea( const idVec3 &a, const idVec3 &b, const idVec3 &c );
protected:
int numPoints; // number of points
idVec5 * p; // pointer to point data
int allocedSize;
bool EnsureAlloced( int n, bool keep = false );
virtual bool ReAllocate( int n, bool keep = false );
};
ID_INLINE idWinding::idWinding( void ) {
numPoints = allocedSize = 0;
p = NULL;
}
ID_INLINE idWinding::idWinding( int n ) {
numPoints = allocedSize = 0;
p = NULL;
EnsureAlloced( n );
}
ID_INLINE idWinding::idWinding( const idVec3 *verts, const int n ) {
int i;
numPoints = allocedSize = 0;
p = NULL;
if ( !EnsureAlloced( n ) ) {
numPoints = 0;
return;
}
for ( i = 0; i < n; i++ ) {
p[i].ToVec3() = verts[i];
p[i].s = p[i].t = 0.0f;
}
numPoints = n;
}
ID_INLINE idWinding::idWinding( const idVec3 &normal, const float dist ) {
numPoints = allocedSize = 0;
p = NULL;
BaseForPlane( normal, dist );
}
ID_INLINE idWinding::idWinding( const idPlane &plane ) {
numPoints = allocedSize = 0;
p = NULL;
BaseForPlane( plane );
}
ID_INLINE idWinding::idWinding( const idWinding &winding ) {
int i;
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
numPoints = 0;
return;
}
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
p[i] = winding[i];
}
numPoints = winding.GetNumPoints();
}
ID_INLINE idWinding::~idWinding( void ) {
delete[] p;
p = NULL;
}
ID_INLINE idWinding &idWinding::operator=( const idWinding &winding ) {
int i;
if ( !EnsureAlloced( winding.numPoints ) ) {
numPoints = 0;
return *this;
}
for ( i = 0; i < winding.numPoints; i++ ) {
p[i] = winding.p[i];
}
numPoints = winding.numPoints;
return *this;
}
ID_INLINE const idVec5 &idWinding::operator[]( const int index ) const {
//assert( index >= 0 && index < numPoints );
return p[ index ];
}
ID_INLINE idVec5 &idWinding::operator[]( const int index ) {
//assert( index >= 0 && index < numPoints );
return p[ index ];
}
ID_INLINE idWinding &idWinding::operator+=( const idVec3 &v ) {
AddPoint( v );
return *this;
}
ID_INLINE idWinding &idWinding::operator+=( const idVec5 &v ) {
AddPoint( v );
return *this;
}
ID_INLINE void idWinding::AddPoint( const idVec3 &v ) {
if ( !EnsureAlloced(numPoints+1, true) ) {
return;
}
p[numPoints] = v;
numPoints++;
}
ID_INLINE void idWinding::AddPoint( const idVec5 &v ) {
if ( !EnsureAlloced(numPoints+1, true) ) {
return;
}
p[numPoints] = v;
numPoints++;
}
ID_INLINE int idWinding::GetNumPoints( void ) const {
return numPoints;
}
ID_INLINE void idWinding::SetNumPoints( int n ) {
if ( !EnsureAlloced( n, true ) ) {
return;
}
numPoints = n;
}
ID_INLINE void idWinding::Clear( void ) {
numPoints = 0;
delete[] p;
p = NULL;
}
ID_INLINE void idWinding::BaseForPlane( const idPlane &plane ) {
BaseForPlane( plane.Normal(), plane.Dist() );
}
ID_INLINE bool idWinding::EnsureAlloced( int n, bool keep ) {
if ( n > allocedSize ) {
return ReAllocate( n, keep );
}
return true;
}
/*
===============================================================================
idFixedWinding is a fixed buffer size winding not using
memory allocations.
When an operation would overflow the fixed buffer a warning
is printed and the operation is safely cancelled.
===============================================================================
*/
#define MAX_POINTS_ON_WINDING 64
class idFixedWinding : public idWinding {
public:
idFixedWinding( void );
explicit idFixedWinding( const int n );
explicit idFixedWinding( const idVec3 *verts, const int n );
explicit idFixedWinding( const idVec3 &normal, const float dist );
explicit idFixedWinding( const idPlane &plane );
explicit idFixedWinding( const idWinding &winding );
explicit idFixedWinding( const idFixedWinding &winding );
virtual ~idFixedWinding( void );
idFixedWinding &operator=( const idWinding &winding );
virtual void Clear( void );
// splits the winding in a back and front part, 'this' becomes the front part
// returns a SIDE_?
int Split( idFixedWinding *back, const idPlane &plane, const float epsilon = ON_EPSILON );
protected:
idVec5 data[MAX_POINTS_ON_WINDING]; // point data
virtual bool ReAllocate( int n, bool keep = false );
};
ID_INLINE idFixedWinding::idFixedWinding( void ) {
numPoints = 0;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
}
ID_INLINE idFixedWinding::idFixedWinding( int n ) {
numPoints = 0;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
}
ID_INLINE idFixedWinding::idFixedWinding( const idVec3 *verts, const int n ) {
int i;
numPoints = 0;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
if ( !EnsureAlloced( n ) ) {
numPoints = 0;
return;
}
for ( i = 0; i < n; i++ ) {
p[i].ToVec3() = verts[i];
p[i].s = p[i].t = 0;
}
numPoints = n;
}
ID_INLINE idFixedWinding::idFixedWinding( const idVec3 &normal, const float dist ) {
numPoints = 0;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
BaseForPlane( normal, dist );
}
ID_INLINE idFixedWinding::idFixedWinding( const idPlane &plane ) {
numPoints = 0;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
BaseForPlane( plane );
}
ID_INLINE idFixedWinding::idFixedWinding( const idWinding &winding ) {
int i;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
numPoints = 0;
return;
}
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
p[i] = winding[i];
}
numPoints = winding.GetNumPoints();
}
ID_INLINE idFixedWinding::idFixedWinding( const idFixedWinding &winding ) {
int i;
p = data;
allocedSize = MAX_POINTS_ON_WINDING;
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
numPoints = 0;
return;
}
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
p[i] = winding[i];
}
numPoints = winding.GetNumPoints();
}
ID_INLINE idFixedWinding::~idFixedWinding( void ) {
p = NULL; // otherwise it tries to free the fixed buffer
}
ID_INLINE idFixedWinding &idFixedWinding::operator=( const idWinding &winding ) {
int i;
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
numPoints = 0;
return *this;
}
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
p[i] = winding[i];
}
numPoints = winding.GetNumPoints();
return *this;
}
ID_INLINE void idFixedWinding::Clear( void ) {
numPoints = 0;
}
#endif /* !__WINDING_H__ */

View File

@@ -0,0 +1,754 @@
/*
===========================================================================
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
#include "Winding2D.h"
/*
============
GetAxialBevel
============
*/
bool GetAxialBevel( const idVec3 &plane1, const idVec3 &plane2, const idVec2 &point, idVec3 &bevel ) {
if ( FLOATSIGNBITSET( plane1.x ) ^ FLOATSIGNBITSET( plane2.x ) ) {
if ( idMath::Fabs( plane1.x ) > 0.1f && idMath::Fabs( plane2.x ) > 0.1f ) {
bevel.x = 0.0f;
if ( FLOATSIGNBITSET( plane1.y ) ) {
bevel.y = -1.0f;
}
else {
bevel.y = 1.0f;
}
bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
return true;
}
}
if ( FLOATSIGNBITSET( plane1.y ) ^ FLOATSIGNBITSET( plane2.y ) ) {
if ( idMath::Fabs( plane1.y ) > 0.1f && idMath::Fabs( plane2.y ) > 0.1f ) {
bevel.y = 0.0f;
if ( FLOATSIGNBITSET( plane1.x ) ) {
bevel.x = -1.0f;
}
else {
bevel.x = 1.0f;
}
bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
return true;
}
}
return false;
}
/*
============
idWinding2D::ExpandForAxialBox
============
*/
void idWinding2D::ExpandForAxialBox( const idVec2 bounds[2] ) {
int i, j, numPlanes;
idVec2 v;
idVec3 planes[MAX_POINTS_ON_WINDING_2D], plane, bevel;
// get planes for the edges and add bevels
for ( numPlanes = i = 0; i < numPoints; i++ ) {
j = (i+1) % numPoints;
if ( ( p[j] - p[i] ).LengthSqr() < 0.01f ) {
continue;
}
plane = Plane2DFromPoints( p[i], p[j], true );
if ( i ) {
if ( GetAxialBevel( planes[numPlanes-1], plane, p[i], bevel ) ) {
planes[numPlanes++] = bevel;
}
}
assert( numPlanes < MAX_POINTS_ON_WINDING_2D );
planes[numPlanes++] = plane;
}
if ( GetAxialBevel( planes[numPlanes-1], planes[0], p[0], bevel ) ) {
planes[numPlanes++] = bevel;
}
// expand the planes
for ( i = 0; i < numPlanes; i++ ) {
v.x = bounds[ FLOATSIGNBITSET( planes[i].x ) ].x;
v.y = bounds[ FLOATSIGNBITSET( planes[i].y ) ].y;
planes[i].z += v.x * planes[i].x + v.y * planes[i].y;
}
// get intersection points of the planes
for ( numPoints = i = 0; i < numPlanes; i++ ) {
if ( Plane2DIntersection( planes[(i+numPlanes-1) % numPlanes], planes[i], p[numPoints] ) ) {
numPoints++;
}
}
}
/*
============
idWinding2D::Expand
============
*/
void idWinding2D::Expand( const float d ) {
int i;
idVec2 edgeNormals[MAX_POINTS_ON_WINDING_2D];
for ( i = 0; i < numPoints; i++ ) {
idVec2 &start = p[i];
idVec2 &end = p[(i+1)%numPoints];
edgeNormals[i].x = start.y - end.y;
edgeNormals[i].y = end.x - start.x;
edgeNormals[i].Normalize();
edgeNormals[i] *= d;
}
for ( i = 0; i < numPoints; i++ ) {
p[i] += edgeNormals[i] + edgeNormals[(i+numPoints-1)%numPoints];
}
}
/*
=============
idWinding2D::Split
=============
*/
int idWinding2D::Split( const idVec3 &plane, const float epsilon, idWinding2D **front, idWinding2D **back ) const {
float dists[MAX_POINTS_ON_WINDING_2D];
byte sides[MAX_POINTS_ON_WINDING_2D];
int counts[3];
float dot;
int i, j;
const idVec2 * p1, *p2;
idVec2 mid;
idWinding2D * f;
idWinding2D * b;
int maxpts;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for ( i = 0; i < numPoints; i++ ) {
dists[i] = dot = plane.x * p[i].x + plane.y * p[i].y + plane.z;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*front = *back = NULL;
// if nothing at the front of the clipping plane
if ( !counts[SIDE_FRONT] ) {
*back = Copy();
return SIDE_BACK;
}
// if nothing at the back of the clipping plane
if ( !counts[SIDE_BACK] ) {
*front = Copy();
return SIDE_FRONT;
}
maxpts = numPoints+4; // cant use counts[0]+2 because of fp grouping errors
*front = f = new idWinding2D;
*back = b = new idWinding2D;
for ( i = 0; i < numPoints; i++ ) {
p1 = &p[i];
if ( sides[i] == SIDE_ON ) {
f->p[f->numPoints] = *p1;
f->numPoints++;
b->p[b->numPoints] = *p1;
b->numPoints++;
continue;
}
if ( sides[i] == SIDE_FRONT ) {
f->p[f->numPoints] = *p1;
f->numPoints++;
}
if ( sides[i] == SIDE_BACK ) {
b->p[b->numPoints] = *p1;
b->numPoints++;
}
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
continue;
}
// generate a split point
p2 = &p[(i+1)%numPoints];
// always calculate the split going from the same side
// or minor epsilon issues can happen
if ( sides[i] == SIDE_FRONT ) {
dot = dists[i] / ( dists[i] - dists[i+1] );
for ( j = 0; j < 2; j++ ) {
// avoid round off error when possible
if ( plane[j] == 1.0f ) {
mid[j] = plane.z;
} else if ( plane[j] == -1.0f ) {
mid[j] = -plane.z;
} else {
mid[j] = (*p1)[j] + dot * ((*p2)[j] - (*p1)[j]);
}
}
} else {
dot = dists[i+1] / ( dists[i+1] - dists[i] );
for ( j = 0; j < 2; j++ ) {
// avoid round off error when possible
if ( plane[j] == 1.0f ) {
mid[j] = plane.z;
} else if ( plane[j] == -1.0f ) {
mid[j] = -plane.z;
} else {
mid[j] = (*p2)[j] + dot * ( (*p1)[j] - (*p2)[j] );
}
}
}
f->p[f->numPoints] = mid;
f->numPoints++;
b->p[b->numPoints] = mid;
b->numPoints++;
}
return SIDE_CROSS;
}
/*
============
idWinding2D::ClipInPlace
============
*/
bool idWinding2D::ClipInPlace( const idVec3 &plane, const float epsilon, const bool keepOn ) {
int i, j, maxpts, newNumPoints;
int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
float dot, dists[MAX_POINTS_ON_WINDING_2D+1];
idVec2 *p1, *p2, mid, newPoints[MAX_POINTS_ON_WINDING_2D+4];
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
for ( i = 0; i < numPoints; i++ ) {
dists[i] = dot = plane.x * p[i].x + plane.y * p[i].y + plane.z;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
// if the winding is on the plane and we should keep it
if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
return true;
}
if ( !counts[SIDE_FRONT] ) {
numPoints = 0;
return false;
}
if ( !counts[SIDE_BACK] ) {
return true;
}
maxpts = numPoints + 4; // cant use counts[0]+2 because of fp grouping errors
newNumPoints = 0;
for ( i = 0; i < numPoints; i++ ) {
p1 = &p[i];
if ( newNumPoints+1 > maxpts ) {
return true; // can't split -- fall back to original
}
if ( sides[i] == SIDE_ON ) {
newPoints[newNumPoints] = *p1;
newNumPoints++;
continue;
}
if ( sides[i] == SIDE_FRONT ) {
newPoints[newNumPoints] = *p1;
newNumPoints++;
}
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
continue;
}
if ( newNumPoints+1 > maxpts ) {
return true; // can't split -- fall back to original
}
// generate a split point
p2 = &p[(i+1)%numPoints];
dot = dists[i] / (dists[i] - dists[i+1]);
for ( j = 0; j < 2; j++ ) {
// avoid round off error when possible
if ( plane[j] == 1.0f ) {
mid[j] = plane.z;
} else if ( plane[j] == -1.0f ) {
mid[j] = -plane.z;
} else {
mid[j] = (*p1)[j] + dot * ((*p2)[j] - (*p1)[j]);
}
}
newPoints[newNumPoints] = mid;
newNumPoints++;
}
if ( newNumPoints >= MAX_POINTS_ON_WINDING_2D ) {
return true;
}
numPoints = newNumPoints;
memcpy( p, newPoints, newNumPoints * sizeof(idVec2) );
return true;
}
/*
=============
idWinding2D::Copy
=============
*/
idWinding2D *idWinding2D::Copy( void ) const {
idWinding2D *w;
w = new idWinding2D;
w->numPoints = numPoints;
memcpy( w->p, p, numPoints * sizeof( p[0] ) );
return w;
}
/*
=============
idWinding2D::Reverse
=============
*/
idWinding2D *idWinding2D::Reverse( void ) const {
idWinding2D *w;
int i;
w = new idWinding2D;
w->numPoints = numPoints;
for ( i = 0; i < numPoints; i++ ) {
w->p[ numPoints - i - 1 ] = p[i];
}
return w;
}
/*
============
idWinding2D::GetArea
============
*/
float idWinding2D::GetArea( void ) const {
int i;
idVec2 d1, d2;
float total;
total = 0.0f;
for ( i = 2; i < numPoints; i++ ) {
d1 = p[i-1] - p[0];
d2 = p[i] - p[0];
total += d1.x * d2.y - d1.y * d2.x;
}
return total * 0.5f;
}
/*
============
idWinding2D::GetCenter
============
*/
idVec2 idWinding2D::GetCenter( void ) const {
int i;
idVec2 center;
center.Zero();
for ( i = 0; i < numPoints; i++ ) {
center += p[i];
}
center *= ( 1.0f / numPoints );
return center;
}
/*
============
idWinding2D::GetRadius
============
*/
float idWinding2D::GetRadius( const idVec2 &center ) const {
int i;
float radius, r;
idVec2 dir;
radius = 0.0f;
for ( i = 0; i < numPoints; i++ ) {
dir = p[i] - center;
r = dir * dir;
if ( r > radius ) {
radius = r;
}
}
return idMath::Sqrt( radius );
}
/*
============
idWinding2D::GetBounds
============
*/
void idWinding2D::GetBounds( idVec2 bounds[2] ) const {
int i;
if ( !numPoints ) {
bounds[0].x = bounds[0].y = idMath::INFINITY;
bounds[1].x = bounds[1].y = -idMath::INFINITY;
return;
}
bounds[0] = bounds[1] = p[0];
for ( i = 1; i < numPoints; i++ ) {
if ( p[i].x < bounds[0].x ) {
bounds[0].x = p[i].x;
} else if ( p[i].x > bounds[1].x ) {
bounds[1].x = p[i].x;
}
if ( p[i].y < bounds[0].y ) {
bounds[0].y = p[i].y;
} else if ( p[i].y > bounds[1].y ) {
bounds[1].y = p[i].y;
}
}
}
/*
=============
idWinding2D::IsTiny
=============
*/
#define EDGE_LENGTH 0.2f
bool idWinding2D::IsTiny( void ) const {
int i;
float len;
idVec2 delta;
int edges;
edges = 0;
for ( i = 0; i < numPoints; i++ ) {
delta = p[(i+1)%numPoints] - p[i];
len = delta.Length();
if ( len > EDGE_LENGTH ) {
if ( ++edges == 3 ) {
return false;
}
}
}
return true;
}
/*
=============
idWinding2D::IsHuge
=============
*/
bool idWinding2D::IsHuge( void ) const {
int i, j;
for ( i = 0; i < numPoints; i++ ) {
for ( j = 0; j < 2; j++ ) {
if ( p[i][j] <= MIN_WORLD_COORD || p[i][j] >= MAX_WORLD_COORD ) {
return true;
}
}
}
return false;
}
/*
=============
idWinding2D::Print
=============
*/
void idWinding2D::Print( void ) const {
int i;
for ( i = 0; i < numPoints; i++ ) {
idLib::common->Printf( "(%5.1f, %5.1f)\n", p[i][0], p[i][1] );
}
}
/*
=============
idWinding2D::PlaneDistance
=============
*/
float idWinding2D::PlaneDistance( const idVec3 &plane ) const {
int i;
float d, min, max;
min = idMath::INFINITY;
max = -min;
for ( i = 0; i < numPoints; i++ ) {
d = plane.x * p[i].x + plane.y * p[i].y + plane.z;
if ( d < min ) {
min = d;
if ( FLOATSIGNBITSET( min ) & FLOATSIGNBITNOTSET( max ) ) {
return 0.0f;
}
}
if ( d > max ) {
max = d;
if ( FLOATSIGNBITSET( min ) & FLOATSIGNBITNOTSET( max ) ) {
return 0.0f;
}
}
}
if ( FLOATSIGNBITNOTSET( min ) ) {
return min;
}
if ( FLOATSIGNBITSET( max ) ) {
return max;
}
return 0.0f;
}
/*
=============
idWinding2D::PlaneSide
=============
*/
int idWinding2D::PlaneSide( const idVec3 &plane, const float epsilon ) const {
bool front, back;
int i;
float d;
front = false;
back = false;
for ( i = 0; i < numPoints; i++ ) {
d = plane.x * p[i].x + plane.y * p[i].y + plane.z;
if ( d < -epsilon ) {
if ( front ) {
return SIDE_CROSS;
}
back = true;
continue;
}
else if ( d > epsilon ) {
if ( back ) {
return SIDE_CROSS;
}
front = true;
continue;
}
}
if ( back ) {
return SIDE_BACK;
}
if ( front ) {
return SIDE_FRONT;
}
return SIDE_ON;
}
/*
============
idWinding2D::PointInside
============
*/
bool idWinding2D::PointInside( const idVec2 &point, const float epsilon ) const {
int i;
float d;
idVec3 plane;
for ( i = 0; i < numPoints; i++ ) {
plane = Plane2DFromPoints( p[i], p[(i+1) % numPoints] );
d = plane.x * point.x + plane.y * point.y + plane.z;
if ( d > epsilon ) {
return false;
}
}
return true;
}
/*
============
idWinding2D::LineIntersection
============
*/
bool idWinding2D::LineIntersection( const idVec2 &start, const idVec2 &end ) const {
int i, numEdges;
int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
float d1, d2, epsilon = 0.1f;
idVec3 plane, edges[2];
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
plane = Plane2DFromPoints( start, end );
for ( i = 0; i < numPoints; i++ ) {
d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z;
if ( d1 > epsilon ) {
sides[i] = SIDE_FRONT;
}
else if ( d1 < -epsilon ) {
sides[i] = SIDE_BACK;
}
else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
if ( !counts[SIDE_FRONT] ) {
return false;
}
if ( !counts[SIDE_BACK] ) {
return false;
}
numEdges = 0;
for ( i = 0; i < numPoints; i++ ) {
if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) {
edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] );
if ( numEdges >= 2 ) {
break;
}
}
}
if ( numEdges < 2 ) {
return false;
}
d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z;
d2 = edges[0].x * end.x + edges[0].y * end.y + edges[0].z;
if ( FLOATSIGNBITNOTSET( d1 ) & FLOATSIGNBITNOTSET( d2 ) ) {
return false;
}
d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z;
d2 = edges[1].x * end.x + edges[1].y * end.y + edges[1].z;
if ( FLOATSIGNBITNOTSET( d1 ) & FLOATSIGNBITNOTSET( d2 ) ) {
return false;
}
return true;
}
/*
============
idWinding2D::RayIntersection
============
*/
bool idWinding2D::RayIntersection( const idVec2 &start, const idVec2 &dir, float &scale1, float &scale2, int *edgeNums ) const {
int i, numEdges, localEdgeNums[2];
int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
float d1, d2, epsilon = 0.1f;
idVec3 plane, edges[2];
scale1 = scale2 = 0.0f;
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
plane = Plane2DFromVecs( start, dir );
for ( i = 0; i < numPoints; i++ ) {
d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z;
if ( d1 > epsilon ) {
sides[i] = SIDE_FRONT;
}
else if ( d1 < -epsilon ) {
sides[i] = SIDE_BACK;
}
else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
if ( !counts[SIDE_FRONT] ) {
return false;
}
if ( !counts[SIDE_BACK] ) {
return false;
}
numEdges = 0;
for ( i = 0; i < numPoints; i++ ) {
if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) {
localEdgeNums[numEdges] = i;
edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] );
if ( numEdges >= 2 ) {
break;
}
}
}
if ( numEdges < 2 ) {
return false;
}
d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z;
d2 = - ( edges[0].x * dir.x + edges[0].y * dir.y );
if ( d2 == 0.0f ) {
return false;
}
scale1 = d1 / d2;
d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z;
d2 = - ( edges[1].x * dir.x + edges[1].y * dir.y );
if ( d2 == 0.0f ) {
return false;
}
scale2 = d1 / d2;
if ( idMath::Fabs( scale1 ) > idMath::Fabs( scale2 ) ) {
idSwap( scale1, scale2 );
idSwap( localEdgeNums[0], localEdgeNums[1] );
}
if ( edgeNums ) {
edgeNums[0] = localEdgeNums[0];
edgeNums[1] = localEdgeNums[1];
}
return true;
}

View File

@@ -0,0 +1,169 @@
/*
===========================================================================
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 __WINDING2D_H__
#define __WINDING2D_H__
/*
===============================================================================
A 2D winding is an arbitrary convex 2D polygon defined by an array of points.
===============================================================================
*/
#define MAX_POINTS_ON_WINDING_2D 16
class idWinding2D {
public:
idWinding2D( void );
idWinding2D & operator=( const idWinding2D &winding );
const idVec2 & operator[]( const int index ) const;
idVec2 & operator[]( const int index );
void Clear( void );
void AddPoint( const idVec2 &point );
int GetNumPoints( void ) const;
void Expand( const float d );
void ExpandForAxialBox( const idVec2 bounds[2] );
// splits the winding into a front and back winding, the winding itself stays unchanged
// returns a SIDE_?
int Split( const idVec3 &plane, const float epsilon, idWinding2D **front, idWinding2D **back ) const;
// cuts off the part at the back side of the plane, returns true if some part was at the front
// if there is nothing at the front the number of points is set to zero
bool ClipInPlace( const idVec3 &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
idWinding2D * Copy( void ) const;
idWinding2D * Reverse( void ) const;
float GetArea( void ) const;
idVec2 GetCenter( void ) const;
float GetRadius( const idVec2 &center ) const;
void GetBounds( idVec2 bounds[2] ) const;
bool IsTiny( void ) const;
bool IsHuge( void ) const; // base winding for a plane is typically huge
void Print( void ) const;
float PlaneDistance( const idVec3 &plane ) const;
int PlaneSide( const idVec3 &plane, const float epsilon = ON_EPSILON ) const;
bool PointInside( const idVec2 &point, const float epsilon ) const;
bool LineIntersection( const idVec2 &start, const idVec2 &end ) const;
bool RayIntersection( const idVec2 &start, const idVec2 &dir, float &scale1, float &scale2, int *edgeNums = NULL ) const;
static idVec3 Plane2DFromPoints( const idVec2 &start, const idVec2 &end, const bool normalize = false );
static idVec3 Plane2DFromVecs( const idVec2 &start, const idVec2 &dir, const bool normalize = false );
static bool Plane2DIntersection( const idVec3 &plane1, const idVec3 &plane2, idVec2 &point );
private:
int numPoints;
idVec2 p[MAX_POINTS_ON_WINDING_2D];
};
ID_INLINE idWinding2D::idWinding2D( void ) {
numPoints = 0;
}
ID_INLINE idWinding2D &idWinding2D::operator=( const idWinding2D &winding ) {
int i;
for ( i = 0; i < winding.numPoints; i++ ) {
p[i] = winding.p[i];
}
numPoints = winding.numPoints;
return *this;
}
ID_INLINE const idVec2 &idWinding2D::operator[]( const int index ) const {
return p[ index ];
}
ID_INLINE idVec2 &idWinding2D::operator[]( const int index ) {
return p[ index ];
}
ID_INLINE void idWinding2D::Clear( void ) {
numPoints = 0;
}
ID_INLINE void idWinding2D::AddPoint( const idVec2 &point ) {
p[numPoints++] = point;
}
ID_INLINE int idWinding2D::GetNumPoints( void ) const {
return numPoints;
}
ID_INLINE idVec3 idWinding2D::Plane2DFromPoints( const idVec2 &start, const idVec2 &end, const bool normalize ) {
idVec3 plane;
plane.x = start.y - end.y;
plane.y = end.x - start.x;
if ( normalize ) {
plane.ToVec2().Normalize();
}
plane.z = - ( start.x * plane.x + start.y * plane.y );
return plane;
}
ID_INLINE idVec3 idWinding2D::Plane2DFromVecs( const idVec2 &start, const idVec2 &dir, const bool normalize ) {
idVec3 plane;
plane.x = -dir.y;
plane.y = dir.x;
if ( normalize ) {
plane.ToVec2().Normalize();
}
plane.z = - ( start.x * plane.x + start.y * plane.y );
return plane;
}
ID_INLINE bool idWinding2D::Plane2DIntersection( const idVec3 &plane1, const idVec3 &plane2, idVec2 &point ) {
float n00, n01, n11, det, invDet, f0, f1;
n00 = plane1.x * plane1.x + plane1.y * plane1.y;
n01 = plane1.x * plane2.x + plane1.y * plane2.y;
n11 = plane2.x * plane2.x + plane2.y * plane2.y;
det = n00 * n11 - n01 * n01;
if ( idMath::Fabs(det) < 1e-6f ) {
return false;
}
invDet = 1.0f / det;
f0 = ( n01 * plane2.z - n11 * plane1.z ) * invDet;
f1 = ( n01 * plane1.z - n00 * plane2.z ) * invDet;
point.x = f0 * plane1.x + f1 * plane2.x;
point.y = f0 * plane1.y + f1 * plane2.y;
return true;
}
#endif /* !__WINDING2D_H__ */