mirror of
https://github.com/id-Software/DOOM-3.git
synced 2026-03-19 16:39:27 +01:00
hello world
This commit is contained in:
44
neo/idlib/geometry/DrawVert.cpp
Normal file
44
neo/idlib/geometry/DrawVert.cpp
Normal 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();
|
||||
}
|
||||
107
neo/idlib/geometry/DrawVert.h
Normal file
107
neo/idlib/geometry/DrawVert.h
Normal 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__ */
|
||||
87
neo/idlib/geometry/JointTransform.cpp
Normal file
87
neo/idlib/geometry/JointTransform.cpp
Normal 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;
|
||||
}
|
||||
245
neo/idlib/geometry/JointTransform.h
Normal file
245
neo/idlib/geometry/JointTransform.h
Normal 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__ */
|
||||
930
neo/idlib/geometry/Surface.cpp
Normal file
930
neo/idlib/geometry/Surface.cpp
Normal 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;
|
||||
}
|
||||
233
neo/idlib/geometry/Surface.h
Normal file
233
neo/idlib/geometry/Surface.h
Normal 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__ */
|
||||
691
neo/idlib/geometry/Surface_Patch.cpp
Normal file
691
neo/idlib/geometry/Surface_Patch.cpp
Normal 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();
|
||||
}
|
||||
146
neo/idlib/geometry/Surface_Patch.h
Normal file
146
neo/idlib/geometry/Surface_Patch.h
Normal 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__ */
|
||||
336
neo/idlib/geometry/Surface_Polytope.cpp
Normal file
336
neo/idlib/geometry/Surface_Polytope.cpp
Normal 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;
|
||||
}
|
||||
70
neo/idlib/geometry/Surface_Polytope.h
Normal file
70
neo/idlib/geometry/Surface_Polytope.h
Normal 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__ */
|
||||
223
neo/idlib/geometry/Surface_SweptSpline.cpp
Normal file
223
neo/idlib/geometry/Surface_SweptSpline.cpp
Normal 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();
|
||||
}
|
||||
93
neo/idlib/geometry/Surface_SweptSpline.h
Normal file
93
neo/idlib/geometry/Surface_SweptSpline.h
Normal 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__ */
|
||||
1494
neo/idlib/geometry/TraceModel.cpp
Normal file
1494
neo/idlib/geometry/TraceModel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
189
neo/idlib/geometry/TraceModel.h
Normal file
189
neo/idlib/geometry/TraceModel.h
Normal 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 ¢erOfMass, 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__ */
|
||||
|
||||
1601
neo/idlib/geometry/Winding.cpp
Normal file
1601
neo/idlib/geometry/Winding.cpp
Normal file
File diff suppressed because it is too large
Load Diff
401
neo/idlib/geometry/Winding.h
Normal file
401
neo/idlib/geometry/Winding.h
Normal 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 ¢er ) 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__ */
|
||||
754
neo/idlib/geometry/Winding2D.cpp
Normal file
754
neo/idlib/geometry/Winding2D.cpp
Normal 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 ¢er ) 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;
|
||||
}
|
||||
169
neo/idlib/geometry/Winding2D.h
Normal file
169
neo/idlib/geometry/Winding2D.h
Normal 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 ¢er ) 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__ */
|
||||
Reference in New Issue
Block a user