mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2026-03-20 09:00:25 +01:00
Initial commit
This commit is contained in:
76
neo/idlib/geometry/DrawVert.cpp
Normal file
76
neo/idlib/geometry/DrawVert.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
============
|
||||
idShadowVert::CreateShadowCache
|
||||
============
|
||||
*/
|
||||
int idShadowVert::CreateShadowCache( idShadowVert * vertexCache, const idDrawVert *verts, const int numVerts ) {
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
vertexCache[i*2+0].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[i*2+0].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[i*2+0].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[i*2+0].xyzw[3] = 1.0f;
|
||||
|
||||
vertexCache[i*2+1].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[i*2+1].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[i*2+1].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[i*2+1].xyzw[3] = 0.0f;
|
||||
}
|
||||
return numVerts * 2;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
idShadowVertSkinned::CreateShadowCache
|
||||
===================
|
||||
*/
|
||||
int idShadowVertSkinned::CreateShadowCache( idShadowVertSkinned * vertexCache, const idDrawVert *verts, const int numVerts ) {
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
vertexCache[0].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[0].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[0].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[0].xyzw[3] = 1.0f;
|
||||
*(unsigned int *)vertexCache[0].color = *(unsigned int *)verts[i].color;
|
||||
*(unsigned int *)vertexCache[0].color2 = *(unsigned int *)verts[i].color2;
|
||||
|
||||
vertexCache[1].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[1].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[1].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[1].xyzw[3] = 0.0f;
|
||||
*(unsigned int *)vertexCache[1].color = *(unsigned int *)verts[i].color;
|
||||
*(unsigned int *)vertexCache[1].color2 = *(unsigned int *)verts[i].color2;
|
||||
|
||||
vertexCache += 2;
|
||||
}
|
||||
return numVerts * 2;
|
||||
}
|
||||
739
neo/idlib/geometry/DrawVert.h
Normal file
739
neo/idlib/geometry/DrawVert.h
Normal file
@@ -0,0 +1,739 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DRAWVERT_H__
|
||||
#define __DRAWVERT_H__
|
||||
|
||||
// The hardware converts a byte to a float by division with 255 and in the
|
||||
// vertex programs we convert the floating-point value in the range [0, 1]
|
||||
// to the range [-1, 1] by multiplying with 2 and subtracting 1.
|
||||
#define VERTEX_BYTE_TO_FLOAT( x ) ( (x) * ( 2.0f / 255.0f ) - 1.0f )
|
||||
#define VERTEX_FLOAT_TO_BYTE( x ) idMath::Ftob( ( (x) + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f )
|
||||
|
||||
// The hardware converts a byte to a float by division with 255 and in the
|
||||
// fragment programs we convert the floating-point value in the range [0, 1]
|
||||
// to the range [-1, 1] by multiplying with 2 and subtracting 1.
|
||||
// This is the conventional OpenGL mapping which specifies an exact
|
||||
// representation for -1 and +1 but not 0. The DirectX 10 mapping is
|
||||
// in the comments which specifies a non-linear mapping with an exact
|
||||
// representation of -1, 0 and +1 but -1 is represented twice.
|
||||
#define NORMALMAP_BYTE_TO_FLOAT( x ) VERTEX_BYTE_TO_FLOAT( x ) //( (x) - 128.0f ) * ( 1.0f / 127.0f )
|
||||
#define NORMALMAP_FLOAT_TO_BYTE( x ) VERTEX_FLOAT_TO_BYTE( x ) //idMath::Ftob( 128.0f + 127.0f * (x) + 0.5f )
|
||||
|
||||
/*
|
||||
================================================
|
||||
halfFloat_t
|
||||
================================================
|
||||
*/
|
||||
typedef unsigned short halfFloat_t;
|
||||
|
||||
// GPU half-float bit patterns
|
||||
#define HF_MANTISSA(x) (x&1023)
|
||||
#define HF_EXP(x) ((x&32767)>>10)
|
||||
#define HF_SIGN(x) ((x&32768)?-1:1)
|
||||
|
||||
/*
|
||||
========================
|
||||
F16toF32
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float F16toF32( halfFloat_t x ) {
|
||||
int e = HF_EXP( x );
|
||||
int m = HF_MANTISSA( x );
|
||||
int s = HF_SIGN( x );
|
||||
|
||||
if ( 0 < e && e < 31 ) {
|
||||
return s * powf( 2.0f, ( e - 15.0f ) ) * ( 1 + m / 1024.0f );
|
||||
} else if ( m == 0 ) {
|
||||
return s * 0.0f;
|
||||
}
|
||||
return s * powf( 2.0f, -14.0f ) * ( m / 1024.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
F32toF16
|
||||
========================
|
||||
*/
|
||||
ID_INLINE halfFloat_t F32toF16( float a ) {
|
||||
unsigned int f = *(unsigned *)( &a );
|
||||
unsigned int signbit = ( f & 0x80000000 ) >> 16;
|
||||
int exponent = ( ( f & 0x7F800000 ) >> 23 ) - 112;
|
||||
unsigned int mantissa = ( f & 0x007FFFFF );
|
||||
|
||||
if ( exponent <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
if ( exponent > 30 ) {
|
||||
return (halfFloat_t)( signbit | 0x7BFF );
|
||||
}
|
||||
|
||||
return (halfFloat_t)( signbit | ( exponent << 10 ) | ( mantissa >> 13 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Draw Vertex.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idDrawVert {
|
||||
public:
|
||||
idVec3 xyz; // 12 bytes
|
||||
halfFloat_t st[2]; // 4 bytes
|
||||
byte normal[4]; // 4 bytes
|
||||
byte tangent[4]; // 4 bytes -- [3] is texture polarity sign
|
||||
byte color[4]; // 4 bytes
|
||||
byte color2[4]; // 4 bytes -- weights for skinning
|
||||
|
||||
float operator[]( const int index ) const;
|
||||
float & operator[]( const int index );
|
||||
|
||||
void Clear();
|
||||
|
||||
const idVec3 GetNormal() const;
|
||||
const idVec3 GetNormalRaw() const; // not re-normalized for renderbump
|
||||
|
||||
// must be normalized already!
|
||||
void SetNormal( float x, float y, float z );
|
||||
void SetNormal( const idVec3 & n );
|
||||
|
||||
const idVec3 GetTangent() const;
|
||||
const idVec3 GetTangentRaw() const; // not re-normalized for renderbump
|
||||
|
||||
// must be normalized already!
|
||||
void SetTangent( float x, float y, float z );
|
||||
void SetTangent( const idVec3 & t );
|
||||
|
||||
// derived from normal, tangent, and tangent flag
|
||||
const idVec3 GetBiTangent() const;
|
||||
const idVec3 GetBiTangentRaw() const; // not re-normalized for renderbump
|
||||
|
||||
void SetBiTangent( float x, float y, float z );
|
||||
ID_INLINE void SetBiTangent( const idVec3 & t );
|
||||
|
||||
float GetBiTangentSign() const;
|
||||
byte GetBiTangentSignBit() const;
|
||||
|
||||
void SetTexCoordNative( const halfFloat_t s, const halfFloat_t t );
|
||||
void SetTexCoord( const idVec2 & st );
|
||||
void SetTexCoord( float s, float t );
|
||||
void SetTexCoordS( float s );
|
||||
void SetTexCoordT( float t );
|
||||
const idVec2 GetTexCoord() const;
|
||||
const halfFloat_t GetTexCoordNativeS() const;
|
||||
const halfFloat_t GetTexCoordNativeT() const;
|
||||
|
||||
// either 1.0f or -1.0f
|
||||
ID_INLINE void SetBiTangentSign( float sign );
|
||||
ID_INLINE void SetBiTangentSignBit( byte bit );
|
||||
|
||||
void Lerp( const idDrawVert &a, const idDrawVert &b, const float f );
|
||||
void LerpAll( const idDrawVert &a, const idDrawVert &b, const float f );
|
||||
|
||||
void SetColor( dword color );
|
||||
void SetNativeOrderColor( dword color );
|
||||
dword GetColor() const;
|
||||
|
||||
void SetColor2( dword color );
|
||||
void SetNativeOrderColor2( dword color );
|
||||
void ClearColor2();
|
||||
dword GetColor2() const;
|
||||
|
||||
static idDrawVert GetSkinnedDrawVert( const idDrawVert & vert, const idJointMat * joints );
|
||||
static idVec3 GetSkinnedDrawVertPosition( const idDrawVert & vert, const idJointMat * joints );
|
||||
};
|
||||
|
||||
#define DRAWVERT_SIZE 32
|
||||
#define DRAWVERT_XYZ_OFFSET (0*4)
|
||||
#define DRAWVERT_ST_OFFSET (3*4)
|
||||
#define DRAWVERT_NORMAL_OFFSET (4*4)
|
||||
#define DRAWVERT_TANGENT_OFFSET (5*4)
|
||||
#define DRAWVERT_COLOR_OFFSET (6*4)
|
||||
#define DRAWVERT_COLOR2_OFFSET (7*4)
|
||||
|
||||
assert_offsetof( idDrawVert, xyz, DRAWVERT_XYZ_OFFSET );
|
||||
assert_offsetof( idDrawVert, normal, DRAWVERT_NORMAL_OFFSET );
|
||||
assert_offsetof( idDrawVert, tangent, DRAWVERT_TANGENT_OFFSET );
|
||||
|
||||
/*
|
||||
========================
|
||||
VertexFloatToByte
|
||||
|
||||
Assumes input is in the range [-1, 1]
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void VertexFloatToByte( const float & x, const float & y, const float & z, byte * bval ) {
|
||||
assert_4_byte_aligned( bval ); // for __stvebx
|
||||
|
||||
|
||||
const __m128 vector_float_one = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const __m128 vector_float_half = { 0.5f, 0.5f, 0.5f, 0.5f };
|
||||
const __m128 vector_float_255_over_2 = { 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f };
|
||||
|
||||
const __m128 xyz = _mm_unpacklo_ps( _mm_unpacklo_ps( _mm_load_ss( &x ), _mm_load_ss( &z ) ), _mm_load_ss( &y ) );
|
||||
const __m128 xyzScaled = _mm_madd_ps( _mm_add_ps( xyz, vector_float_one ), vector_float_255_over_2, vector_float_half );
|
||||
const __m128i xyzInt = _mm_cvtps_epi32( xyzScaled );
|
||||
const __m128i xyzShort = _mm_packs_epi32( xyzInt, xyzInt );
|
||||
const __m128i xyzChar = _mm_packus_epi16( xyzShort, xyzShort );
|
||||
const __m128i xyz16 = _mm_unpacklo_epi8( xyzChar, _mm_setzero_si128() );
|
||||
|
||||
bval[0] = (byte)_mm_extract_epi16( xyz16, 0 ); // cannot use _mm_extract_epi8 because it is an SSE4 instruction
|
||||
bval[1] = (byte)_mm_extract_epi16( xyz16, 1 );
|
||||
bval[2] = (byte)_mm_extract_epi16( xyz16, 2 );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::operator[]
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float idDrawVert::operator[]( const int index ) const {
|
||||
assert( index >= 0 && index < 5 );
|
||||
return ((float *)(&xyz))[index];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::operator[]
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float &idDrawVert::operator[]( const int index ) {
|
||||
assert( index >= 0 && index < 5 );
|
||||
return ((float *)(&xyz))[index];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::Clear
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::Clear() {
|
||||
*reinterpret_cast<dword *>(&this->xyz.x) = 0;
|
||||
*reinterpret_cast<dword *>(&this->xyz.y) = 0;
|
||||
*reinterpret_cast<dword *>(&this->xyz.z) = 0;
|
||||
*reinterpret_cast<dword *>(this->st) = 0;
|
||||
*reinterpret_cast<dword *>(this->normal) = 0x00FF8080; // x=0, y=0, z=1
|
||||
*reinterpret_cast<dword *>(this->tangent) = 0xFF8080FF; // x=1, y=0, z=0
|
||||
*reinterpret_cast<dword *>(this->color) = 0;
|
||||
*reinterpret_cast<dword *>(this->color2) = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetNormal
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetNormal() const {
|
||||
idVec3 n( VERTEX_BYTE_TO_FLOAT( normal[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[2] ) );
|
||||
n.Normalize(); // after the normal has been compressed & uncompressed, it may not be normalized anymore
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetNormalRaw
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetNormalRaw() const {
|
||||
idVec3 n( VERTEX_BYTE_TO_FLOAT( normal[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[2] ) );
|
||||
// don't re-normalize just like we do in the vertex programs
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNormal
|
||||
must be normalized already!
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNormal( const idVec3 & n ) {
|
||||
VertexFloatToByte( n.x, n.y, n.z, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNormal
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNormal( float x, float y, float z ) {
|
||||
VertexFloatToByte( x, y, z, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
&idDrawVert::GetTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetTangent() const {
|
||||
idVec3 t( VERTEX_BYTE_TO_FLOAT( tangent[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[2] ) );
|
||||
t.Normalize();
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
&idDrawVert::GetTangentRaw
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetTangentRaw() const {
|
||||
idVec3 t( VERTEX_BYTE_TO_FLOAT( tangent[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[2] ) );
|
||||
// don't re-normalize just like we do in the vertex programs
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTangent( float x, float y, float z ) {
|
||||
VertexFloatToByte( x, y, z, tangent );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTangent( const idVec3 & t ) {
|
||||
VertexFloatToByte( t.x, t.y, t.z, tangent );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetBiTangent() const {
|
||||
// derive from the normal, tangent, and bitangent direction flag
|
||||
idVec3 bitangent;
|
||||
bitangent.Cross( GetNormal(), GetTangent() );
|
||||
bitangent *= GetBiTangentSign();
|
||||
return bitangent;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangentRaw
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetBiTangentRaw() const {
|
||||
// derive from the normal, tangent, and bitangent direction flag
|
||||
// don't re-normalize just like we do in the vertex programs
|
||||
idVec3 bitangent;
|
||||
bitangent.Cross( GetNormalRaw(), GetTangentRaw() );
|
||||
bitangent *= GetBiTangentSign();
|
||||
return bitangent;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangent( float x, float y, float z ) {
|
||||
SetBiTangent( idVec3( x, y, z ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangent( const idVec3 &t ) {
|
||||
idVec3 bitangent;
|
||||
bitangent.Cross( GetNormal(), GetTangent() );
|
||||
SetBiTangentSign( bitangent * t );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangentSign
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float idDrawVert::GetBiTangentSign() const {
|
||||
return ( tangent[3] < 128 ) ? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangentSignBit
|
||||
========================
|
||||
*/
|
||||
ID_INLINE byte idDrawVert::GetBiTangentSignBit() const {
|
||||
return ( tangent[3] < 128 ) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangentSign
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangentSign( float sign ) {
|
||||
tangent[3] = ( sign < 0.0f ) ? 0 : 255;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangentSignBit
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangentSignBit( byte sign ) {
|
||||
tangent[3] = sign ? 0 : 255;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::Lerp
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::Lerp( const idDrawVert &a, const idDrawVert &b, const float f ) {
|
||||
xyz = a.xyz + f * ( b.xyz - a.xyz );
|
||||
SetTexCoord( ::Lerp( a.GetTexCoord(), b.GetTexCoord(), f ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::LerpAll
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::LerpAll( const idDrawVert &a, const idDrawVert &b, const float f ) {
|
||||
xyz = ::Lerp( a.xyz, b.xyz, f );
|
||||
SetTexCoord( ::Lerp( a.GetTexCoord(), b.GetTexCoord(), f ) );
|
||||
|
||||
idVec3 normal = ::Lerp( a.GetNormal(), b.GetNormal(), f );
|
||||
idVec3 tangent = ::Lerp( a.GetTangent(), b.GetTangent(), f );
|
||||
idVec3 bitangent = ::Lerp( a.GetBiTangent(), b.GetBiTangent(), f );
|
||||
normal.Normalize();
|
||||
tangent.Normalize();
|
||||
bitangent.Normalize();
|
||||
SetNormal( normal );
|
||||
SetTangent( tangent );
|
||||
SetBiTangent( bitangent );
|
||||
|
||||
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] ) );
|
||||
|
||||
color2[0] = (byte)( a.color2[0] + f * ( b.color2[0] - a.color2[0] ) );
|
||||
color2[1] = (byte)( a.color2[1] + f * ( b.color2[1] - a.color2[1] ) );
|
||||
color2[2] = (byte)( a.color2[2] + f * ( b.color2[2] - a.color2[2] ) );
|
||||
color2[3] = (byte)( a.color2[3] + f * ( b.color2[3] - a.color2[3] ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNativeOrderColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNativeOrderColor( dword color ) {
|
||||
*reinterpret_cast<dword *>(this->color) = color;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetColor( dword color ) {
|
||||
*reinterpret_cast<dword *>(this->color) = color;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE dword idDrawVert::GetColor() const {
|
||||
return *reinterpret_cast<const dword *>(this->color);
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoordNative
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoordNative( const halfFloat_t s, const halfFloat_t t ) {
|
||||
st[0] = s;
|
||||
st[1] = t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoord
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoord( const idVec2 & st ) {
|
||||
SetTexCoordS( st.x );
|
||||
SetTexCoordT( st.y );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoord
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoord( float s, float t ) {
|
||||
SetTexCoordS( s );
|
||||
SetTexCoordT( t );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoordS
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoordS( float s ) {
|
||||
st[0] = F32toF16( s );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoordT
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoordT( float t ) {
|
||||
st[1] = F32toF16( t );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoord
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec2 idDrawVert::GetTexCoord() const {
|
||||
return idVec2( F16toF32( st[0] ), F16toF32( st[1] ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordNativeS
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const halfFloat_t idDrawVert::GetTexCoordNativeS() const {
|
||||
return st[0];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordNativeT
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const halfFloat_t idDrawVert::GetTexCoordNativeT() const {
|
||||
return st[1];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNativeOrderColor2
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNativeOrderColor2( dword color2 ) {
|
||||
*reinterpret_cast<dword *>(this->color2) = color2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetColor2( dword color2 ) {
|
||||
*reinterpret_cast<dword *>(this->color2) = color2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::ClearColor2
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::ClearColor2() {
|
||||
*reinterpret_cast<dword *>(this->color2) = 0x80808080;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetColor2
|
||||
========================
|
||||
*/
|
||||
ID_INLINE dword idDrawVert::GetColor2() const {
|
||||
return *reinterpret_cast<const dword *>(this->color2);
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
WriteDrawVerts16
|
||||
|
||||
Use 16-byte in-order SIMD writes because the destVerts may live in write-combined memory
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void WriteDrawVerts16( idDrawVert * destVerts, const idDrawVert * localVerts, int numVerts ) {
|
||||
assert_sizeof( idDrawVert, 32 );
|
||||
assert_16_byte_aligned( destVerts );
|
||||
assert_16_byte_aligned( localVerts );
|
||||
|
||||
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
__m128i v0 = _mm_load_si128( (const __m128i *)( (byte *)( localVerts + i ) + 0 ) );
|
||||
__m128i v1 = _mm_load_si128( (const __m128i *)( (byte *)( localVerts + i ) + 16 ) );
|
||||
_mm_stream_si128( (__m128i *)( (byte *)( destVerts + i ) + 0 ), v0 );
|
||||
_mm_stream_si128( (__m128i *)( (byte *)( destVerts + i ) + 16 ), v1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idDrawVert::GetSkinnedDrawVert
|
||||
=====================
|
||||
*/
|
||||
ID_INLINE idDrawVert idDrawVert::GetSkinnedDrawVert( const idDrawVert & vert, const idJointMat * joints ) {
|
||||
if ( joints == NULL ) {
|
||||
return vert;
|
||||
}
|
||||
|
||||
const idJointMat & j0 = joints[vert.color[0]];
|
||||
const idJointMat & j1 = joints[vert.color[1]];
|
||||
const idJointMat & j2 = joints[vert.color[2]];
|
||||
const idJointMat & j3 = joints[vert.color[3]];
|
||||
|
||||
const float w0 = vert.color2[0] * ( 1.0f / 255.0f );
|
||||
const float w1 = vert.color2[1] * ( 1.0f / 255.0f );
|
||||
const float w2 = vert.color2[2] * ( 1.0f / 255.0f );
|
||||
const float w3 = vert.color2[3] * ( 1.0f / 255.0f );
|
||||
|
||||
idJointMat accum;
|
||||
idJointMat::Mul( accum, j0, w0 );
|
||||
idJointMat::Mad( accum, j1, w1 );
|
||||
idJointMat::Mad( accum, j2, w2 );
|
||||
idJointMat::Mad( accum, j3, w3 );
|
||||
|
||||
idDrawVert outVert;
|
||||
outVert.xyz = accum * idVec4( vert.xyz.x, vert.xyz.y, vert.xyz.z, 1.0f );
|
||||
outVert.SetTexCoordNative( vert.GetTexCoordNativeS(), vert.GetTexCoordNativeT() );
|
||||
outVert.SetNormal( accum * vert.GetNormal() );
|
||||
outVert.SetTangent( accum * vert.GetTangent() );
|
||||
outVert.tangent[3] = vert.tangent[3];
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
outVert.color[i] = vert.color[i];
|
||||
outVert.color2[i] = vert.color2[i];
|
||||
}
|
||||
return outVert;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idDrawVert::GetSkinnedDrawVertPosition
|
||||
=====================
|
||||
*/
|
||||
ID_INLINE idVec3 idDrawVert::GetSkinnedDrawVertPosition( const idDrawVert & vert, const idJointMat * joints ) {
|
||||
if ( joints == NULL ) {
|
||||
return vert.xyz;
|
||||
}
|
||||
|
||||
const idJointMat & j0 = joints[vert.color[0]];
|
||||
const idJointMat & j1 = joints[vert.color[1]];
|
||||
const idJointMat & j2 = joints[vert.color[2]];
|
||||
const idJointMat & j3 = joints[vert.color[3]];
|
||||
|
||||
const float w0 = vert.color2[0] * ( 1.0f / 255.0f );
|
||||
const float w1 = vert.color2[1] * ( 1.0f / 255.0f );
|
||||
const float w2 = vert.color2[2] * ( 1.0f / 255.0f );
|
||||
const float w3 = vert.color2[3] * ( 1.0f / 255.0f );
|
||||
|
||||
idJointMat accum;
|
||||
idJointMat::Mul( accum, j0, w0 );
|
||||
idJointMat::Mad( accum, j1, w1 );
|
||||
idJointMat::Mad( accum, j2, w2 );
|
||||
idJointMat::Mad( accum, j3, w3 );
|
||||
|
||||
return accum * idVec4( vert.xyz.x, vert.xyz.y, vert.xyz.z, 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
Shadow Vertex
|
||||
===============================================================================
|
||||
*/
|
||||
class idShadowVert {
|
||||
public:
|
||||
idVec4 xyzw;
|
||||
|
||||
void Clear();
|
||||
static int CreateShadowCache( idShadowVert * vertexCache, const idDrawVert *verts, const int numVerts );
|
||||
};
|
||||
|
||||
#define SHADOWVERT_XYZW_OFFSET (0)
|
||||
|
||||
assert_offsetof( idShadowVert, xyzw, SHADOWVERT_XYZW_OFFSET );
|
||||
|
||||
ID_INLINE void idShadowVert::Clear() {
|
||||
xyzw.Zero();
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
Skinned Shadow Vertex
|
||||
===============================================================================
|
||||
*/
|
||||
class idShadowVertSkinned {
|
||||
public:
|
||||
idVec4 xyzw;
|
||||
byte color[4];
|
||||
byte color2[4];
|
||||
byte pad[8]; // pad to multiple of 32-byte for glDrawElementsBaseVertex
|
||||
|
||||
void Clear();
|
||||
static int CreateShadowCache( idShadowVertSkinned * vertexCache, const idDrawVert *verts, const int numVerts );
|
||||
};
|
||||
|
||||
#define SHADOWVERTSKINNED_XYZW_OFFSET (0)
|
||||
#define SHADOWVERTSKINNED_COLOR_OFFSET (16)
|
||||
#define SHADOWVERTSKINNED_COLOR2_OFFSET (20)
|
||||
|
||||
assert_offsetof( idShadowVertSkinned, xyzw, SHADOWVERTSKINNED_XYZW_OFFSET );
|
||||
assert_offsetof( idShadowVertSkinned, color, SHADOWVERTSKINNED_COLOR_OFFSET );
|
||||
assert_offsetof( idShadowVertSkinned, color2, SHADOWVERTSKINNED_COLOR2_OFFSET );
|
||||
|
||||
ID_INLINE void idShadowVertSkinned::Clear() {
|
||||
xyzw.Zero();
|
||||
}
|
||||
|
||||
#endif /* !__DRAWVERT_H__ */
|
||||
200
neo/idlib/geometry/DrawVert_intrinsics.h
Normal file
200
neo/idlib/geometry/DrawVert_intrinsics.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DRAWVERT_INTRINSICS_H__
|
||||
#define __DRAWVERT_INTRINSICS_H__
|
||||
|
||||
|
||||
static const __m128i vector_int_f32_sign_mask = _mm_set1_epi32( 1U << IEEE_FLT_SIGN_BIT );
|
||||
static const __m128i vector_int_f32_exponent_mask = _mm_set1_epi32( ( ( 1U << IEEE_FLT_EXPONENT_BITS ) - 1 ) << IEEE_FLT_MANTISSA_BITS );
|
||||
static const __m128i vector_int_f32_mantissa_mask = _mm_set1_epi32( ( 1U << IEEE_FLT_MANTISSA_BITS ) - 1 );
|
||||
static const __m128i vector_int_f16_min_exponent = _mm_set1_epi32( 0 );
|
||||
static const __m128i vector_int_f16_max_exponent = _mm_set1_epi32( ( 30 << IEEE_FLT16_MANTISSA_BITS ) );
|
||||
static const __m128i vector_int_f16_min_mantissa = _mm_set1_epi32( 0 );
|
||||
static const __m128i vector_int_f16_max_mantissa = _mm_set1_epi32( ( ( 1 << IEEE_FLT16_MANTISSA_BITS ) - 1 ) );
|
||||
static const __m128i vector_int_f32_to_f16_exponent_bias = _mm_set1_epi32( ( IEEE_FLT_EXPONENT_BIAS - IEEE_FLT16_EXPONENT_BIAS ) << IEEE_FLT16_MANTISSA_BITS );
|
||||
static const int f32_to_f16_sign_shift = IEEE_FLT_SIGN_BIT - IEEE_FLT16_SIGN_BIT;
|
||||
static const int f32_to_f16_exponent_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
static const int f32_to_f16_mantissa_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
|
||||
static const __m128i vector_int_zero = _mm_setzero_si128();
|
||||
static const __m128i vector_int_one = _mm_set_epi32( 1, 1, 1, 1 );
|
||||
|
||||
static const __m128 vector_float_mask_clear_last = __m128c( _mm_set_epi32( 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ) );
|
||||
static const __m128 vector_float_last_one = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
static const __m128 vector_float_1_over_255 = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f };
|
||||
static const __m128 vector_float_1_over_4 = { 1.0f / 4.0f, 1.0f / 4.0f, 1.0f / 4.0f, 1.0f / 4.0f };
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
FastF32toF16
|
||||
====================
|
||||
*/
|
||||
|
||||
ID_INLINE_EXTERN __m128i FastF32toF16( __m128i f32_bits ) {
|
||||
__m128i f16_sign = _mm_srli_epi32( _mm_and_si128( f32_bits, vector_int_f32_sign_mask ), f32_to_f16_sign_shift );
|
||||
__m128i f16_exponent = _mm_srli_epi32( _mm_and_si128( f32_bits, vector_int_f32_exponent_mask ), f32_to_f16_exponent_shift );
|
||||
__m128i f16_mantissa = _mm_srli_epi32( _mm_and_si128( f32_bits, vector_int_f32_mantissa_mask ), f32_to_f16_mantissa_shift );
|
||||
|
||||
f16_exponent = _mm_sub_epi32( f16_exponent, vector_int_f32_to_f16_exponent_bias );
|
||||
|
||||
const __m128i underflow = _mm_cmplt_epi32( f16_exponent, vector_int_f16_min_exponent );
|
||||
const __m128i overflow = _mm_cmpgt_epi32( f16_exponent, vector_int_f16_max_exponent );
|
||||
|
||||
f16_exponent = _mm_sel_si128( f16_exponent, vector_int_f16_min_exponent, underflow );
|
||||
f16_exponent = _mm_sel_si128( f16_exponent, vector_int_f16_max_exponent, overflow );
|
||||
f16_mantissa = _mm_sel_si128( f16_mantissa, vector_int_f16_min_mantissa, underflow );
|
||||
f16_mantissa = _mm_sel_si128( f16_mantissa, vector_int_f16_max_mantissa, overflow );
|
||||
|
||||
__m128i flt16 = _mm_or_si128( _mm_or_si128( f16_sign, f16_exponent ), f16_mantissa );
|
||||
|
||||
return _mm_packs_epi32( flt16, flt16 );
|
||||
}
|
||||
|
||||
|
||||
ID_INLINE_EXTERN halfFloat_t Scalar_FastF32toF16( float f32 ) {
|
||||
const int f32_sign_mask = 1U << IEEE_FLT_SIGN_BIT;
|
||||
const int f32_exponent_mask = ( ( 1U << IEEE_FLT_EXPONENT_BITS ) - 1 ) << IEEE_FLT_MANTISSA_BITS;
|
||||
const int f32_mantissa_mask = ( 1U << IEEE_FLT_MANTISSA_BITS ) - 1;
|
||||
const int f16_min_exponent = 0;
|
||||
const int f16_max_exponent = ( 30 << IEEE_FLT16_MANTISSA_BITS );
|
||||
const int f16_min_mantissa = 0;
|
||||
const int f16_max_mantissa = ( ( 1 << IEEE_FLT16_MANTISSA_BITS ) - 1 );
|
||||
const int f32_to_f16_sign_shift = IEEE_FLT_SIGN_BIT - IEEE_FLT16_SIGN_BIT;
|
||||
const int f32_to_f16_exponent_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
const int f32_to_f16_mantissa_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
const int f32_to_f16_exponent_bias = ( IEEE_FLT_EXPONENT_BIAS - IEEE_FLT16_EXPONENT_BIAS ) << IEEE_FLT16_MANTISSA_BITS;
|
||||
|
||||
int f32_bits = *(unsigned int *)&f32;
|
||||
|
||||
int f16_sign = ( (unsigned int )( f32_bits & f32_sign_mask ) >> f32_to_f16_sign_shift );
|
||||
int f16_exponent = ( (unsigned int )( f32_bits & f32_exponent_mask ) >> f32_to_f16_exponent_shift );
|
||||
int f16_mantissa = ( (unsigned int )( f32_bits & f32_mantissa_mask ) >> f32_to_f16_mantissa_shift );
|
||||
|
||||
f16_exponent -= f32_to_f16_exponent_bias;
|
||||
|
||||
const bool underflow = ( f16_exponent < f16_min_exponent );
|
||||
const bool overflow = ( f16_exponent > f16_max_exponent );
|
||||
|
||||
f16_exponent = underflow ? f16_min_exponent : f16_exponent;
|
||||
f16_exponent = overflow ? f16_max_exponent : f16_exponent;
|
||||
f16_mantissa = underflow ? f16_min_mantissa : f16_mantissa;
|
||||
f16_mantissa = overflow ? f16_max_mantissa : f16_mantissa;
|
||||
|
||||
return (halfFloat_t)( f16_sign | f16_exponent | f16_mantissa );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
LoadSkinnedDrawVertPosition
|
||||
====================
|
||||
*/
|
||||
|
||||
ID_INLINE_EXTERN __m128 LoadSkinnedDrawVertPosition( const idDrawVert & base, const idJointMat * joints ) {
|
||||
const idJointMat & j0 = joints[base.color[0]];
|
||||
const idJointMat & j1 = joints[base.color[1]];
|
||||
const idJointMat & j2 = joints[base.color[2]];
|
||||
const idJointMat & j3 = joints[base.color[3]];
|
||||
|
||||
__m128i weights_b = _mm_cvtsi32_si128( *(const unsigned int *)base.color2 );
|
||||
__m128i weights_s = _mm_unpacklo_epi8( weights_b, vector_int_zero );
|
||||
__m128i weights_i = _mm_unpacklo_epi16( weights_s, vector_int_zero );
|
||||
|
||||
__m128 weights = _mm_cvtepi32_ps( weights_i );
|
||||
weights = _mm_mul_ps( weights, vector_float_1_over_255 );
|
||||
|
||||
__m128 w0 = _mm_splat_ps( weights, 0 );
|
||||
__m128 w1 = _mm_splat_ps( weights, 1 );
|
||||
__m128 w2 = _mm_splat_ps( weights, 2 );
|
||||
__m128 w3 = _mm_splat_ps( weights, 3 );
|
||||
|
||||
__m128 matX = _mm_mul_ps( _mm_load_ps( j0.ToFloatPtr() + 0 * 4 ), w0 );
|
||||
__m128 matY = _mm_mul_ps( _mm_load_ps( j0.ToFloatPtr() + 1 * 4 ), w0 );
|
||||
__m128 matZ = _mm_mul_ps( _mm_load_ps( j0.ToFloatPtr() + 2 * 4 ), w0 );
|
||||
|
||||
matX = _mm_madd_ps( _mm_load_ps( j1.ToFloatPtr() + 0 * 4 ), w1, matX );
|
||||
matY = _mm_madd_ps( _mm_load_ps( j1.ToFloatPtr() + 1 * 4 ), w1, matY );
|
||||
matZ = _mm_madd_ps( _mm_load_ps( j1.ToFloatPtr() + 2 * 4 ), w1, matZ );
|
||||
|
||||
matX = _mm_madd_ps( _mm_load_ps( j2.ToFloatPtr() + 0 * 4 ), w2, matX );
|
||||
matY = _mm_madd_ps( _mm_load_ps( j2.ToFloatPtr() + 1 * 4 ), w2, matY );
|
||||
matZ = _mm_madd_ps( _mm_load_ps( j2.ToFloatPtr() + 2 * 4 ), w2, matZ );
|
||||
|
||||
matX = _mm_madd_ps( _mm_load_ps( j3.ToFloatPtr() + 0 * 4 ), w3, matX );
|
||||
matY = _mm_madd_ps( _mm_load_ps( j3.ToFloatPtr() + 1 * 4 ), w3, matY );
|
||||
matZ = _mm_madd_ps( _mm_load_ps( j3.ToFloatPtr() + 2 * 4 ), w3, matZ );
|
||||
|
||||
__m128 v = _mm_load_ps( base.xyz.ToFloatPtr() );
|
||||
v = _mm_and_ps( v, vector_float_mask_clear_last );
|
||||
v = _mm_or_ps( v, vector_float_last_one );
|
||||
|
||||
__m128 t0 = _mm_mul_ps( matX, v );
|
||||
__m128 t1 = _mm_mul_ps( matY, v );
|
||||
__m128 t2 = _mm_mul_ps( matZ, v );
|
||||
__m128 t3 = vector_float_1_over_4;
|
||||
|
||||
__m128 s0 = _mm_unpacklo_ps( t0, t2 ); // x0, z0, x1, z1
|
||||
__m128 s1 = _mm_unpackhi_ps( t0, t2 ); // x2, z2, x3, z3
|
||||
__m128 s2 = _mm_unpacklo_ps( t1, t3 ); // y0, w0, y1, w1
|
||||
__m128 s3 = _mm_unpackhi_ps( t1, t3 ); // y2, w2, y3, w3
|
||||
|
||||
__m128 r0 = _mm_unpacklo_ps( s0, s2 ); // x0, y0, z0, w0
|
||||
__m128 r1 = _mm_unpackhi_ps( s0, s2 ); // x1, y1, z1, w1
|
||||
__m128 r2 = _mm_unpacklo_ps( s1, s3 ); // x2, y2, z2, w2
|
||||
__m128 r3 = _mm_unpackhi_ps( s1, s3 ); // x3, y3, z3, w3
|
||||
|
||||
r0 = _mm_add_ps( r0, r1 );
|
||||
r2 = _mm_add_ps( r2, r3 );
|
||||
r0 = _mm_add_ps( r0, r2 );
|
||||
|
||||
return r0;
|
||||
}
|
||||
|
||||
|
||||
ID_INLINE_EXTERN idVec3 Scalar_LoadSkinnedDrawVertPosition( const idDrawVert & vert, const idJointMat * joints ) {
|
||||
const idJointMat & j0 = joints[vert.color[0]];
|
||||
const idJointMat & j1 = joints[vert.color[1]];
|
||||
const idJointMat & j2 = joints[vert.color[2]];
|
||||
const idJointMat & j3 = joints[vert.color[3]];
|
||||
|
||||
const float w0 = vert.color2[0] * ( 1.0f / 255.0f );
|
||||
const float w1 = vert.color2[1] * ( 1.0f / 255.0f );
|
||||
const float w2 = vert.color2[2] * ( 1.0f / 255.0f );
|
||||
const float w3 = vert.color2[3] * ( 1.0f / 255.0f );
|
||||
|
||||
idJointMat accum;
|
||||
idJointMat::Mul( accum, j0, w0 );
|
||||
idJointMat::Mad( accum, j1, w1 );
|
||||
idJointMat::Mad( accum, j2, w2 );
|
||||
idJointMat::Mad( accum, j3, w3 );
|
||||
|
||||
return accum * idVec4( vert.xyz.x, vert.xyz.y, vert.xyz.z, 1.0f );
|
||||
}
|
||||
|
||||
#endif /* !__DRAWVERT_INTRINSICS_H__ */
|
||||
87
neo/idlib/geometry/JointTransform.cpp
Normal file
87
neo/idlib/geometry/JointTransform.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
=============
|
||||
idJointMat::ToJointQuat
|
||||
=============
|
||||
*/
|
||||
idJointQuat idJointMat::ToJointQuat() 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];
|
||||
jq.w = 0.0f;
|
||||
|
||||
return jq;
|
||||
}
|
||||
544
neo/idlib/geometry/JointTransform.h
Normal file
544
neo/idlib/geometry/JointTransform.h
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JOINTTRANSFORM_H__
|
||||
#define __JOINTTRANSFORM_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Joint Quaternion
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idJointQuat {
|
||||
public:
|
||||
const float * ToFloatPtr() const { return q.ToFloatPtr(); }
|
||||
float * ToFloatPtr() { return q.ToFloatPtr(); }
|
||||
|
||||
idQuat q;
|
||||
idVec3 t;
|
||||
float w;
|
||||
};
|
||||
|
||||
// offsets for SIMD code
|
||||
#define JOINTQUAT_SIZE (8*4) // sizeof( idJointQuat )
|
||||
#define JOINTQUAT_SIZE_SHIFT 5 // log2( sizeof( idJointQuat ) )
|
||||
#define JOINTQUAT_Q_OFFSET (0*4) // offsetof( idJointQuat, q )
|
||||
#define JOINTQUAT_T_OFFSET (4*4) // offsetof( idJointQuat, t )
|
||||
|
||||
assert_sizeof( idJointQuat, JOINTQUAT_SIZE );
|
||||
assert_sizeof( idJointQuat, (1<<JOINTQUAT_SIZE_SHIFT) );
|
||||
assert_offsetof( idJointQuat, q, JOINTQUAT_Q_OFFSET );
|
||||
assert_offsetof( idJointQuat, t, JOINTQUAT_T_OFFSET );
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Joint Matrix
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================================================
|
||||
idJointMat has the following structure:
|
||||
|
||||
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 );
|
||||
idMat3 GetRotation() const;
|
||||
void SetTranslation( const idVec3 &t );
|
||||
idVec3 GetTranslation() const;
|
||||
|
||||
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
|
||||
|
||||
void Identity();
|
||||
void Invert();
|
||||
|
||||
void FromMat4( const idMat4 & m );
|
||||
|
||||
idMat3 ToMat3() const;
|
||||
idMat4 ToMat4() const;
|
||||
idVec3 ToVec3() const;
|
||||
const float * ToFloatPtr() const { return mat; }
|
||||
float * ToFloatPtr() { return mat; }
|
||||
idJointQuat ToJointQuat() const;
|
||||
|
||||
void Transform( idVec3 &result, const idVec3 &v ) const;
|
||||
void Rotate( idVec3 &result, const idVec3 &v ) const;
|
||||
|
||||
static void Mul( idJointMat &result, const idJointMat &mat, const float s );
|
||||
static void Mad( idJointMat &result, const idJointMat &mat, const float s );
|
||||
static void Multiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 );
|
||||
static void InverseMultiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 );
|
||||
|
||||
float mat[3*4];
|
||||
};
|
||||
|
||||
// offsets for SIMD code
|
||||
#define JOINTMAT_SIZE (4*3*4) // sizeof( idJointMat )
|
||||
assert_sizeof( idJointMat, JOINTMAT_SIZE );
|
||||
|
||||
#define JOINTMAT_TYPESIZE ( 4 * 3 )
|
||||
/*
|
||||
========================
|
||||
idJointMat::SetRotation
|
||||
========================
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::GetRotation
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idMat3 idJointMat::GetRotation() const {
|
||||
idMat3 m;
|
||||
m[0][0] = mat[0 * 4 + 0];
|
||||
m[1][0] = mat[0 * 4 + 1];
|
||||
m[2][0] = mat[0 * 4 + 2];
|
||||
m[0][1] = mat[1 * 4 + 0];
|
||||
m[1][1] = mat[1 * 4 + 1];
|
||||
m[2][1] = mat[1 * 4 + 2];
|
||||
m[0][2] = mat[2 * 4 + 0];
|
||||
m[1][2] = mat[2 * 4 + 1];
|
||||
m[2][2] = mat[2 * 4 + 2];
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::SetTranslation
|
||||
========================
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::GetTranslation
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idVec3 idJointMat::GetTranslation() const {
|
||||
idVec3 t;
|
||||
t[0] = mat[0 * 4 + 3];
|
||||
t[1] = mat[1 * 4 + 3];
|
||||
t[2] = mat[2 * 4 + 3];
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator*
|
||||
========================
|
||||
*/
|
||||
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] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator*=
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idJointMat & idJointMat::operator*=( const idJointMat &a ) {
|
||||
float tmp[3];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 0] = tmp[1];
|
||||
mat[2 * 4 + 0] = tmp[2];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 1] = tmp[1];
|
||||
mat[2 * 4 + 1] = tmp[2];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 2] = tmp[1];
|
||||
mat[2 * 4 + 2] = tmp[2];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 3] = tmp[1];
|
||||
mat[2 * 4 + 3] = tmp[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;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator/=
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idJointMat &idJointMat::operator/=( const idJointMat &a ) {
|
||||
float tmp[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];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 0] = tmp[1];
|
||||
mat[2 * 4 + 0] = tmp[2];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 1] = tmp[1];
|
||||
mat[2 * 4 + 1] = tmp[2];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 2] = tmp[1];
|
||||
mat[2 * 4 + 2] = tmp[2];
|
||||
|
||||
tmp[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];
|
||||
tmp[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];
|
||||
tmp[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] = tmp[0];
|
||||
mat[1 * 4 + 3] = tmp[1];
|
||||
mat[2 * 4 + 3] = tmp[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Compare
|
||||
========================
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Compare
|
||||
========================
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator==
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idJointMat::operator==( const idJointMat &a ) const {
|
||||
return Compare( a );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator!=
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idJointMat::operator!=( const idJointMat &a ) const {
|
||||
return !Compare( a );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Identity
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Identity() {
|
||||
mat[0 * 4 + 0] = 1.0f; mat[0 * 4 + 1] = 0.0f; mat[0 * 4 + 2] = 0.0f; mat[0 * 4 + 3] = 0.0f;
|
||||
mat[1 * 4 + 0] = 0.0f; mat[1 * 4 + 1] = 1.0f; mat[1 * 4 + 2] = 0.0f; mat[1 * 4 + 3] = 0.0f;
|
||||
mat[2 * 4 + 0] = 0.0f; mat[2 * 4 + 1] = 0.0f; mat[2 * 4 + 2] = 1.0f; mat[2 * 4 + 3] = 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Invert
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Invert() {
|
||||
float tmp[3];
|
||||
|
||||
// negate inverse rotated translation part
|
||||
tmp[0] = mat[0 * 4 + 0] * mat[0 * 4 + 3] + mat[1 * 4 + 0] * mat[1 * 4 + 3] + mat[2 * 4 + 0] * mat[2 * 4 + 3];
|
||||
tmp[1] = mat[0 * 4 + 1] * mat[0 * 4 + 3] + mat[1 * 4 + 1] * mat[1 * 4 + 3] + mat[2 * 4 + 1] * mat[2 * 4 + 3];
|
||||
tmp[2] = mat[0 * 4 + 2] * mat[0 * 4 + 3] + mat[1 * 4 + 2] * mat[1 * 4 + 3] + mat[2 * 4 + 2] * mat[2 * 4 + 3];
|
||||
mat[0 * 4 + 3] = -tmp[0];
|
||||
mat[1 * 4 + 3] = -tmp[1];
|
||||
mat[2 * 4 + 3] = -tmp[2];
|
||||
|
||||
// transpose rotation part
|
||||
tmp[0] = mat[0 * 4 + 1];
|
||||
mat[0 * 4 + 1] = mat[1 * 4 + 0];
|
||||
mat[1 * 4 + 0] = tmp[0];
|
||||
tmp[1] = mat[0 * 4 + 2];
|
||||
mat[0 * 4 + 2] = mat[2 * 4 + 0];
|
||||
mat[2 * 4 + 0] = tmp[1];
|
||||
tmp[2] = mat[1 * 4 + 2];
|
||||
mat[1 * 4 + 2] = mat[2 * 4 + 1];
|
||||
mat[2 * 4 + 1] = tmp[2];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::ToMat3
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idMat3 idJointMat::ToMat3() 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] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::ToMat4
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idMat4 idJointMat::ToMat4() const {
|
||||
return idMat4(
|
||||
mat[0 * 4 + 0], mat[0 * 4 + 1], mat[0 * 4 + 2], mat[0 * 4 + 3],
|
||||
mat[1 * 4 + 0], mat[1 * 4 + 1], mat[1 * 4 + 2], mat[1 * 4 + 3],
|
||||
mat[2 * 4 + 0], mat[2 * 4 + 1], mat[2 * 4 + 2], mat[2 * 4 + 3],
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::FromMat4
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::FromMat4( const idMat4 & m ) {
|
||||
mat[0*4+0] = m[0][0], mat[0*4+1] = m[0][1], mat[0*4+2] = m[0][2], mat[0*4+3] = m[0][3];
|
||||
mat[1*4+0] = m[1][0], mat[1*4+1] = m[1][1], mat[1*4+2] = m[1][2], mat[1*4+3] = m[1][3];
|
||||
mat[2*4+0] = m[2][0], mat[2*4+1] = m[2][1], mat[2*4+2] = m[2][2], mat[2*4+3] = m[2][3];
|
||||
assert( m[3][0] == 0.0f );
|
||||
assert( m[3][1] == 0.0f );
|
||||
assert( m[3][2] == 0.0f );
|
||||
assert( m[3][3] == 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::ToVec3
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idVec3 idJointMat::ToVec3() const {
|
||||
return idVec3( mat[0 * 4 + 3], mat[1 * 4 + 3], mat[2 * 4 + 3] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Transform
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Transform( idVec3 &result, const idVec3 &v ) const {
|
||||
result.x = mat[0 * 4 + 0] * v.x + mat[0 * 4 + 1] * v.y + mat[0 * 4 + 2] * v.z + mat[0 * 4 + 3];
|
||||
result.y = mat[1 * 4 + 0] * v.x + mat[1 * 4 + 1] * v.y + mat[1 * 4 + 2] * v.z + mat[1 * 4 + 3];
|
||||
result.z = mat[2 * 4 + 0] * v.x + mat[2 * 4 + 1] * v.y + mat[2 * 4 + 2] * v.z + mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Rotate
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Rotate( idVec3 &result, const idVec3 &v ) const {
|
||||
result.x = mat[0 * 4 + 0] * v.x + mat[0 * 4 + 1] * v.y + mat[0 * 4 + 2] * v.z;
|
||||
result.y = mat[1 * 4 + 0] * v.x + mat[1 * 4 + 1] * v.y + mat[1 * 4 + 2] * v.z;
|
||||
result.z = mat[2 * 4 + 0] * v.x + mat[2 * 4 + 1] * v.y + mat[2 * 4 + 2] * v.z;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Mul
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Mul( idJointMat &result, const idJointMat &mat, const float s ) {
|
||||
result.mat[0 * 4 + 0] = s * mat.mat[0 * 4 + 0];
|
||||
result.mat[0 * 4 + 1] = s * mat.mat[0 * 4 + 1];
|
||||
result.mat[0 * 4 + 2] = s * mat.mat[0 * 4 + 2];
|
||||
result.mat[0 * 4 + 3] = s * mat.mat[0 * 4 + 3];
|
||||
result.mat[1 * 4 + 0] = s * mat.mat[1 * 4 + 0];
|
||||
result.mat[1 * 4 + 1] = s * mat.mat[1 * 4 + 1];
|
||||
result.mat[1 * 4 + 2] = s * mat.mat[1 * 4 + 2];
|
||||
result.mat[1 * 4 + 3] = s * mat.mat[1 * 4 + 3];
|
||||
result.mat[2 * 4 + 0] = s * mat.mat[2 * 4 + 0];
|
||||
result.mat[2 * 4 + 1] = s * mat.mat[2 * 4 + 1];
|
||||
result.mat[2 * 4 + 2] = s * mat.mat[2 * 4 + 2];
|
||||
result.mat[2 * 4 + 3] = s * mat.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Mad
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Mad( idJointMat &result, const idJointMat &mat, const float s ) {
|
||||
result.mat[0 * 4 + 0] += s * mat.mat[0 * 4 + 0];
|
||||
result.mat[0 * 4 + 1] += s * mat.mat[0 * 4 + 1];
|
||||
result.mat[0 * 4 + 2] += s * mat.mat[0 * 4 + 2];
|
||||
result.mat[0 * 4 + 3] += s * mat.mat[0 * 4 + 3];
|
||||
result.mat[1 * 4 + 0] += s * mat.mat[1 * 4 + 0];
|
||||
result.mat[1 * 4 + 1] += s * mat.mat[1 * 4 + 1];
|
||||
result.mat[1 * 4 + 2] += s * mat.mat[1 * 4 + 2];
|
||||
result.mat[1 * 4 + 3] += s * mat.mat[1 * 4 + 3];
|
||||
result.mat[2 * 4 + 0] += s * mat.mat[2 * 4 + 0];
|
||||
result.mat[2 * 4 + 1] += s * mat.mat[2 * 4 + 1];
|
||||
result.mat[2 * 4 + 2] += s * mat.mat[2 * 4 + 2];
|
||||
result.mat[2 * 4 + 3] += s * mat.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Multiply
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Multiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 ) {
|
||||
result.mat[0 * 4 + 0] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 0] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 0];
|
||||
result.mat[0 * 4 + 1] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 1] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 1];
|
||||
result.mat[0 * 4 + 2] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 2] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 2] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
result.mat[0 * 4 + 3] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 3] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 3] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 3] + m1.mat[0 * 4 + 3];
|
||||
|
||||
result.mat[1 * 4 + 0] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 0] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 0];
|
||||
result.mat[1 * 4 + 1] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 1] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 1];
|
||||
result.mat[1 * 4 + 2] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 2] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 2] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
result.mat[1 * 4 + 3] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 3] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 3] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 3] + m1.mat[1 * 4 + 3];
|
||||
|
||||
result.mat[2 * 4 + 0] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 0] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 0];
|
||||
result.mat[2 * 4 + 1] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 1] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 1];
|
||||
result.mat[2 * 4 + 2] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 2] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 2] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
result.mat[2 * 4 + 3] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 3] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 3] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 3] + m1.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::InverseMultiply
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::InverseMultiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 ) {
|
||||
float dst[3];
|
||||
|
||||
result.mat[0 * 4 + 0] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[0 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[0 * 4 + 2];
|
||||
result.mat[0 * 4 + 1] = m1.mat[0 * 4 + 0] * m2.mat[1 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[1 * 4 + 2];
|
||||
result.mat[0 * 4 + 2] = m1.mat[0 * 4 + 0] * m2.mat[2 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[2 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
|
||||
result.mat[1 * 4 + 0] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[0 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[0 * 4 + 2];
|
||||
result.mat[1 * 4 + 1] = m1.mat[1 * 4 + 0] * m2.mat[1 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[1 * 4 + 2];
|
||||
result.mat[1 * 4 + 2] = m1.mat[1 * 4 + 0] * m2.mat[2 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[2 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
|
||||
result.mat[2 * 4 + 0] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[0 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[0 * 4 + 2];
|
||||
result.mat[2 * 4 + 1] = m1.mat[2 * 4 + 0] * m2.mat[1 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[1 * 4 + 2];
|
||||
result.mat[2 * 4 + 2] = m1.mat[2 * 4 + 0] * m2.mat[2 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[2 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
|
||||
dst[0] = - ( m2.mat[0 * 4 + 0] * m2.mat[0 * 4 + 3] + m2.mat[1 * 4 + 0] * m2.mat[1 * 4 + 3] + m2.mat[2 * 4 + 0] * m2.mat[2 * 4 + 3] );
|
||||
dst[1] = - ( m2.mat[0 * 4 + 1] * m2.mat[0 * 4 + 3] + m2.mat[1 * 4 + 1] * m2.mat[1 * 4 + 3] + m2.mat[2 * 4 + 1] * m2.mat[2 * 4 + 3] );
|
||||
dst[2] = - ( m2.mat[0 * 4 + 2] * m2.mat[0 * 4 + 3] + m2.mat[1 * 4 + 2] * m2.mat[1 * 4 + 3] + m2.mat[2 * 4 + 2] * m2.mat[2 * 4 + 3] );
|
||||
|
||||
result.mat[0 * 4 + 3] = m1.mat[0 * 4 + 0] * dst[0] + m1.mat[0 * 4 + 1] * dst[1] + m1.mat[0 * 4 + 2] * dst[2] + m1.mat[0 * 4 + 3];
|
||||
result.mat[1 * 4 + 3] = m1.mat[1 * 4 + 0] * dst[0] + m1.mat[1 * 4 + 1] * dst[1] + m1.mat[1 * 4 + 2] * dst[2] + m1.mat[1 * 4 + 3];
|
||||
result.mat[2 * 4 + 3] = m1.mat[2 * 4 + 0] * dst[0] + m1.mat[2 * 4 + 1] * dst[1] + m1.mat[2 * 4 + 2] * dst[2] + m1.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
#endif /* !__JOINTTRANSFORM_H__ */
|
||||
3238
neo/idlib/geometry/RenderMatrix.cpp
Normal file
3238
neo/idlib/geometry/RenderMatrix.cpp
Normal file
File diff suppressed because it is too large
Load Diff
489
neo/idlib/geometry/RenderMatrix.h
Normal file
489
neo/idlib/geometry/RenderMatrix.h
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef __RENDERMATRIX_H__
|
||||
#define __RENDERMATRIX_H__
|
||||
|
||||
static const int NUM_FRUSTUM_CORNERS = 8;
|
||||
|
||||
struct frustumCorners_t {
|
||||
float x[NUM_FRUSTUM_CORNERS];
|
||||
float y[NUM_FRUSTUM_CORNERS];
|
||||
float z[NUM_FRUSTUM_CORNERS];
|
||||
};
|
||||
|
||||
enum frustumCull_t {
|
||||
FRUSTUM_CULL_FRONT = 1,
|
||||
FRUSTUM_CULL_BACK = 2,
|
||||
FRUSTUM_CULL_CROSS = 3
|
||||
};
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
|
||||
idRenderMatrix
|
||||
|
||||
This is a row-major matrix and transforms are applied with left-multiplication.
|
||||
|
||||
================================================================================================
|
||||
*/
|
||||
class idRenderMatrix {
|
||||
public:
|
||||
idRenderMatrix() {}
|
||||
ID_INLINE idRenderMatrix( float a0, float a1, float a2, float a3,
|
||||
float b0, float b1, float b2, float b3,
|
||||
float c0, float c1, float c2, float c3,
|
||||
float d0, float d1, float d2, float d3 );
|
||||
|
||||
const float * operator[]( int index ) const { assert( index >= 0 && index < 4 ); return &m[index*4]; }
|
||||
float * operator[]( int index ) { assert( index >= 0 && index < 4 ); return &m[index*4]; }
|
||||
|
||||
void Zero() { memset( m, 0, sizeof( m ) ); }
|
||||
ID_INLINE void Identity();
|
||||
|
||||
// Matrix classification (only meant to be used for asserts).
|
||||
ID_INLINE bool IsZero( float epsilon ) const;
|
||||
ID_INLINE bool IsIdentity( float epsilon ) const;
|
||||
ID_INLINE bool IsAffineTransform( float epsilon ) const;
|
||||
ID_INLINE bool IsUniformScale( float epsilon ) const;
|
||||
|
||||
// Transform a point.
|
||||
// NOTE: the idVec3 out variant does not divide by W.
|
||||
ID_INLINE void TransformPoint( const idVec3 & in, idVec3 & out ) const;
|
||||
ID_INLINE void TransformPoint( const idVec3 & in, idVec4 & out ) const;
|
||||
ID_INLINE void TransformPoint( const idVec4 & in, idVec4 & out ) const;
|
||||
|
||||
// These assume the matrix has no non-uniform scaling or shearing.
|
||||
// NOTE: a direction will only stay normalized if the matrix has no skewing or scaling.
|
||||
ID_INLINE void TransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const;
|
||||
ID_INLINE void TransformPlane( const idPlane & in, idPlane & out, bool normalize ) const;
|
||||
|
||||
// These transforms work with non-uniform scaling and shearing by multiplying
|
||||
// with 'transpose(inverse(M))' where this matrix is assumed to be 'inverse(M)'.
|
||||
ID_INLINE void InverseTransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const;
|
||||
ID_INLINE void InverseTransformPlane( const idPlane & in, idPlane & out, bool normalize ) const;
|
||||
|
||||
// Project a point.
|
||||
static ID_INLINE void TransformModelToClip( const idVec3 & src, const idRenderMatrix & modelMatrix, const idRenderMatrix & projectionMatrix, idVec4 & eye, idVec4 & clip );
|
||||
static ID_INLINE void TransformClipToDevice( const idVec4 & clip, idVec3 & ndc );
|
||||
|
||||
// Create a matrix that goes from local space to the space defined by the 'origin' and 'axis'.
|
||||
static void CreateFromOriginAxis( const idVec3 & origin, const idMat3 & axis, idRenderMatrix & out );
|
||||
static void CreateFromOriginAxisScale( const idVec3 & origin, const idMat3 & axis, const idVec3 & scale, idRenderMatrix & out );
|
||||
|
||||
// Create a matrix that goes from a global coordinate to a view coordinate (OpenGL looking down -Z) based on the given view origin/axis.
|
||||
static void CreateViewMatrix( const idVec3 & origin, const idMat3 & axis, idRenderMatrix & out );
|
||||
|
||||
// Create a projection matrix.
|
||||
static void CreateProjectionMatrix( float xMin, float xMax, float yMin, float yMax, float zNear, float zFar, idRenderMatrix & out );
|
||||
static void CreateProjectionMatrixFov( float xFovDegrees, float yFovDegrees, float zNear, float zFar, float xOffset, float yOffset, idRenderMatrix & out );
|
||||
|
||||
// Apply depth hacks to a projection matrix.
|
||||
static ID_INLINE void ApplyDepthHack( idRenderMatrix & src );
|
||||
static ID_INLINE void ApplyModelDepthHack( idRenderMatrix & src, float value );
|
||||
|
||||
// Offset and scale the given matrix such that the result matrix transforms the unit-cube to exactly cover the given bounds (and the inverse).
|
||||
static void OffsetScaleForBounds( const idRenderMatrix & src, const idBounds & bounds, idRenderMatrix & out );
|
||||
static void InverseOffsetScaleForBounds( const idRenderMatrix & src, const idBounds & bounds, idRenderMatrix & out );
|
||||
|
||||
// Basic matrix operations.
|
||||
static void Transpose( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
static void Multiply( const idRenderMatrix & a, const idRenderMatrix & b, idRenderMatrix & out );
|
||||
static bool Inverse( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
static void InverseByTranspose( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
static bool InverseByDoubles( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
|
||||
// Copy or create a matrix that is stored directly into four float4 vectors which is useful for directly setting vertex program uniforms.
|
||||
static void CopyMatrix( const idRenderMatrix & matrix, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3 );
|
||||
static void SetMVP( const idRenderMatrix & mvp, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3, bool & negativeDeterminant );
|
||||
static void SetMVPForBounds( const idRenderMatrix & mvp, const idBounds & bounds, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3, bool & negativeDeterminant );
|
||||
static void SetMVPForInverseProject( const idRenderMatrix & mvp, const idRenderMatrix & inverseProject, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3, bool & negativeDeterminant );
|
||||
|
||||
// Cull to a Model-View-Projection (MVP) matrix.
|
||||
static bool CullPointToMVP( const idRenderMatrix & mvp, const idVec3 & point, bool zeroToOne = false );
|
||||
static bool CullPointToMVPbits( const idRenderMatrix & mvp, const idVec3 & point, byte * outBits, bool zeroToOne = false );
|
||||
static bool CullBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, bool zeroToOne = false );
|
||||
static bool CullBoundsToMVPbits( const idRenderMatrix & mvp, const idBounds & bounds, byte * outBits, bool zeroToOne = false );
|
||||
static bool CullExtrudedBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, bool zeroToOne = false );
|
||||
static bool CullExtrudedBoundsToMVPbits( const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, byte * outBits, bool zeroToOne = false );
|
||||
|
||||
// Calculate the projected bounds.
|
||||
static void ProjectedBounds( idBounds & projected, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
static void ProjectedNearClippedBounds( idBounds & projected, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
static void ProjectedFullyClippedBounds( idBounds & projected, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
|
||||
// Calculate the projected depth bounds.
|
||||
static void DepthBoundsForBounds( float & min, float & max, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
static void DepthBoundsForExtrudedBounds( float & min, float & max, const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, bool windowSpace = true );
|
||||
static void DepthBoundsForShadowBounds( float & min, float & max, const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & localLightOrigin, bool windowSpace = true );
|
||||
|
||||
// Create frustum planes and corners from a matrix.
|
||||
static void GetFrustumPlanes( idPlane planes[6], const idRenderMatrix & frustum, bool zeroToOne, bool normalize );
|
||||
static void GetFrustumCorners( frustumCorners_t & corners, const idRenderMatrix & frustumTransform, const idBounds & frustumBounds );
|
||||
static frustumCull_t CullFrustumCornersToPlane( const frustumCorners_t & corners, const idPlane & plane );
|
||||
|
||||
private:
|
||||
float m[16];
|
||||
};
|
||||
|
||||
extern const idRenderMatrix renderMatrix_identity;
|
||||
extern const idRenderMatrix renderMatrix_flipToOpenGL;
|
||||
extern const idRenderMatrix renderMatrix_windowSpaceToClipSpace;
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::idRenderMatrix
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idRenderMatrix::idRenderMatrix( float a0, float a1, float a2, float a3,
|
||||
float b0, float b1, float b2, float b3,
|
||||
float c0, float c1, float c2, float c3,
|
||||
float d0, float d1, float d2, float d3 ) {
|
||||
m[0*4+0] = a0; m[0*4+1] = a1; m[0*4+2] = a2; m[0*4+3] = a3;
|
||||
m[1*4+0] = b0; m[1*4+1] = b1; m[1*4+2] = b2; m[1*4+3] = b3;
|
||||
m[2*4+0] = c0; m[2*4+1] = c1; m[2*4+2] = c2; m[2*4+3] = c3;
|
||||
m[3*4+0] = d0; m[3*4+1] = d1; m[3*4+2] = d2; m[3*4+3] = d3;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::Identity
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::Identity() {
|
||||
m[0*4+0] = 1.0f;
|
||||
m[0*4+1] = 0.0f;
|
||||
m[0*4+2] = 0.0f;
|
||||
m[0*4+3] = 0.0f;
|
||||
|
||||
m[1*4+0] = 0.0f;
|
||||
m[1*4+1] = 1.0f;
|
||||
m[1*4+2] = 0.0f;
|
||||
m[1*4+3] = 0.0f;
|
||||
|
||||
m[2*4+0] = 0.0f;
|
||||
m[2*4+1] = 0.0f;
|
||||
m[2*4+2] = 1.0f;
|
||||
m[2*4+3] = 0.0f;
|
||||
|
||||
m[3*4+0] = 0.0f;
|
||||
m[3*4+1] = 0.0f;
|
||||
m[3*4+2] = 0.0f;
|
||||
m[3*4+3] = 1.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsZero
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsZero( float epsilon ) const {
|
||||
for ( int i = 0; i < 16; i++ ) {
|
||||
if ( idMath::Fabs( m[i] ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsIdentity
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsIdentity( float epsilon ) const {
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
for ( int j = 0; j < 4; j++ ) {
|
||||
if ( i == j ) {
|
||||
if ( idMath::Fabs( m[i * 4 + j] - 1.0f ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( idMath::Fabs( m[i * 4 + j] ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsAffineTransform
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsAffineTransform( float epsilon ) const {
|
||||
if ( idMath::Fabs( m[3 * 4 + 0] ) > epsilon ||
|
||||
idMath::Fabs( m[3 * 4 + 1] ) > epsilon ||
|
||||
idMath::Fabs( m[3 * 4 + 2] ) > epsilon ||
|
||||
idMath::Fabs( m[3 * 4 + 3] - 1.0f ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsUniformScale
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsUniformScale( float epsilon ) const {
|
||||
float d0 = idMath::InvSqrt( m[0*4+0] * m[0*4+0] + m[1*4+0] * m[1*4+0] + m[2*4+0] * m[2*4+0] );
|
||||
float d1 = idMath::InvSqrt( m[0*4+1] * m[0*4+1] + m[1*4+1] * m[1*4+1] + m[2*4+1] * m[2*4+1] );
|
||||
float d2 = idMath::InvSqrt( m[0*4+2] * m[0*4+2] + m[1*4+2] * m[1*4+2] + m[2*4+2] * m[2*4+2] );
|
||||
if ( idMath::Fabs( d0 - d1 ) > epsilon ) { return false; }
|
||||
if ( idMath::Fabs( d1 - d2 ) > epsilon ) { return false; }
|
||||
if ( idMath::Fabs( d0 - d2 ) > epsilon ) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPoint
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPoint( const idVec3 & in, idVec3 & out ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
out[0] = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2] + matrix[0][3];
|
||||
out[1] = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2] + matrix[1][3];
|
||||
out[2] = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2] + matrix[2][3];
|
||||
assert( idMath::Fabs( in[0] * matrix[3][0] + in[1] * matrix[3][1] + in[2] * matrix[3][2] + matrix[3][3] - 1.0f ) < 0.01f );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPoint
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPoint( const idVec3 & in, idVec4 & out ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
out[0] = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2] + matrix[0][3];
|
||||
out[1] = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2] + matrix[1][3];
|
||||
out[2] = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2] + matrix[2][3];
|
||||
out[3] = in[0] * matrix[3][0] + in[1] * matrix[3][1] + in[2] * matrix[3][2] + matrix[3][3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPoint
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPoint( const idVec4 & in, idVec4 & out ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
out[0] = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2] + in[3] * matrix[0][3];
|
||||
out[1] = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2] + in[3] * matrix[1][3];
|
||||
out[2] = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2] + in[3] * matrix[2][3];
|
||||
out[3] = in[0] * matrix[3][0] + in[1] * matrix[3][1] + in[2] * matrix[3][2] + in[3] * matrix[3][3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformDir
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const {
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2];
|
||||
float p1 = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2];
|
||||
float p2 = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPlane
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPlane( const idPlane & in, idPlane & out, bool normalize ) const {
|
||||
assert( IsUniformScale( 0.01f ) );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2];
|
||||
float p1 = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2];
|
||||
float p2 = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2];
|
||||
float d0 = matrix[0][3] - p0 * in[3];
|
||||
float d1 = matrix[1][3] - p1 * in[3];
|
||||
float d2 = matrix[2][3] - p2 * in[3];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
out[3] = - p0 * d0 - p1 * d1 - p2 * d2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::InverseTransformDir
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::InverseTransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[1][0] + in[2] * matrix[2][0];
|
||||
float p1 = in[0] * matrix[0][1] + in[1] * matrix[1][1] + in[2] * matrix[2][1];
|
||||
float p2 = in[0] * matrix[0][2] + in[1] * matrix[1][2] + in[2] * matrix[2][2];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::InverseTransformPlane
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::InverseTransformPlane( const idPlane & in, idPlane & out, bool normalize ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[1][0] + in[2] * matrix[2][0] + in[3] * matrix[3][0];
|
||||
float p1 = in[0] * matrix[0][1] + in[1] * matrix[1][1] + in[2] * matrix[2][1] + in[3] * matrix[3][1];
|
||||
float p2 = in[0] * matrix[0][2] + in[1] * matrix[1][2] + in[2] * matrix[2][2] + in[3] * matrix[3][2];
|
||||
float p3 = in[0] * matrix[0][3] + in[1] * matrix[1][3] + in[2] * matrix[2][3] + in[3] * matrix[3][3];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
p3 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
out[3] = p3;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformModelToClip
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformModelToClip( const idVec3 & src, const idRenderMatrix & modelMatrix, const idRenderMatrix & projectionMatrix, idVec4 & eye, idVec4 & clip ) {
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
eye[i] = modelMatrix[i][0] * src[0] +
|
||||
modelMatrix[i][1] * src[1] +
|
||||
modelMatrix[i][2] * src[2] +
|
||||
modelMatrix[i][3];
|
||||
}
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
clip[i] = projectionMatrix[i][0] * eye[0] +
|
||||
projectionMatrix[i][1] * eye[1] +
|
||||
projectionMatrix[i][2] * eye[2] +
|
||||
projectionMatrix[i][3] * eye[3];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformClipToDevice
|
||||
|
||||
Clip to normalized device coordinates.
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformClipToDevice( const idVec4 & clip, idVec3 & ndc ) {
|
||||
assert( idMath::Fabs( clip[3] ) > idMath::FLT_SMALLEST_NON_DENORMAL );
|
||||
float r = 1.0f / clip[3];
|
||||
ndc[0] = clip[0] * r;
|
||||
ndc[1] = clip[1] * r;
|
||||
ndc[2] = clip[2] * r;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::ApplyDepthHack
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::ApplyDepthHack( idRenderMatrix & src ) {
|
||||
// scale projected z by 25%
|
||||
src.m[2*4+0] *= 0.25f;
|
||||
src.m[2*4+1] *= 0.25f;
|
||||
src.m[2*4+2] *= 0.25f;
|
||||
src.m[2*4+3] *= 0.25f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::ApplyModelDepthHack
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::ApplyModelDepthHack( idRenderMatrix & src, float value ) {
|
||||
// offset projected z
|
||||
src.m[2*4+3] -= value;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::CullPointToMVP
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::CullPointToMVP( const idRenderMatrix & mvp, const idVec3 & point, bool zeroToOne ) {
|
||||
byte bits;
|
||||
return CullPointToMVPbits( mvp, point, &bits, zeroToOne );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::CullBoundsToMVP
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::CullBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, bool zeroToOne ) {
|
||||
byte bits;
|
||||
return CullBoundsToMVPbits( mvp, bounds, &bits, zeroToOne );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::CullExtrudedBoundsToMVP
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::CullExtrudedBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, bool zeroToOne ) {
|
||||
byte bits;
|
||||
return CullExtrudedBoundsToMVPbits( mvp, bounds, extrudeDirection, clipPlane, &bits, zeroToOne );
|
||||
}
|
||||
|
||||
#endif // !__RENDERMATRIX_H__
|
||||
929
neo/idlib/geometry/Surface.cpp
Normal file
929
neo/idlib/geometry/Surface.cpp
Normal file
@@ -0,0 +1,929 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
=================
|
||||
UpdateVertexIndex
|
||||
=================
|
||||
*/
|
||||
ID_INLINE int UpdateVertexIndex( int vertexIndexNum[2], int *vertexRemap, int *vertexCopyIndex, int vertNum ) {
|
||||
int s = INT32_SIGNBITSET( 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 ( IEEE_FLT_SIGNBITSET( f ) ) {
|
||||
*back = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_BACK;
|
||||
} else {
|
||||
*front = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
}
|
||||
// if nothing at the front of the clipping plane
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
*back = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_BACK;
|
||||
}
|
||||
// if nothing at the back of the clipping plane
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
*front = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
|
||||
// allocate front and back surface
|
||||
*front = surface[0] = new (TAG_IDLIB_SURFACE) idSurface();
|
||||
*back = surface[1] = new (TAG_IDLIB_SURFACE) 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( ( INT32_SIGNBITSET( edgeSplitVertex[e0] ) | ( INT32_SIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INT32_SIGNBITSET( 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 = IEEE_FLT_SIGNBITSET( 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] );
|
||||
surface[1]->indexes.SetNum( indexNum[1] );
|
||||
|
||||
// copy vertexes
|
||||
surface[0]->verts.SetNum( vertexIndexNum[0][1] );
|
||||
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] );
|
||||
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, TAG_IDLIB_LIST_SURFACE> newVerts;
|
||||
idList<int, TAG_IDLIB_LIST_SURFACE> 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 ( IEEE_FLT_SIGNBITSET( 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( ( INT32_SIGNBITSET( edgeSplitVertex[e0] ) | ( INT32_SIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INT32_SIGNBITSET( 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 ( IEEE_FLT_SIGNBITSET( 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 );
|
||||
|
||||
// copy vertexes
|
||||
newVerts.SetNum( vertexIndexNum[1] );
|
||||
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() 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[INT32_SIGNBITNOTSET(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() 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 ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
if ( d > max ) {
|
||||
max = d;
|
||||
if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
|
||||
return min;
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITSET( 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 ] = IEEE_FLT_SIGNBITSET( 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)] ^ INT32_SIGNBITSET( i0 );
|
||||
s1 = sidedness[abs(i1)] ^ INT32_SIGNBITSET( i1 );
|
||||
s2 = sidedness[abs(i2)] ^ INT32_SIGNBITSET( 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() {
|
||||
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() );
|
||||
|
||||
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 = INT32_SIGNBITSET(i1 - i0);
|
||||
e[0].verts[0] = index[s];
|
||||
e[0].verts[1] = index[s^1];
|
||||
s = INT32_SIGNBITSET(i2 - i1) + 1;
|
||||
e[1].verts[0] = index[s];
|
||||
e[1].verts[1] = index[s^3];
|
||||
s = INT32_SIGNBITSET(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;
|
||||
}
|
||||
219
neo/idlib/geometry/Surface.h
Normal file
219
neo/idlib/geometry/Surface.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __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();
|
||||
explicit idSurface( const idSurface &surf );
|
||||
explicit idSurface( const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes );
|
||||
~idSurface();
|
||||
|
||||
const idDrawVert & operator[]( const int index ) const;
|
||||
idDrawVert & operator[]( const int index );
|
||||
idSurface & operator+=( const idSurface &surf );
|
||||
|
||||
int GetNumIndexes() const { return indexes.Num(); }
|
||||
const int * GetIndexes() const { return indexes.Ptr(); }
|
||||
int GetNumVertices() const { return verts.Num(); }
|
||||
const idDrawVert * GetVertices() const { return verts.Ptr(); }
|
||||
const int * GetEdgeIndexes() const { return edgeIndexes.Ptr(); }
|
||||
const surfaceEdge_t * GetEdges() const { return edges.Ptr(); }
|
||||
|
||||
void Clear();
|
||||
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() const;
|
||||
// returns true if the surface is closed
|
||||
bool IsClosed() 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, TAG_IDLIB_LIST_SURFACE> verts; // vertices
|
||||
idList<int, TAG_IDLIB_LIST_SURFACE> indexes; // 3 references to vertices for each triangle
|
||||
idList<surfaceEdge_t, TAG_IDLIB_LIST_SURFACE> edges; // edges
|
||||
idList<int, TAG_IDLIB_LIST_SURFACE> edgeIndexes; // 3 references to edges for each triangle, may be negative for reversed edge
|
||||
|
||||
protected:
|
||||
void GenerateEdgeIndexes();
|
||||
int FindEdge( int v1, int v2 ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface::idSurface
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface::idSurface() {
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
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() {
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
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() {
|
||||
verts.Clear();
|
||||
indexes.Clear();
|
||||
edges.Clear();
|
||||
edgeIndexes.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
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].SetNormal( verts[i].GetNormal() * rotation );
|
||||
verts[i].SetTangent( verts[i].GetTangent() * rotation );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_H__ */
|
||||
698
neo/idlib/geometry/Surface_Patch.cpp
Normal file
698
neo/idlib/geometry/Surface_Patch.cpp
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
=================
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::PutOnCurve
|
||||
|
||||
Expects an expanded patch.
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::PutOnCurve() {
|
||||
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() {
|
||||
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() {
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idSurface_Patch::Expand
|
||||
================
|
||||
*/
|
||||
void idSurface_Patch::Expand() {
|
||||
int i, j;
|
||||
|
||||
if ( expanded ) {
|
||||
idLib::common->FatalError("idSurface_Patch::Expand: patch alread expanded");
|
||||
}
|
||||
expanded = true;
|
||||
verts.SetNum( maxWidth * maxHeight );
|
||||
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.SetNormal( ( a.GetNormal() + b.GetNormal() ) * 0.5f );
|
||||
out.SetTexCoord( ( a.GetTexCoord() + b.GetTexCoord() ) * 0.5f );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
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() {
|
||||
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].SetNormal( 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;
|
||||
}
|
||||
sum.Normalize();
|
||||
verts[j * width + i].SetNormal( sum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::GenerateIndexes
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::GenerateIndexes() {
|
||||
int i, j, v1, v2, v3, v4, index;
|
||||
|
||||
indexes.SetNum( (width-1) * (height-1) * 2 * 3 );
|
||||
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].GetNormal()[axis-3];
|
||||
b = ctrl[1][vPoint].GetNormal()[axis-3];
|
||||
c = ctrl[2][vPoint].GetNormal()[axis-3];
|
||||
} else {
|
||||
a = ctrl[0][vPoint].GetTexCoord()[axis-6];
|
||||
b = ctrl[1][vPoint].GetTexCoord()[axis-6];
|
||||
c = ctrl[2][vPoint].GetTexCoord()[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 ) {
|
||||
idVec3 tempNormal = out->GetNormal();
|
||||
tempNormal[axis-3] = qA * v * v + qB * v + qC;
|
||||
out->SetNormal( tempNormal );
|
||||
//out->normal[axis-3] = qA * v * v + qB * v + qC;
|
||||
} else {
|
||||
idVec2 tempST = out->GetTexCoord();
|
||||
tempST[axis-6] = qA * v * v + qB * v + qC;
|
||||
out->SetTexCoord( tempST );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
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 (TAG_IDLIB_SURFACE) 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 ) {
|
||||
idVec3 tempNormal;
|
||||
for ( i = 0; i < width * height; i++ ) {
|
||||
tempNormal= verts[i].GetNormal();
|
||||
tempNormal.Normalize();
|
||||
verts[i].SetNormal( tempNormal );
|
||||
}
|
||||
}
|
||||
|
||||
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 ) {
|
||||
idVec3 tempNormal;
|
||||
for ( i = 0; i < width * height; i++ ) {
|
||||
tempNormal = verts[i].GetNormal();
|
||||
tempNormal.Normalize();
|
||||
verts[i].SetNormal( tempNormal );
|
||||
}
|
||||
}
|
||||
|
||||
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 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SURFACE_PATCH_H__
|
||||
#define __SURFACE_PATCH_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Bezier patch surface.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idSurface_Patch : public idSurface {
|
||||
|
||||
public:
|
||||
idSurface_Patch();
|
||||
idSurface_Patch( int maxPatchWidth, int maxPatchHeight );
|
||||
idSurface_Patch( const idSurface_Patch &patch );
|
||||
~idSurface_Patch();
|
||||
|
||||
void SetSize( int patchWidth, int patchHeight );
|
||||
int GetWidth() const;
|
||||
int GetHeight() 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();
|
||||
// remove columns and rows with all points on one line
|
||||
void RemoveLinearColumnsRows();
|
||||
// resize verts buffer
|
||||
void ResizeExpanded( int height, int width );
|
||||
// space points out over maxWidth * maxHeight buffer
|
||||
void Expand();
|
||||
// move all points to the start of the verts buffer
|
||||
void Collapse();
|
||||
// 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();
|
||||
// generate triangle indexes
|
||||
void GenerateIndexes();
|
||||
// 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() {
|
||||
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() const {
|
||||
return width;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::GetHeight
|
||||
=================
|
||||
*/
|
||||
ID_INLINE int idSurface_Patch::GetHeight() const {
|
||||
return height;
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_PATCH_H__ */
|
||||
334
neo/idlib/geometry/Surface_Polytope.cpp
Normal file
334
neo/idlib/geometry/Surface_Polytope.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
#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(); k++ ) {
|
||||
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 (TAG_IDLIB_SURFACE) idSurface_Polytope;
|
||||
*back = polytopeSurfaces[1] = new (TAG_IDLIB_SURFACE) idSurface_Polytope;
|
||||
|
||||
for ( s = 0; s < 2; s++ ) {
|
||||
if ( surface[s] ) {
|
||||
polytopeSurfaces[s] = new idSurface_Polytope( *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[INT32_SIGNBITSET(edgeNum)];
|
||||
v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(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[INT32_SIGNBITSET(edgeNum)] ) {
|
||||
v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];
|
||||
SwapValues( 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[INT32_SIGNBITNOTSET(edgeNum)];
|
||||
v2 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)];
|
||||
surf->indexes.Append( v0 );
|
||||
surf->indexes.Append( v1 );
|
||||
surf->indexes.Append( v2 );
|
||||
}
|
||||
|
||||
surf->GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
return side;
|
||||
}
|
||||
71
neo/idlib/geometry/Surface_Polytope.h
Normal file
71
neo/idlib/geometry/Surface_Polytope.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __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();
|
||||
explicit idSurface_Polytope( const idSurface &surface ) : idSurface( surface ) {}
|
||||
|
||||
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() {
|
||||
}
|
||||
|
||||
#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 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
====================
|
||||
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 (TAG_IDLIB_SURFACE) 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 );
|
||||
|
||||
// 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].SetTexCoordS( splinePos.w );
|
||||
verts[baseOffset+i].SetTangent( 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();
|
||||
idVec3 tempNormal;
|
||||
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->SetTexCoord( verts[baseOffset+j].GetTexCoord().x, splinePos.w );
|
||||
v->SetTangent( verts[baseOffset+j].GetTangent() * splineMat );
|
||||
v->SetBiTangent( splineD1.ToVec3() );
|
||||
tempNormal = v->GetBiTangent().Cross( v->GetTangent() );
|
||||
tempNormal.Normalize();
|
||||
v->SetNormal( tempNormal );
|
||||
v->color[0] = v->color[1] = v->color[2] = v->color[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
indexes.SetNum( splineDiv * sweptSplineDiv * 2 * 3 );
|
||||
|
||||
// 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 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SURFACE_SWEPTSPLINE_H__
|
||||
#define __SURFACE_SWEPTSPLINE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Swept Spline surface.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idSurface_SweptSpline : public idSurface {
|
||||
public:
|
||||
idSurface_SweptSpline();
|
||||
~idSurface_SweptSpline();
|
||||
|
||||
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();
|
||||
|
||||
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() {
|
||||
spline = NULL;
|
||||
sweptSpline = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::~idSurface_SweptSpline
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface_SweptSpline::~idSurface_SweptSpline() {
|
||||
delete spline;
|
||||
delete sweptSpline;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::Clear
|
||||
====================
|
||||
*/
|
||||
ID_INLINE void idSurface_SweptSpline::Clear() {
|
||||
idSurface::Clear();
|
||||
delete spline;
|
||||
spline = NULL;
|
||||
delete sweptSpline;
|
||||
sweptSpline = NULL;
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_SWEPTSPLINE_H__ */
|
||||
1492
neo/idlib/geometry/TraceModel.cpp
Normal file
1492
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 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __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();
|
||||
// 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();
|
||||
// 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 InitOctahedron();
|
||||
void InitDodecahedron();
|
||||
void InitBone();
|
||||
|
||||
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() {
|
||||
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__ */
|
||||
|
||||
1600
neo/idlib/geometry/Winding.cpp
Normal file
1600
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 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __WINDING_H__
|
||||
#define __WINDING_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
A winding is an arbitrary convex polygon defined by an array of points.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idWinding {
|
||||
|
||||
public:
|
||||
idWinding();
|
||||
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();
|
||||
|
||||
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() const;
|
||||
void SetNumPoints( int n );
|
||||
virtual void Clear();
|
||||
|
||||
// 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() const;
|
||||
idWinding * Reverse() const;
|
||||
void ReverseSelf();
|
||||
void RemoveEqualPoints( const float epsilon = ON_EPSILON );
|
||||
void RemoveColinearPoints( const idVec3 &normal, const float epsilon = ON_EPSILON );
|
||||
void RemovePoint( int point );
|
||||
void InsertPoint( const idVec5 &point, int spot );
|
||||
bool InsertPointIfOnEdge( const idVec5 &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() const;
|
||||
idVec3 GetCenter() 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() const;
|
||||
bool IsHuge() const; // base winding for a plane is typically huge
|
||||
void Print() 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() {
|
||||
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() {
|
||||
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() const {
|
||||
return numPoints;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::SetNumPoints( int n ) {
|
||||
if ( !EnsureAlloced( n, true ) ) {
|
||||
return;
|
||||
}
|
||||
numPoints = n;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::Clear() {
|
||||
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();
|
||||
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();
|
||||
|
||||
idFixedWinding &operator=( const idWinding &winding );
|
||||
|
||||
virtual void Clear();
|
||||
|
||||
// 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() {
|
||||
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() {
|
||||
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() {
|
||||
numPoints = 0;
|
||||
}
|
||||
#endif /* !__WINDING_H__ */
|
||||
753
neo/idlib/geometry/Winding2D.cpp
Normal file
753
neo/idlib/geometry/Winding2D.cpp
Normal file
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
#include "Winding2D.h"
|
||||
|
||||
/*
|
||||
============
|
||||
GetAxialBevel
|
||||
============
|
||||
*/
|
||||
bool GetAxialBevel( const idVec3 &plane1, const idVec3 &plane2, const idVec2 &point, idVec3 &bevel ) {
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.x ) ^ IEEE_FLT_SIGNBITSET( plane2.x ) ) {
|
||||
if ( idMath::Fabs( plane1.x ) > 0.1f && idMath::Fabs( plane2.x ) > 0.1f ) {
|
||||
bevel.x = 0.0f;
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.y ) ) {
|
||||
bevel.y = -1.0f;
|
||||
}
|
||||
else {
|
||||
bevel.y = 1.0f;
|
||||
}
|
||||
bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.y ) ^ IEEE_FLT_SIGNBITSET( plane2.y ) ) {
|
||||
if ( idMath::Fabs( plane1.y ) > 0.1f && idMath::Fabs( plane2.y ) > 0.1f ) {
|
||||
bevel.y = 0.0f;
|
||||
if ( IEEE_FLT_SIGNBITSET( 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;
|
||||
}
|
||||
assert( numPlanes < MAX_POINTS_ON_WINDING_2D && numPlanes > 0 );
|
||||
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[ IEEE_FLT_SIGNBITSET( planes[i].x ) ].x;
|
||||
v.y = bounds[ IEEE_FLT_SIGNBITSET( 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 (TAG_IDLIB_WINDING) idWinding2D;
|
||||
*back = b = new (TAG_IDLIB_WINDING) 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() const {
|
||||
idWinding2D *w;
|
||||
|
||||
w = new (TAG_IDLIB_WINDING) idWinding2D;
|
||||
w->numPoints = numPoints;
|
||||
memcpy( w->p, p, numPoints * sizeof( p[0] ) );
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::Reverse
|
||||
=============
|
||||
*/
|
||||
idWinding2D *idWinding2D::Reverse() const {
|
||||
idWinding2D *w;
|
||||
int i;
|
||||
|
||||
w = new (TAG_IDLIB_WINDING) idWinding2D;
|
||||
w->numPoints = numPoints;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
w->p[ numPoints - i - 1 ] = p[i];
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::GetArea
|
||||
============
|
||||
*/
|
||||
float idWinding2D::GetArea() 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() 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() 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() 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() 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 ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
if ( d > max ) {
|
||||
max = d;
|
||||
if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
|
||||
return min;
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITSET( 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 ( IEEE_FLT_SIGNBITNOTSET( d1 ) & IEEE_FLT_SIGNBITNOTSET( 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 ( IEEE_FLT_SIGNBITNOTSET( d1 ) & IEEE_FLT_SIGNBITNOTSET( 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 ) ) {
|
||||
SwapValues( scale1, scale2 );
|
||||
SwapValues( 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 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __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();
|
||||
|
||||
idWinding2D & operator=( const idWinding2D &winding );
|
||||
const idVec2 & operator[]( const int index ) const;
|
||||
idVec2 & operator[]( const int index );
|
||||
|
||||
void Clear();
|
||||
void AddPoint( const idVec2 &point );
|
||||
int GetNumPoints() 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() const;
|
||||
idWinding2D * Reverse() const;
|
||||
|
||||
float GetArea() const;
|
||||
idVec2 GetCenter() const;
|
||||
float GetRadius( const idVec2 ¢er ) const;
|
||||
void GetBounds( idVec2 bounds[2] ) const;
|
||||
|
||||
bool IsTiny() const;
|
||||
bool IsHuge() const; // base winding for a plane is typically huge
|
||||
void Print() 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() {
|
||||
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() {
|
||||
numPoints = 0;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding2D::AddPoint( const idVec2 &point ) {
|
||||
p[numPoints++] = point;
|
||||
}
|
||||
|
||||
ID_INLINE int idWinding2D::GetNumPoints() 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