Initial commit

This commit is contained in:
Brian Harris
2012-11-26 12:58:24 -06:00
parent a5214f79ef
commit 5016f605b8
1115 changed files with 587266 additions and 0 deletions

233
neo/idlib/Base64.cpp Normal file
View File

@@ -0,0 +1,233 @@
#include "precompiled.h"
#pragma hdrstop
/*
Copyright (c) 1996 Lars Wirzenius. All rights reserved.
June 14 2003: TTimo <ttimo@idsoftware.com>
modified + endian bug fixes
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=197039
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
============
idBase64::Encode
============
*/
static const char sixtet_to_base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
void idBase64::Encode( const byte *from, int size ) {
int i, j;
unsigned long w;
byte *to;
EnsureAlloced( 4*(size+3)/3 + 2 ); // ratio and padding + trailing \0
to = data;
w = 0;
i = 0;
while (size > 0) {
w |= *from << i*8;
++from;
--size;
++i;
if (size == 0 || i == 3) {
byte out[4];
SixtetsForInt( out, w );
for (j = 0; j*6 < i*8; ++j) {
*to++ = sixtet_to_base64[ out[j] ];
}
if (size == 0) {
for (j = i; j < 3; ++j) {
*to++ = '=';
}
}
w = 0;
i = 0;
}
}
*to++ = '\0';
len = to - data;
}
/*
============
idBase64::DecodeLength
returns the minimum size in bytes of the target buffer for decoding
4 base64 digits <-> 3 bytes
============
*/
int idBase64::DecodeLength( void ) const {
return 3*len/4;
}
/*
============
idBase64::Decode
============
*/
int idBase64::Decode( byte *to ) const {
unsigned long w;
int i, j;
size_t n;
static char base64_to_sixtet[256];
static int tab_init = 0;
byte *from = data;
if (!tab_init) {
memset( base64_to_sixtet, 0, 256 );
for (i = 0; (j = sixtet_to_base64[i]) != '\0'; ++i) {
base64_to_sixtet[j] = i;
}
tab_init = 1;
}
w = 0;
i = 0;
n = 0;
byte in[4] = {0,0,0,0};
while (*from != '\0' && *from != '=' ) {
if (*from == ' ' || *from == '\n') {
++from;
continue;
}
in[i] = base64_to_sixtet[* (unsigned char *) from];
++i;
++from;
if (*from == '\0' || *from == '=' || i == 4) {
w = IntForSixtets( in );
for (j = 0; j*8 < i*6; ++j) {
*to++ = w & 0xff;
++n;
w >>= 8;
}
i = 0;
w = 0;
}
}
return n;
}
/*
============
idBase64::Encode
============
*/
void idBase64::Encode( const idStr &src ) {
Encode( (const byte *)src.c_str(), src.Length() );
}
/*
============
idBase64::Decode
============
*/
void idBase64::Decode( idStr &dest ) const {
byte *buf = new (TAG_IDLIB) byte[ DecodeLength()+1 ]; // +1 for trailing \0
int out = Decode( buf );
buf[out] = '\0';
dest = (const char *)buf;
delete[] buf;
}
/*
============
idBase64::Decode
============
*/
void idBase64::Decode( idFile *dest ) const {
byte *buf = new (TAG_IDLIB) byte[ DecodeLength()+1 ]; // +1 for trailing \0
int out = Decode( buf );
dest->Write( buf, out );
delete[] buf;
}
#if 0
void idBase64_TestBase64() {
idStr src;
idBase64 dest;
src = "Encode me in base64";
dest.Encode( src );
idLib::common->Printf( "%s -> %s\n", src.c_str(), dest.c_str() );
dest.Decode( src );
idLib::common->Printf( "%s -> %s\n", dest.c_str(), src.c_str() );
idDict src_dict;
src_dict.SetFloat("float", 0.5f);
src_dict.SetBool("bool", true);
src_dict.Set("value", "foo");
idFile_Memory src_fmem("serialize_dict");
src_dict.WriteToFileHandle( &src_fmem );
dest.Encode( (const byte *)src_fmem.GetDataPtr(), src_fmem.Length() );
idLib::common->Printf( "idDict encoded to %s\n", dest.c_str());
// now decode to another stream and build back
idFile_Memory dest_fmem( "build_back" );
dest.Decode( &dest_fmem );
dest_fmem.MakeReadOnly();
idDict dest_dict;
dest_dict.ReadFromFileHandle( &dest_fmem );
idLib::common->Printf( "idDict reconstructed after base64 decode\n");
dest_dict.Print();
// test idDict read from file - from python generated files, see idDict.py
idFile *file = idLib::fileSystem->OpenFileRead("idDict.test");
if (file) {
idDict test_dict;
test_dict.ReadFromFileHandle( file );
//
idLib::common->Printf( "read idDict.test:\n");
test_dict.Print();
idLib::fileSystem->CloseFile(file);
file = NULL;
} else {
idLib::common->Printf( "idDict.test not found\n" );
}
idBase64 base64_src;
void *buffer;
if ( idLib::fileSystem->ReadFile( "idDict.base64.test", &buffer ) != -1 ) {
idFile_Memory mem_src( "dict" );
idLib::common->Printf( "read: %d %s\n", idStr::Length( (char*)buffer ), buffer );
base64_src = (char *)buffer;
base64_src.Decode( &mem_src );
mem_src.MakeReadOnly();
idDict test_dict;
test_dict.ReadFromFileHandle( &mem_src );
idLib::common->Printf( "read idDict.base64.test:\n");
test_dict.Print();
idLib::fileSystem->FreeFile( buffer );
} else {
idLib::common->Printf( "idDict.base64.test not found\n" );
}
}
#endif

111
neo/idlib/Base64.h Normal file
View File

@@ -0,0 +1,111 @@
/*
===========================================================================
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 __BASE64_H__
#define __BASE64_H__
/*
===============================================================================
base64
===============================================================================
*/
class idBase64 {
public:
idBase64();
idBase64( const idStr &s );
~idBase64();
void Encode( const byte *from, int size );
void Encode( const idStr &src );
int DecodeLength() const; // minimum size in bytes of destination buffer for decoding
int Decode( byte *to ) const; // does not append a \0 - needs a DecodeLength() bytes buffer
void Decode( idStr &dest ) const; // decodes the binary content to an idStr (a bit dodgy, \0 and other non-ascii are possible in the decoded content)
void Decode( idFile *dest ) const;
const char *c_str() const;
void operator=( const idStr &s );
private:
byte * data;
int len;
int alloced;
void Init();
void Release();
void EnsureAlloced( int size );
};
ID_INLINE idBase64::idBase64() {
Init();
}
ID_INLINE idBase64::idBase64( const idStr &s ) {
Init();
*this = s;
}
ID_INLINE idBase64::~idBase64() {
Release();
}
ID_INLINE const char *idBase64::c_str() const {
return (const char *)data;
}
ID_INLINE void idBase64::Init() {
len = 0;
alloced = 0;
data = NULL;
}
ID_INLINE void idBase64::Release() {
if ( data ) {
delete[] data;
}
Init();
}
ID_INLINE void idBase64::EnsureAlloced( int size ) {
if ( size > alloced ) {
Release();
}
data = new (TAG_IDLIB) byte[size];
alloced = size;
}
ID_INLINE void idBase64::operator=( const idStr &s ) {
EnsureAlloced( s.Length()+1 ); // trailing \0 - beware, this does a Release
strcpy( (char *)data, s.c_str() );
len = s.Length();
}
#endif /* !__BASE64_H__ */

511
neo/idlib/BitMsg.cpp Normal file
View File

@@ -0,0 +1,511 @@
/*
===========================================================================
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"
/*
================================================================================================
idBitMsg
================================================================================================
*/
/*
========================
idBitMsg::CheckOverflow
========================
*/
bool idBitMsg::CheckOverflow( int numBits ) {
if ( numBits > GetRemainingWriteBits() ) {
if ( !allowOverflow ) {
idLib::FatalError( "idBitMsg: overflow without allowOverflow set; maxsize=%i size=%i numBits=%i numRemainingWriteBits=%i",
GetMaxSize(), GetSize(), numBits, GetRemainingWriteBits() );
}
if ( numBits > ( maxSize << 3 ) ) {
idLib::FatalError( "idBitMsg: %i bits is > full message size", numBits );
}
idLib::Printf( "idBitMsg: overflow\n" );
BeginWriting();
overflowed = true;
return true;
}
return false;
}
/*
========================
idBitMsg::GetByteSpace
========================
*/
byte *idBitMsg::GetByteSpace( int length ) {
byte *ptr;
if ( !writeData ) {
idLib::FatalError( "idBitMsg::GetByteSpace: cannot write to message" );
}
// round up to the next byte
WriteByteAlign();
// check for overflow
CheckOverflow( length << 3 );
ptr = writeData + curSize;
curSize += length;
return ptr;
}
#define NBM( x ) (uint64)( ( 1LL << x ) - 1 )
static uint64 maskForNumBits64[33] = { NBM( 0x00 ), NBM( 0x01 ), NBM( 0x02 ), NBM( 0x03 ),
NBM( 0x04 ), NBM( 0x05 ), NBM( 0x06 ), NBM( 0x07 ),
NBM( 0x08 ), NBM( 0x09 ), NBM( 0x0A ), NBM( 0x0B ),
NBM( 0x0C ), NBM( 0x0D ), NBM( 0x0E ), NBM( 0x0F ),
NBM( 0x10 ), NBM( 0x11 ), NBM( 0x12 ), NBM( 0x13 ),
NBM( 0x14 ), NBM( 0x15 ), NBM( 0x16 ), NBM( 0x17 ),
NBM( 0x18 ), NBM( 0x19 ), NBM( 0x1A ), NBM( 0x1B ),
NBM( 0x1C ), NBM( 0x1D ), NBM( 0x1E ), NBM( 0x1F ), 0xFFFFFFFF };
/*
========================
idBitMsg::WriteBits
If the number of bits is negative a sign is included.
========================
*/
void idBitMsg::WriteBits( int value, int numBits ) {
if ( !writeData ) {
idLib::FatalError( "idBitMsg::WriteBits: cannot write to message" );
}
// check if the number of bits is valid
if ( numBits == 0 || numBits < -31 || numBits > 32 ) {
idLib::FatalError( "idBitMsg::WriteBits: bad numBits %i", numBits );
}
// check for value overflows
if ( numBits != 32 ) {
if ( numBits > 0 ) {
if ( value > ( 1 << numBits ) - 1 ) {
idLib::FatalError( "idBitMsg::WriteBits: value overflow %d %d",
value, numBits );
} else if ( value < 0 ) {
idLib::FatalError( "idBitMsg::WriteBits: value overflow %d %d",
value, numBits );
}
} else {
const unsigned shift = ( -1 - numBits );
int r = 1 << shift;
if ( value > r - 1 ) {
idLib::FatalError( "idBitMsg::WriteBits: value overflow %d %d",
value, numBits );
} else if ( value < -r ) {
idLib::FatalError( "idBitMsg::WriteBits: value overflow %d %d",
value, numBits );
}
}
}
if ( numBits < 0 ) {
numBits = -numBits;
}
// check for msg overflow
if ( CheckOverflow( numBits ) ) {
return;
}
// Merge value with possible previous leftover
tempValue |= (((int64)value) & maskForNumBits64[numBits] ) << writeBit;
writeBit += numBits;
// Flush 8 bits (1 byte) at a time
while ( writeBit >= 8 ) {
writeData[curSize++] = tempValue & 255;
tempValue >>= 8;
writeBit -= 8;
}
// Write leftover now, in case this is the last WriteBits call
if ( writeBit > 0 ) {
writeData[curSize] = tempValue & 255;
}
}
/*
========================
idBitMsg::WriteString
========================
*/
void idBitMsg::WriteString( const char * s, int maxLength, bool make7Bit ) {
if ( !s ) {
WriteData( "", 1 );
} else {
int i, l;
byte *dataPtr;
const byte *bytePtr;
l = idStr::Length( s );
if ( maxLength >= 0 && l >= maxLength ) {
l = maxLength - 1;
}
dataPtr = GetByteSpace( l + 1 );
bytePtr = reinterpret_cast< const byte * >( s );
if ( make7Bit ) {
for ( i = 0; i < l; i++ ) {
if ( bytePtr[i] > 127 ) {
dataPtr[i] = '.';
} else {
dataPtr[i] = bytePtr[i];
}
}
} else {
for ( i = 0; i < l; i++ ) {
dataPtr[i] = bytePtr[i];
}
}
dataPtr[i] = '\0';
}
}
/*
========================
idBitMsg::WriteData
========================
*/
void idBitMsg::WriteData( const void *data, int length ) {
memcpy( GetByteSpace( length ), data, length );
}
/*
========================
idBitMsg::WriteNetadr
========================
*/
void idBitMsg::WriteNetadr( const netadr_t adr ) {
WriteData( adr.ip, 4 );
WriteUShort( adr.port );
WriteByte( adr.type );
}
/*
========================
idBitMsg::WriteDeltaDict
========================
*/
bool idBitMsg::WriteDeltaDict( const idDict &dict, const idDict *base ) {
int i;
const idKeyValue *kv, *basekv;
bool changed = false;
if ( base != NULL ) {
for ( i = 0; i < dict.GetNumKeyVals(); i++ ) {
kv = dict.GetKeyVal( i );
basekv = base->FindKey( kv->GetKey() );
if ( basekv == NULL || basekv->GetValue().Icmp( kv->GetValue() ) != 0 ) {
WriteString( kv->GetKey() );
WriteString( kv->GetValue() );
changed = true;
}
}
WriteString( "" );
for ( i = 0; i < base->GetNumKeyVals(); i++ ) {
basekv = base->GetKeyVal( i );
kv = dict.FindKey( basekv->GetKey() );
if ( kv == NULL ) {
WriteString( basekv->GetKey() );
changed = true;
}
}
WriteString( "" );
} else {
for ( i = 0; i < dict.GetNumKeyVals(); i++ ) {
kv = dict.GetKeyVal( i );
WriteString( kv->GetKey() );
WriteString( kv->GetValue() );
changed = true;
}
WriteString( "" );
WriteString( "" );
}
return changed;
}
/*
========================
idBitMsg::ReadBits
If the number of bits is negative a sign is included.
========================
*/
int idBitMsg::ReadBits( int numBits ) const {
int value;
int valueBits;
int get;
int fraction;
bool sgn;
if ( !readData ) {
idLib::FatalError( "idBitMsg::ReadBits: cannot read from message" );
}
// check if the number of bits is valid
if ( numBits == 0 || numBits < -31 || numBits > 32 ) {
idLib::FatalError( "idBitMsg::ReadBits: bad numBits %i", numBits );
}
value = 0;
valueBits = 0;
if ( numBits < 0 ) {
numBits = -numBits;
sgn = true;
} else {
sgn = false;
}
// check for overflow
if ( numBits > GetRemainingReadBits() ) {
return -1;
}
while ( valueBits < numBits ) {
if ( readBit == 0 ) {
readCount++;
}
get = 8 - readBit;
if ( get > (numBits - valueBits) ) {
get = (numBits - valueBits);
}
fraction = readData[readCount - 1];
fraction >>= readBit;
fraction &= ( 1 << get ) - 1;
value |= fraction << valueBits;
valueBits += get;
readBit = ( readBit + get ) & 7;
}
if ( sgn ) {
if ( value & ( 1 << ( numBits - 1 ) ) ) {
value |= -1 ^ ( ( 1 << numBits ) - 1 );
}
}
return value;
}
/*
========================
idBitMsg::ReadString
========================
*/
int idBitMsg::ReadString( char * buffer, int bufferSize ) const {
int l, c;
ReadByteAlign();
l = 0;
while( 1 ) {
c = ReadByte();
if ( c <= 0 || c >= 255 ) {
break;
}
// translate all fmt spec to avoid crash bugs in string routines
if ( c == '%' ) {
c = '.';
}
// we will read past any excessively long string, so
// the following data can be read, but the string will
// be truncated
if ( l < bufferSize - 1 ) {
buffer[l] = c;
l++;
}
}
buffer[l] = 0;
return l;
}
/*
========================
idBitMsg::ReadString
========================
*/
int idBitMsg::ReadString( idStr & str ) const {
ReadByteAlign();
int cnt = 0;
for ( int i = readCount; i < curSize; i++ ) {
if ( readData[i] == 0 ) {
break;
}
cnt++;
}
str.Clear();
str.Append( (const char *)readData + readCount, cnt );
readCount += cnt + 1;
return str.Length();
}
/*
========================
idBitMsg::ReadData
========================
*/
int idBitMsg::ReadData( void *data, int length ) const {
int cnt;
ReadByteAlign();
cnt = readCount;
if ( readCount + length > curSize ) {
if ( data ) {
memcpy( data, readData + readCount, GetRemainingData() );
}
readCount = curSize;
} else {
if ( data ) {
memcpy( data, readData + readCount, length );
}
readCount += length;
}
return ( readCount - cnt );
}
/*
========================
idBitMsg::ReadNetadr
========================
*/
void idBitMsg::ReadNetadr( netadr_t *adr ) const {
ReadData( adr->ip, 4 );
adr->port = ReadUShort();
adr->type = ( netadrtype_t ) ReadByte();
}
/*
========================
idBitMsg::ReadDeltaDict
========================
*/
bool idBitMsg::ReadDeltaDict( idDict &dict, const idDict *base ) const {
char key[MAX_STRING_CHARS];
char value[MAX_STRING_CHARS];
bool changed = false;
if ( base != NULL ) {
dict = *base;
} else {
dict.Clear();
}
while( ReadString( key, sizeof( key ) ) != 0 ) {
ReadString( value, sizeof( value ) );
dict.Set( key, value );
changed = true;
}
while( ReadString( key, sizeof( key ) ) != 0 ) {
dict.Delete( key );
changed = true;
}
return changed;
}
/*
========================
idBitMsg::DirToBits
========================
*/
int idBitMsg::DirToBits( const idVec3 &dir, int numBits ) {
int max, bits;
float bias;
assert( numBits >= 6 && numBits <= 32 );
assert( dir.LengthSqr() - 1.0f < 0.01f );
numBits /= 3;
max = ( 1 << ( numBits - 1 ) ) - 1;
bias = 0.5f / max;
bits = IEEE_FLT_SIGNBITSET( dir.x ) << ( numBits * 3 - 1 );
bits |= ( idMath::Ftoi( ( idMath::Fabs( dir.x ) + bias ) * max ) ) << ( numBits * 2 );
bits |= IEEE_FLT_SIGNBITSET( dir.y ) << ( numBits * 2 - 1 );
bits |= ( idMath::Ftoi( ( idMath::Fabs( dir.y ) + bias ) * max ) ) << ( numBits * 1 );
bits |= IEEE_FLT_SIGNBITSET( dir.z ) << ( numBits * 1 - 1 );
bits |= ( idMath::Ftoi( ( idMath::Fabs( dir.z ) + bias ) * max ) ) << ( numBits * 0 );
return bits;
}
/*
========================
idBitMsg::BitsToDir
========================
*/
idVec3 idBitMsg::BitsToDir( int bits, int numBits ) {
static float sign[2] = { 1.0f, -1.0f };
int max;
float invMax;
idVec3 dir;
assert( numBits >= 6 && numBits <= 32 );
numBits /= 3;
max = ( 1 << ( numBits - 1 ) ) - 1;
invMax = 1.0f / max;
dir.x = sign[( bits >> ( numBits * 3 - 1 ) ) & 1] * ( ( bits >> ( numBits * 2 ) ) & max )
* invMax;
dir.y = sign[( bits >> ( numBits * 2 - 1 ) ) & 1] * ( ( bits >> ( numBits * 1 ) ) & max )
* invMax;
dir.z = sign[( bits >> ( numBits * 1 - 1 ) ) & 1] * ( ( bits >> ( numBits * 0 ) ) & max )
* invMax;
dir.NormalizeFast();
return dir;
}

958
neo/idlib/BitMsg.h Normal file
View File

@@ -0,0 +1,958 @@
/*
===========================================================================
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 __BITMSG_H__
#define __BITMSG_H__
/*
================================================
idBitMsg operates on a sequence of individual bits. It handles byte ordering and
avoids alignment errors. It allows concurrent writing and reading. The data set with Init
is never free-d.
================================================
*/
class idBitMsg {
public:
idBitMsg() { InitWrite( NULL, 0 ); }
idBitMsg( byte * data, int length ) { InitWrite( data, length ); }
idBitMsg( const byte * data, int length ) { InitRead( data, length ); }
// both read & write
void InitWrite( byte *data, int length );
// read only
void InitRead( const byte *data, int length );
// get data for writing
byte * GetWriteData();
// get data for reading
const byte * GetReadData() const;
// get the maximum message size
int GetMaxSize() const;
// generate error if not set and message is overflowed
void SetAllowOverflow( bool set );
// returns true if the message was overflowed
bool IsOverflowed() const;
// size of the message in bytes
int GetSize() const;
// set the message size
void SetSize( int size );
// get current write bit
int GetWriteBit() const;
// set current write bit
void SetWriteBit( int bit );
// returns number of bits written
int GetNumBitsWritten() const;
// space left in bytes for writing
int GetRemainingSpace() const;
// space left in bits for writing
int GetRemainingWriteBits() const;
//------------------------
// Write State
//------------------------
// save the write state
void SaveWriteState( int &s, int &b, uint64 &t ) const;
// restore the write state
void RestoreWriteState( int s, int b, uint64 t );
//------------------------
// Reading
//------------------------
// bytes read so far
int GetReadCount() const;
// set the number of bytes and bits read
void SetReadCount( int bytes );
// get current read bit
int GetReadBit() const;
// set current read bit
void SetReadBit( int bit );
// returns number of bits read
int GetNumBitsRead() const;
// number of bytes left to read
int GetRemainingData() const;
// number of bits left to read
int GetRemainingReadBits() const;
// save the read state
void SaveReadState( int &c, int &b ) const;
// restore the read state
void RestoreReadState( int c, int b );
//------------------------
// Writing
//------------------------
// begin writing
void BeginWriting();
// write up to the next byte boundary
void WriteByteAlign();
// write the specified number of bits
void WriteBits( int value, int numBits );
void WriteBool( bool c );
void WriteChar( int8 c );
void WriteByte( uint8 c );
void WriteShort( int16 c );
void WriteUShort( uint16 c );
void WriteLong( int32 c );
void WriteLongLong( int64 c );
void WriteFloat( float f );
void WriteFloat( float f, int exponentBits, int mantissaBits );
void WriteAngle8( float f );
void WriteAngle16( float f );
void WriteDir( const idVec3 &dir, int numBits );
void WriteString( const char *s, int maxLength = -1, bool make7Bit = true );
void WriteData( const void *data, int length );
void WriteNetadr( const netadr_t adr );
void WriteUNorm8( float f ) { WriteByte( idMath::Ftob( f * 255.0f ) ); }
void WriteUNorm16( float f ) { WriteUShort( idMath::Ftoi( f * 65535.0f ) ); }
void WriteNorm16( float f ) { WriteShort( idMath::Ftoi( f * 32767.0f ) ); }
void WriteDeltaChar( int8 oldValue, int8 newValue ) { WriteByte( newValue - oldValue ); }
void WriteDeltaByte( uint8 oldValue, uint8 newValue ) { WriteByte( newValue - oldValue ); }
void WriteDeltaShort( int16 oldValue, int16 newValue ) { WriteUShort( newValue - oldValue ); }
void WriteDeltaUShort( uint16 oldValue, uint16 newValue ) { WriteUShort( newValue - oldValue ); }
void WriteDeltaLong( int32 oldValue, int32 newValue ) { WriteLong( newValue - oldValue ); }
void WriteDeltaFloat( float oldValue, float newValue ) { WriteFloat( newValue - oldValue ); }
void WriteDeltaFloat( float oldValue, float newValue, int exponentBits, int mantissaBits ) { WriteFloat( newValue - oldValue, exponentBits, mantissaBits ); }
bool WriteDeltaDict( const idDict &dict, const idDict *base );
template< int _max_, int _numBits_ >
void WriteQuantizedFloat( float value );
template< int _max_, int _numBits_ >
void WriteQuantizedUFloat( float value ); // Quantize a float to a variable number of bits (assumes unsigned, uses simple quantization)
template< typename T >
void WriteVectorFloat( const T & v ) { for ( int i = 0; i < v.GetDimension(); i++ ) { WriteFloat( v[i] ); } }
template< typename T >
void WriteVectorUNorm8( const T & v ) { for ( int i = 0; i < v.GetDimension(); i++ ) { WriteUNorm8( v[i] ); } }
template< typename T >
void WriteVectorUNorm16( const T & v ) { for ( int i = 0; i < v.GetDimension(); i++ ) { WriteUNorm16( v[i] ); } }
template< typename T >
void WriteVectorNorm16( const T & v ) { for ( int i = 0; i < v.GetDimension(); i++ ) { WriteNorm16( v[i] ); } }
// Compress a vector to a variable number of bits (assumes signed, uses simple quantization)
template< typename T, int _max_, int _numBits_ >
void WriteQuantizedVector( const T & v ) { for ( int i = 0; i < v.GetDimension(); i++ ) { WriteQuantizedFloat< _max_, _numBits_ >( v[i] ); } }
// begin reading.
void BeginReading() const;
// read up to the next byte boundary
void ReadByteAlign() const;
// read the specified number of bits
int ReadBits( int numBits ) const;
bool ReadBool() const;
int ReadChar() const;
int ReadByte() const;
int ReadShort() const;
int ReadUShort() const;
int ReadLong() const;
int64 ReadLongLong() const;
float ReadFloat() const;
float ReadFloat( int exponentBits, int mantissaBits ) const;
float ReadAngle8() const;
float ReadAngle16() const;
idVec3 ReadDir( int numBits ) const;
int ReadString( char *buffer, int bufferSize ) const;
int ReadString( idStr & str ) const;
int ReadData( void *data, int length ) const;
void ReadNetadr( netadr_t *adr ) const;
float ReadUNorm8() const { return ReadByte() / 255.0f; }
float ReadUNorm16() const { return ReadUShort() / 65535.0f; }
float ReadNorm16() const { return ReadShort() / 32767.0f; }
int8 ReadDeltaChar( int8 oldValue ) const { return oldValue + ReadByte(); }
uint8 ReadDeltaByte( uint8 oldValue ) const { return oldValue + ReadByte(); }
int16 ReadDeltaShort( int16 oldValue ) const { return oldValue + ReadUShort(); }
uint16 ReadDeltaUShort( uint16 oldValue ) const { return oldValue + ReadUShort(); }
int32 ReadDeltaLong( int32 oldValue ) const { return oldValue + ReadLong(); }
float ReadDeltaFloat( float oldValue ) const { return oldValue + ReadFloat(); }
float ReadDeltaFloat( float oldValue, int exponentBits, int mantissaBits ) const { return oldValue + ReadFloat( exponentBits, mantissaBits ); }
bool ReadDeltaDict( idDict &dict, const idDict *base ) const;
template< int _max_, int _numBits_ >
float ReadQuantizedFloat() const;
template< int _max_, int _numBits_ >
float ReadQuantizedUFloat() const;
template< typename T >
void ReadVectorFloat( T & v ) const { for ( int i = 0; i < v.GetDimension(); i++ ) { v[i] = ReadFloat(); } }
template< typename T >
void ReadVectorUNorm8( T & v ) const { for ( int i = 0; i < v.GetDimension(); i++ ) { v[i] = ReadUNorm8(); } }
template< typename T >
void ReadVectorUNorm16( T & v ) const { for ( int i = 0; i < v.GetDimension(); i++ ) { v[i] = ReadUNorm16(); } }
template< typename T >
void ReadVectorNorm16( T & v ) const { for ( int i = 0; i < v.GetDimension(); i++ ) { v[i] = ReadNorm16(); } }
template< typename T, int _max_, int _numBits_ >
void ReadQuantizedVector( T & v ) const { for ( int i = 0; i < v.GetDimension(); i++ ) { v[i] = ReadQuantizedFloat< _max_, _numBits_ >(); } }
static int DirToBits( const idVec3 &dir, int numBits );
static idVec3 BitsToDir( int bits, int numBits );
void SetHasChanged( bool b ) { hasChanged = b; }
bool HasChanged() const { return hasChanged; }
private:
byte * writeData; // pointer to data for writing
const byte * readData; // pointer to data for reading
int maxSize; // maximum size of message in bytes
int curSize; // current size of message in bytes
mutable int writeBit; // number of bits written to the last written byte
mutable int readCount; // number of bytes read so far
mutable int readBit; // number of bits read from the last read byte
bool allowOverflow; // if false, generate error when the message is overflowed
bool overflowed; // set true if buffer size failed (with allowOverflow set)
bool hasChanged; // Hack
mutable uint64 tempValue;
private:
bool CheckOverflow( int numBits );
byte * GetByteSpace( int length );
};
/*
========================
idBitMsg::InitWrite
========================
*/
ID_INLINE void idBitMsg::InitWrite( byte *data, int length ) {
writeData = data;
readData = data;
maxSize = length;
curSize = 0;
writeBit = 0;
readCount = 0;
readBit = 0;
allowOverflow = false;
overflowed = false;
tempValue = 0;
}
/*
========================
idBitMsg::InitRead
========================
*/
ID_INLINE void idBitMsg::InitRead( const byte *data, int length ) {
writeData = NULL;
readData = data;
maxSize = length;
curSize = length;
writeBit = 0;
readCount = 0;
readBit = 0;
allowOverflow = false;
overflowed = false;
tempValue = 0;
}
/*
========================
idBitMsg::GetWriteData
========================
*/
ID_INLINE byte *idBitMsg::GetWriteData() {
return writeData;
}
/*
========================
idBitMsg::GetReadData
========================
*/
ID_INLINE const byte *idBitMsg::GetReadData() const {
return readData;
}
/*
========================
idBitMsg::GetMaxSize
========================
*/
ID_INLINE int idBitMsg::GetMaxSize() const {
return maxSize;
}
/*
========================
idBitMsg::SetAllowOverflow
========================
*/
ID_INLINE void idBitMsg::SetAllowOverflow( bool set ) {
allowOverflow = set;
}
/*
========================
idBitMsg::IsOverflowed
========================
*/
ID_INLINE bool idBitMsg::IsOverflowed() const {
return overflowed;
}
/*
========================
idBitMsg::GetSize
========================
*/
ID_INLINE int idBitMsg::GetSize() const {
return curSize + ( writeBit != 0 );
}
/*
========================
idBitMsg::SetSize
========================
*/
ID_INLINE void idBitMsg::SetSize( int size ) {
assert( writeBit == 0 );
if ( size > maxSize ) {
curSize = maxSize;
} else {
curSize = size;
}
}
/*
========================
idBitMsg::GetWriteBit
========================
*/
ID_INLINE int idBitMsg::GetWriteBit() const {
return writeBit;
}
/*
========================
idBitMsg::SetWriteBit
========================
*/
ID_INLINE void idBitMsg::SetWriteBit( int bit ) {
// see idBitMsg::WriteByteAlign
assert( false );
writeBit = bit & 7;
if ( writeBit ) {
writeData[curSize - 1] &= ( 1 << writeBit ) - 1;
}
}
/*
========================
idBitMsg::GetNumBitsWritten
========================
*/
ID_INLINE int idBitMsg::GetNumBitsWritten() const {
return ( curSize << 3 ) + writeBit;
}
/*
========================
idBitMsg::GetRemainingSpace
========================
*/
ID_INLINE int idBitMsg::GetRemainingSpace() const {
return maxSize - GetSize();
}
/*
========================
idBitMsg::GetRemainingWriteBits
========================
*/
ID_INLINE int idBitMsg::GetRemainingWriteBits() const {
return ( maxSize << 3 ) - GetNumBitsWritten();
}
/*
========================
idBitMsg::SaveWriteState
========================
*/
ID_INLINE void idBitMsg::SaveWriteState( int &s, int &b, uint64 &t ) const {
s = curSize;
b = writeBit;
t = tempValue;
}
/*
========================
idBitMsg::RestoreWriteState
========================
*/
ID_INLINE void idBitMsg::RestoreWriteState( int s, int b, uint64 t ) {
curSize = s;
writeBit = b & 7;
if ( writeBit ) {
writeData[curSize] &= ( 1 << writeBit ) - 1;
}
tempValue = t;
}
/*
========================
idBitMsg::GetReadCount
========================
*/
ID_INLINE int idBitMsg::GetReadCount() const {
return readCount;
}
/*
========================
idBitMsg::SetReadCount
========================
*/
ID_INLINE void idBitMsg::SetReadCount( int bytes ) {
readCount = bytes;
}
/*
========================
idBitMsg::GetReadBit
========================
*/
ID_INLINE int idBitMsg::GetReadBit() const {
return readBit;
}
/*
========================
idBitMsg::SetReadBit
========================
*/
ID_INLINE void idBitMsg::SetReadBit( int bit ) {
readBit = bit & 7;
}
/*
========================
idBitMsg::GetNumBitsRead
========================
*/
ID_INLINE int idBitMsg::GetNumBitsRead() const {
return ( ( readCount << 3 ) - ( ( 8 - readBit ) & 7 ) );
}
/*
========================
idBitMsg::GetRemainingData
========================
*/
ID_INLINE int idBitMsg::GetRemainingData() const {
assert( writeBit == 0 );
return curSize - readCount;
}
/*
========================
idBitMsg::GetRemainingReadBits
========================
*/
ID_INLINE int idBitMsg::GetRemainingReadBits() const {
assert( writeBit == 0 );
return ( curSize << 3 ) - GetNumBitsRead();
}
/*
========================
idBitMsg::SaveReadState
========================
*/
ID_INLINE void idBitMsg::SaveReadState( int &c, int &b ) const {
assert( writeBit == 0 );
c = readCount;
b = readBit;
}
/*
========================
idBitMsg::RestoreReadState
========================
*/
ID_INLINE void idBitMsg::RestoreReadState( int c, int b ) {
assert( writeBit == 0 );
readCount = c;
readBit = b & 7;
}
/*
========================
idBitMsg::BeginWriting
========================
*/
ID_INLINE void idBitMsg::BeginWriting() {
curSize = 0;
overflowed = false;
writeBit = 0;
tempValue = 0;
}
/*
========================
idBitMsg::WriteByteAlign
========================
*/
ID_INLINE void idBitMsg::WriteByteAlign() {
// it is important that no uninitialized data slips in the msg stream,
// because we use memcmp to decide if entities have changed and wether we should transmit them
// this function has the potential to leave uninitialized bits into the stream,
// however idBitMsg::WriteBits is properly initializing the byte to 0 so hopefully we are still safe
// adding this extra check just in case
curSize += writeBit != 0;
assert( writeBit == 0 || ( ( writeData[curSize - 1] >> writeBit ) == 0 ) ); // had to early out writeBit == 0 because when writeBit == 0 writeData[curSize - 1] may be the previous byte written and trigger false positives
writeBit = 0;
tempValue = 0;
}
/*
========================
idBitMsg::WriteBool
========================
*/
ID_INLINE void idBitMsg::WriteBool( bool c ) {
WriteBits( c, 1 );
}
/*
========================
idBitMsg::WriteChar
========================
*/
ID_INLINE void idBitMsg::WriteChar( int8 c ) {
WriteBits( c, -8 );
}
/*
========================
idBitMsg::WriteByte
========================
*/
ID_INLINE void idBitMsg::WriteByte( uint8 c ) {
WriteBits( c, 8 );
}
/*
========================
idBitMsg::WriteShort
========================
*/
ID_INLINE void idBitMsg::WriteShort( int16 c ) {
WriteBits( c, -16 );
}
/*
========================
idBitMsg::WriteUShort
========================
*/
ID_INLINE void idBitMsg::WriteUShort( uint16 c ) {
WriteBits( c, 16 );
}
/*
========================
idBitMsg::WriteLong
========================
*/
ID_INLINE void idBitMsg::WriteLong( int32 c ) {
WriteBits( c, 32 );
}
/*
========================
idBitMsg::WriteLongLong
========================
*/
ID_INLINE void idBitMsg::WriteLongLong( int64 c ) {
int a = c;
int b = c >> 32;
WriteBits( a, 32 );
WriteBits( b, 32 );
}
/*
========================
idBitMsg::WriteFloat
========================
*/
ID_INLINE void idBitMsg::WriteFloat( float f ) {
WriteBits( *reinterpret_cast<int *>(&f), 32 );
}
/*
========================
idBitMsg::WriteFloat
========================
*/
ID_INLINE void idBitMsg::WriteFloat( float f, int exponentBits, int mantissaBits ) {
int bits = idMath::FloatToBits( f, exponentBits, mantissaBits );
WriteBits( bits, 1 + exponentBits + mantissaBits );
}
/*
========================
idBitMsg::WriteAngle8
========================
*/
ID_INLINE void idBitMsg::WriteAngle8( float f ) {
WriteByte( ANGLE2BYTE( f ) );
}
/*
========================
idBitMsg::WriteAngle16
========================
*/
ID_INLINE void idBitMsg::WriteAngle16( float f ) {
WriteShort( ANGLE2SHORT(f) );
}
/*
========================
idBitMsg::WriteDir
========================
*/
ID_INLINE void idBitMsg::WriteDir( const idVec3 &dir, int numBits ) {
WriteBits( DirToBits( dir, numBits ), numBits );
}
/*
========================
idBitMsg::BeginReading
========================
*/
ID_INLINE void idBitMsg::BeginReading() const {
readCount = 0;
readBit = 0;
writeBit = 0;
tempValue = 0;
}
/*
========================
idBitMsg::ReadByteAlign
========================
*/
ID_INLINE void idBitMsg::ReadByteAlign() const {
readBit = 0;
}
/*
========================
idBitMsg::ReadBool
========================
*/
ID_INLINE bool idBitMsg::ReadBool() const {
return ( ReadBits( 1 ) == 1 ) ? true : false;
}
/*
========================
idBitMsg::ReadChar
========================
*/
ID_INLINE int idBitMsg::ReadChar() const {
return (signed char)ReadBits( -8 );
}
/*
========================
idBitMsg::ReadByte
========================
*/
ID_INLINE int idBitMsg::ReadByte() const {
return (unsigned char)ReadBits( 8 );
}
/*
========================
idBitMsg::ReadShort
========================
*/
ID_INLINE int idBitMsg::ReadShort() const {
return (short)ReadBits( -16 );
}
/*
========================
idBitMsg::ReadUShort
========================
*/
ID_INLINE int idBitMsg::ReadUShort() const {
return (unsigned short)ReadBits( 16 );
}
/*
========================
idBitMsg::ReadLong
========================
*/
ID_INLINE int idBitMsg::ReadLong() const {
return ReadBits( 32 );
}
/*
========================
idBitMsg::ReadLongLong
========================
*/
ID_INLINE int64 idBitMsg::ReadLongLong() const {
int64 a = ReadBits( 32 );
int64 b = ReadBits( 32 );
int64 c = ( 0x00000000ffffffff & a ) | ( b << 32 );
return c;
}
/*
========================
idBitMsg::ReadFloat
========================
*/
ID_INLINE float idBitMsg::ReadFloat() const {
float value;
*reinterpret_cast<int *>(&value) = ReadBits( 32 );
return value;
}
/*
========================
idBitMsg::ReadFloat
========================
*/
ID_INLINE float idBitMsg::ReadFloat( int exponentBits, int mantissaBits ) const {
int bits = ReadBits( 1 + exponentBits + mantissaBits );
return idMath::BitsToFloat( bits, exponentBits, mantissaBits );
}
/*
========================
idBitMsg::ReadAngle8
========================
*/
ID_INLINE float idBitMsg::ReadAngle8() const {
return BYTE2ANGLE( ReadByte() );
}
/*
========================
idBitMsg::ReadAngle16
========================
*/
ID_INLINE float idBitMsg::ReadAngle16() const {
return SHORT2ANGLE( ReadShort() );
}
/*
========================
idBitMsg::ReadDir
========================
*/
ID_INLINE idVec3 idBitMsg::ReadDir( int numBits ) const {
return BitsToDir( ReadBits( numBits ), numBits );
}
/*
========================
idBitMsg::WriteQuantizedFloat
========================
*/
template< int _max_, int _numBits_ >
ID_INLINE void idBitMsg::WriteQuantizedFloat( float value ) {
enum { storeMax = ( 1 << ( _numBits_ - 1 ) ) - 1 };
if ( _max_ > storeMax ) {
// Scaling down (scale should be < 1)
const float scale = (float)storeMax / (float)_max_;
WriteBits( idMath::ClampInt( -storeMax, storeMax, idMath::Ftoi( value * scale ) ), -_numBits_ );
} else {
// Scaling up (scale should be >= 1) (Preserve whole numbers when possible)
enum { scale = storeMax / _max_ };
WriteBits( idMath::ClampInt( -storeMax, storeMax, idMath::Ftoi( value * scale ) ), -_numBits_ );
}
}
/*
========================
idBitMsg::WriteQuantizedUFloat
========================
*/
template< int _max_, int _numBits_ >
ID_INLINE void idBitMsg::WriteQuantizedUFloat( float value ) {
enum { storeMax = ( 1 << _numBits_ ) - 1 };
if ( _max_ > storeMax ) {
// Scaling down (scale should be < 1)
const float scale = (float)storeMax / (float)_max_;
WriteBits( idMath::ClampInt( 0, storeMax, idMath::Ftoi( value * scale ) ), _numBits_ );
} else {
// Scaling up (scale should be >= 1) (Preserve whole numbers when possible)
enum { scale = storeMax / _max_ };
WriteBits( idMath::ClampInt( 0, storeMax, idMath::Ftoi( value * scale ) ), _numBits_ );
}
}
/*
========================
idBitMsg::ReadQuantizedFloat
========================
*/
template< int _max_, int _numBits_ >
ID_INLINE float idBitMsg::ReadQuantizedFloat() const {
enum { storeMax = ( 1 << ( _numBits_ - 1 ) ) - 1 };
if ( _max_ > storeMax ) {
// Scaling down (scale should be < 1)
const float invScale = (float)_max_ / (float)storeMax;
return (float)ReadBits( -_numBits_ ) * invScale;
} else {
// Scaling up (scale should be >= 1) (Preserve whole numbers when possible)
// Scale will be a whole number.
// We use a float to get rid of (potential divide by zero) which is handled above, but the compiler is dumb
const float scale = storeMax / _max_;
const float invScale = 1.0f / scale;
return (float)ReadBits( -_numBits_ ) * invScale;
}
}
/*
========================
idBitMsg::ReadQuantizedUFloat
========================
*/
template< int _max_, int _numBits_ >
float idBitMsg::ReadQuantizedUFloat() const {
enum { storeMax = ( 1 << _numBits_ ) - 1 };
if ( _max_ > storeMax ) {
// Scaling down (scale should be < 1)
const float invScale = (float)_max_ / (float)storeMax;
return (float)ReadBits( _numBits_ ) * invScale;
} else {
// Scaling up (scale should be >= 1) (Preserve whole numbers when possible)
// Scale will be a whole number.
// We use a float to get rid of (potential divide by zero) which is handled above, but the compiler is dumb
const float scale = storeMax / _max_;
const float invScale = 1.0f / scale;
return (float)ReadBits( _numBits_ ) * invScale;
}
}
/*
================
WriteFloatArray
Writes all the values from the array to the bit message.
================
*/
template< class _arrayType_ >
void WriteFloatArray( idBitMsg & message, const _arrayType_ & sourceArray ) {
for( int i = 0; i < idTupleSize< _arrayType_ >::value; ++i ) {
message.WriteFloat( sourceArray[i] );
}
}
/*
================
WriteFloatArrayDelta
Writes _num_ values from the array to the bit message.
================
*/
template< class _arrayType_ >
void WriteDeltaFloatArray( idBitMsg & message, const _arrayType_ & oldArray, const _arrayType_ & newArray ) {
for( int i = 0; i < idTupleSize< _arrayType_ >::value; ++i ) {
message.WriteDeltaFloat( oldArray[i], newArray[i] );
}
}
/*
================
ReadFloatArray
Reads _num_ values from the array to the bit message.
================
*/
template< class _arrayType_ >
_arrayType_ ReadFloatArray( const idBitMsg & message ) {
_arrayType_ result;
for( int i = 0; i < idTupleSize< _arrayType_ >::value; ++i ) {
result[i] = message.ReadFloat();
}
return result;
}
/*
================
ReadDeltaFloatArray
Reads _num_ values from the array to the bit message.
================
*/
template< class _arrayType_ >
_arrayType_ ReadDeltaFloatArray( const idBitMsg & message, const _arrayType_ & oldArray ) {
_arrayType_ result;
for( int i = 0; i < idTupleSize< _arrayType_ >::value; ++i ) {
result[i] = message.ReadDeltaFloat( oldArray[i] );
}
return result;
}
#endif /* !__BITMSG_H__ */

173
neo/idlib/Callback.h Normal file
View File

@@ -0,0 +1,173 @@
/*
===========================================================================
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 __CALLBACK_H__
#define __CALLBACK_H__
/*
================================================================================================
This file defines a set of template functors for generating callbacks, specifically
the OnChange handlers in the CVar system.
================================================================================================
*/
/*
================================================
idCallback
================================================
*/
class idCallback {
public:
virtual ~idCallback() {}
virtual void Call() = 0;
virtual idCallback * Clone() const = 0;
};
/*
================================================
idCallbackStatic
Callback class that forwards the call to a c-style function
================================================
*/
class idCallbackStatic : public idCallback {
public:
idCallbackStatic( void (*f)() ) {
this->f = f;
}
void Call() {
f();
}
idCallback * Clone() const {
//idScopedGlobalHeap everythingHereGoesInTheGlobalHeap;
return new (TAG_FUNC_CALLBACK) idCallbackStatic( f );
}
private:
void (*f)();
};
/*
================================================
idCallbackBindMem
Callback class that forwards the call to a member function
================================================
*/
template< class T >
class idCallbackBindMem : public idCallback {
public:
idCallbackBindMem( T * t, void (T::*f)() ) {
this->t = t;
this->f = f;
}
void Call() {
(t->*f)();
}
idCallback * Clone() const {
return new (TAG_FUNC_CALLBACK) idCallbackBindMem( t, f );
}
private:
T * t;
void (T::*f)();
};
/*
================================================
idCallbackBindMemArg1
Callback class that forwards the call to a member function with an additional constant parameter
================================================
*/
template< class T, typename A1 >
class idCallbackBindMemArg1 : public idCallback {
public:
idCallbackBindMemArg1( T * t_, void (T::*f_)( A1 ), A1 a1_ ) :
t( t_ ),
f( f_ ),
a1( a1_ ) {
}
void Call() {
(t->*f)( a1 );
}
idCallback * Clone() const {
return new (TAG_FUNC_CALLBACK) idCallbackBindMemArg1( t, f, a1 );
}
private:
T * t;
void (T::*f)( A1 );
A1 a1;
// hack to get to compile on the 360 with reference arguments
// with this on the PC, the MakeCallback function fails compilation because it's returning a copy
// therefore, the Arg1 callbacks can't have arguments that are references
//DISALLOW_COPY_AND_ASSIGN( idCallbackBindMemArg1 );
};
/*
================================================================================================
These are needed because we can't derive the type of an object from the type passed to the
constructor. If it weren't for these, we'd have to manually specify the type:
idCallbackBindMem<idFoo>( this, &idFoo::MyFunction );
becomes:
MakeCallback( this, &idFoo::MyFunction );
================================================================================================
*/
/*
========================
MakeCallback
========================
*/
ID_INLINE_EXTERN idCallbackStatic MakeCallback( void (*f)(void) ) {
return idCallbackStatic( f );
}
/*
========================
MakeCallback
========================
*/
template < class T >
ID_INLINE_EXTERN idCallbackBindMem<T> MakeCallback( T * t, void (T::*f)(void) ) {
return idCallbackBindMem<T>( t, f );
}
/*
========================
MakeCallback
========================
*/
template < class T, typename A1 >
ID_INLINE_EXTERN idCallbackBindMemArg1<T, A1> MakeCallback( T * t, void (T::*f)( A1 ), A1 a1 ) {
return idCallbackBindMemArg1<T, A1>( t, f, a1 );
}
#endif // __CALLBACK_H__

202
neo/idlib/CmdArgs.cpp Normal file
View File

@@ -0,0 +1,202 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
/*
============
idCmdArgs::operator=
============
*/
void idCmdArgs::operator=( const idCmdArgs &args ) {
int i;
argc = args.argc;
memcpy( tokenized, args.tokenized, MAX_COMMAND_STRING );
for ( i = 0; i < argc; i++ ) {
argv[ i ] = tokenized + ( args.argv[ i ] - args.tokenized );
}
}
/*
============
idCmdArgs::Args
============
*/
const char *idCmdArgs::Args( int start, int end, bool escapeArgs ) const {
static char cmd_args[MAX_COMMAND_STRING];
int i;
assert( argc < MAX_COMMAND_ARGS );
if ( end < 0 ) {
end = argc - 1;
} else if ( end >= argc ) {
end = argc - 1;
}
cmd_args[0] = '\0';
if ( escapeArgs ) {
strcat( cmd_args, "\"" );
}
for ( i = start; i <= end; i++ ) {
if ( i > start ) {
if ( escapeArgs ) {
strcat( cmd_args, "\" \"" );
} else {
strcat( cmd_args, " " );
}
}
if ( escapeArgs && strchr( argv[i], '\\' ) ) {
char *p = argv[i];
while ( *p != '\0' ) {
if ( *p == '\\' ) {
strcat( cmd_args, "\\\\" );
} else {
int l = strlen( cmd_args );
cmd_args[ l ] = *p;
cmd_args[ l+1 ] = '\0';
}
p++;
}
} else {
strcat( cmd_args, argv[i] );
}
}
if ( escapeArgs ) {
strcat( cmd_args, "\"" );
}
return cmd_args;
}
/*
============
idCmdArgs::TokenizeString
Parses the given string into command line tokens.
The text is copied to a separate buffer and 0 characters
are inserted in the appropriate place. The argv array
will point into this temporary buffer.
============
*/
void idCmdArgs::TokenizeString( const char *text, bool keepAsStrings ) {
idLexer lex;
idToken token, number;
int len, totalLen;
// clear previous args
argc = 0;
if ( !text ) {
return;
}
lex.LoadMemory( text, strlen( text ), "idCmdSystemLocal::TokenizeString" );
lex.SetFlags( LEXFL_NOERRORS
| LEXFL_NOWARNINGS
| LEXFL_NOSTRINGCONCAT
| LEXFL_ALLOWPATHNAMES
| LEXFL_NOSTRINGESCAPECHARS
| LEXFL_ALLOWIPADDRESSES | ( keepAsStrings ? LEXFL_ONLYSTRINGS : 0 ) );
totalLen = 0;
while ( 1 ) {
if ( argc == MAX_COMMAND_ARGS ) {
return; // this is usually something malicious
}
if ( !lex.ReadToken( &token ) ) {
return;
}
// check for negative numbers
if ( !keepAsStrings && ( token == "-" ) ) {
if ( lex.CheckTokenType( TT_NUMBER, 0, &number ) ) {
token = "-" + number;
}
}
// check for cvar expansion
if ( token == "$" ) {
if ( !lex.ReadToken( &token ) ) {
return;
}
if ( idLib::cvarSystem ) {
token = idLib::cvarSystem->GetCVarString( token.c_str() );
} else {
token = "<unknown>";
}
}
len = token.Length();
if ( totalLen + len + 1 > sizeof( tokenized ) ) {
return; // this is usually something malicious
}
// regular token
argv[argc] = tokenized + totalLen;
argc++;
idStr::Copynz( tokenized + totalLen, token.c_str(), sizeof( tokenized ) - totalLen );
totalLen += len + 1;
}
}
/*
============
idCmdArgs::AppendArg
============
*/
void idCmdArgs::AppendArg( const char *text ) {
if ( argc >= MAX_COMMAND_ARGS ) {
return;
}
if ( !argc ) {
argc = 1;
argv[ 0 ] = tokenized;
idStr::Copynz( tokenized, text, sizeof( tokenized ) );
} else {
argv[ argc ] = argv[ argc-1 ] + strlen( argv[ argc-1 ] ) + 1;
idStr::Copynz( argv[ argc ], text, sizeof( tokenized ) - ( argv[ argc ] - tokenized ) );
argc++;
}
}
/*
============
idCmdArgs::GetArgs
============
*/
const char * const * idCmdArgs::GetArgs( int *_argc ) {
*_argc = argc;
return (const char **)&argv[0];
}

73
neo/idlib/CmdArgs.h Normal file
View File

@@ -0,0 +1,73 @@
/*
===========================================================================
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 __CMDARGS_H__
#define __CMDARGS_H__
/*
===============================================================================
Command arguments.
===============================================================================
*/
class idCmdArgs {
public:
idCmdArgs() { argc = 0; }
idCmdArgs( const char *text, bool keepAsStrings ) { TokenizeString( text, keepAsStrings ); }
void operator=( const idCmdArgs &args );
// The functions that execute commands get their parameters with these functions.
int Argc() const { return argc; }
// Argv() will return an empty string, not NULL if arg >= argc.
const char * Argv( int arg ) const { return ( arg >= 0 && arg < argc ) ? argv[arg] : ""; }
// Returns a single string containing argv(start) to argv(end)
// escapeArgs is a fugly way to put the string back into a state ready to tokenize again
const char * Args( int start = 1, int end = -1, bool escapeArgs = false ) const;
// Takes a null terminated string and breaks the string up into arg tokens.
// Does not need to be /n terminated.
// Set keepAsStrings to true to only seperate tokens from whitespace and comments, ignoring punctuation
void TokenizeString( const char *text, bool keepAsStrings );
void AppendArg( const char *text );
void Clear() { argc = 0; }
const char * const * GetArgs( int *argc );
private:
static const int MAX_COMMAND_ARGS = 64;
static const int MAX_COMMAND_STRING = 2 * MAX_STRING_CHARS;
int argc; // number of arguments
char * argv[MAX_COMMAND_ARGS]; // points into tokenized
char tokenized[MAX_COMMAND_STRING]; // will have 0 bytes inserted
};
#endif /* !__CMDARGS_H__ */

59
neo/idlib/CommandLink.cpp Normal file
View File

@@ -0,0 +1,59 @@
/*
===========================================================================
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"
/*
========================
CommandLinks
The command system is not required for idLib, but we want to be able
to use the CONSOLE_COMMAND() macro inside idlib, so these must be here.
========================
*/
idCommandLink *CommandLinks( idCommandLink *cl ) {
static idCommandLink *commandLinks = NULL;
if ( cl != NULL ) {
commandLinks = cl;
}
return commandLinks;
}
idCommandLink *commandLinks = NULL;
idCommandLink::idCommandLink( const char *cmdName, cmdFunction_t function,
const char *description, argCompletion_t argCompletion ) {
next = CommandLinks();
CommandLinks( this );
cmdName_ = cmdName;
function_ = function;
description_ = description;
argCompletion_ = argCompletion;
}

83
neo/idlib/DataQueue.h Normal file
View File

@@ -0,0 +1,83 @@
#ifndef DATAQUEUE_H
#define DATAQUEUE_H
template< int maxItems, int maxBuffer >
class idDataQueue {
public:
idDataQueue() {
dataLength = 0;
}
bool Append( int sequence, const byte * b1, int b1Len, const byte * b2 = NULL, int b2Len = 0 );
void RemoveOlderThan( int sequence );
int GetDataLength() const { return dataLength; }
int Num() const { return items.Num(); }
int ItemSequence( int i ) const { return items[i].sequence; }
int ItemLength( int i ) const { return items[i].length; }
const byte * ItemData( int i ) const { return &data[items[i].dataOffset]; }
void Clear() { dataLength = 0; items.Clear(); memset( data, 0, sizeof( data ) ); }
private:
struct msgItem_t {
int sequence;
int length;
int dataOffset;
};
idStaticList<msgItem_t, maxItems > items;
int dataLength;
byte data[ maxBuffer ];
};
/*
========================
idDataQueue::RemoveOlderThan
========================
*/
template< int maxItems, int maxBuffer >
void idDataQueue< maxItems, maxBuffer >::RemoveOlderThan( int sequence ) {
int length = 0;
while ( items.Num() > 0 && items[0].sequence < sequence ) {
length += items[0].length;
items.RemoveIndex( 0 );
}
if ( length >= dataLength ) {
assert( items.Num() == 0 );
assert( dataLength == length );
dataLength = 0;
} else if ( length > 0 ) {
memmove( data, data + length, dataLength - length );
dataLength -= length;
}
length = 0;
for ( int i = 0; i < items.Num(); i++ ) {
items[i].dataOffset = length;
length += items[i].length;
}
assert( length == dataLength );
}
/*
========================
idDataQueue::Append
========================
*/
template< int maxItems, int maxBuffer >
bool idDataQueue< maxItems, maxBuffer >::Append( int sequence, const byte * b1, int b1Len, const byte * b2, int b2Len ) {
if ( items.Num() == items.Max() ) {
return false;
}
if ( dataLength + b1Len + b2Len >= maxBuffer ) {
return false;
}
msgItem_t & item = *items.Alloc();
item.length = b1Len + b2Len;
item.sequence = sequence;
item.dataOffset = dataLength;
memcpy( data + dataLength, b1, b1Len ); dataLength += b1Len;
memcpy( data + dataLength, b2, b2Len ); dataLength += b2Len;
return true;
}
#endif // DATAQUEUE_H

943
neo/idlib/Dict.cpp Normal file
View File

@@ -0,0 +1,943 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
idStrPool idDict::globalKeys;
idStrPool idDict::globalValues;
/*
================
idDict::operator=
clear existing key/value pairs and copy all key/value pairs from other
================
*/
idDict &idDict::operator=( const idDict &other ) {
int i;
// check for assignment to self
if ( this == &other ) {
return *this;
}
Clear();
args = other.args;
argHash = other.argHash;
for ( i = 0; i < args.Num(); i++ ) {
args[i].key = globalKeys.CopyString( args[i].key );
args[i].value = globalValues.CopyString( args[i].value );
}
return *this;
}
/*
================
idDict::Copy
copy all key value pairs without removing existing key/value pairs not present in the other dict
================
*/
void idDict::Copy( const idDict &other ) {
int i, n, *found;
idKeyValue kv;
// check for assignment to self
if ( this == &other ) {
return;
}
n = other.args.Num();
if ( args.Num() ) {
found = (int *) _alloca16( other.args.Num() * sizeof( int ) );
for ( i = 0; i < n; i++ ) {
found[i] = FindKeyIndex( other.args[i].GetKey() );
}
} else {
found = NULL;
}
for ( i = 0; i < n; i++ ) {
if ( found && found[i] != -1 ) {
// first set the new value and then free the old value to allow proper self copying
const idPoolStr *oldValue = args[found[i]].value;
args[found[i]].value = globalValues.CopyString( other.args[i].value );
globalValues.FreeString( oldValue );
} else {
kv.key = globalKeys.CopyString( other.args[i].key );
kv.value = globalValues.CopyString( other.args[i].value );
argHash.Add( argHash.GenerateKey( kv.GetKey(), false ), args.Append( kv ) );
}
}
}
/*
================
idDict::TransferKeyValues
clear existing key/value pairs and transfer key/value pairs from other
================
*/
void idDict::TransferKeyValues( idDict &other ) {
int i, n;
if ( this == &other ) {
return;
}
if ( other.args.Num() && other.args[0].key->GetPool() != &globalKeys ) {
common->FatalError( "idDict::TransferKeyValues: can't transfer values across a DLL boundary" );
return;
}
Clear();
n = other.args.Num();
args.SetNum( n );
for ( i = 0; i < n; i++ ) {
args[i].key = other.args[i].key;
args[i].value = other.args[i].value;
}
argHash = other.argHash;
other.args.Clear();
other.argHash.Free();
}
/*
================
idDict::Parse
================
*/
bool idDict::Parse( idParser &parser ) {
idToken token;
idToken token2;
bool errors;
errors = false;
parser.ExpectTokenString( "{" );
parser.ReadToken( &token );
while( ( token.type != TT_PUNCTUATION ) || ( token != "}" ) ) {
if ( token.type != TT_STRING ) {
parser.Error( "Expected quoted string, but found '%s'", token.c_str() );
}
if ( !parser.ReadToken( &token2 ) ) {
parser.Error( "Unexpected end of file" );
}
if ( FindKey( token ) ) {
parser.Warning( "'%s' already defined", token.c_str() );
errors = true;
}
Set( token, token2 );
if ( !parser.ReadToken( &token ) ) {
parser.Error( "Unexpected end of file" );
}
}
return !errors;
}
/*
================
idDict::SetDefaults
================
*/
void idDict::SetDefaults( const idDict *dict ) {
int i, n;
const idKeyValue *kv, *def;
idKeyValue newkv;
n = dict->args.Num();
for( i = 0; i < n; i++ ) {
def = &dict->args[i];
kv = FindKey( def->GetKey() );
if ( !kv ) {
newkv.key = globalKeys.CopyString( def->key );
newkv.value = globalValues.CopyString( def->value );
argHash.Add( argHash.GenerateKey( newkv.GetKey(), false ), args.Append( newkv ) );
}
}
}
/*
================
idDict::Clear
================
*/
void idDict::Clear() {
int i;
for( i = 0; i < args.Num(); i++ ) {
globalKeys.FreeString( args[i].key );
globalValues.FreeString( args[i].value );
}
args.Clear();
argHash.Free();
}
/*
================
idDict::Print
================
*/
void idDict::Print() const {
int i;
int n;
n = args.Num();
for( i = 0; i < n; i++ ) {
idLib::common->Printf( "%s = %s\n", args[i].GetKey().c_str(), args[i].GetValue().c_str() );
}
}
int KeyCompare( const idKeyValue *a, const idKeyValue *b ) {
return idStr::Cmp( a->GetKey(), b->GetKey() );
}
/*
================
idDict::Checksum
================
*/
int idDict::Checksum() const {
unsigned long ret;
int i, n;
idList<idKeyValue> sorted = args;
sorted.SortWithTemplate( idSort_KeyValue() );
n = sorted.Num();
CRC32_InitChecksum( ret );
for( i = 0; i < n; i++ ) {
CRC32_UpdateChecksum( ret, sorted[i].GetKey().c_str(), sorted[i].GetKey().Length() );
CRC32_UpdateChecksum( ret, sorted[i].GetValue().c_str(), sorted[i].GetValue().Length() );
}
CRC32_FinishChecksum( ret );
return ret;
}
/*
================
idDict::Allocated
================
*/
size_t idDict::Allocated() const {
int i;
size_t size;
size = args.Allocated() + argHash.Allocated();
for( i = 0; i < args.Num(); i++ ) {
size += args[i].Size();
}
return size;
}
/*
================
idDict::Set
================
*/
void idDict::Set( const char *key, const char *value ) {
int i;
idKeyValue kv;
if ( key == NULL || key[0] == '\0' ) {
return;
}
i = FindKeyIndex( key );
if ( i != -1 ) {
// first set the new value and then free the old value to allow proper self copying
const idPoolStr *oldValue = args[i].value;
args[i].value = globalValues.AllocString( value );
globalValues.FreeString( oldValue );
} else {
kv.key = globalKeys.AllocString( key );
kv.value = globalValues.AllocString( value );
argHash.Add( argHash.GenerateKey( kv.GetKey(), false ), args.Append( kv ) );
}
}
/*
================
idDict::GetFloat
================
*/
bool idDict::GetFloat( const char *key, const char *defaultString, float &out ) const {
const char *s;
bool found;
found = GetString( key, defaultString, &s );
out = atof( s );
return found;
}
/*
================
idDict::GetInt
================
*/
bool idDict::GetInt( const char *key, const char *defaultString, int &out ) const {
const char *s;
bool found;
found = GetString( key, defaultString, &s );
out = atoi( s );
return found;
}
/*
================
idDict::GetBool
================
*/
bool idDict::GetBool( const char *key, const char *defaultString, bool &out ) const {
const char *s;
bool found;
found = GetString( key, defaultString, &s );
out = ( atoi( s ) != 0 );
return found;
}
/*
================
idDict::GetFloat
================
*/
bool idDict::GetFloat( const char *key, const float defaultFloat, float &out ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
out = atof( kv->GetValue() );
return true;
} else {
out = defaultFloat;
return false;
}
}
/*
================
idDict::GetInt
================
*/
bool idDict::GetInt( const char *key, const int defaultInt, int &out ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
out = atoi( kv->GetValue() );
return true;
} else {
out = defaultInt;
return false;
}
}
/*
================
idDict::GetBool
================
*/
bool idDict::GetBool( const char *key, const bool defaultBool, bool &out ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
out = ( atoi( kv->GetValue() ) != 0 );
return true;
} else {
out = defaultBool;
return false;
}
}
/*
================
idDict::GetAngles
================
*/
bool idDict::GetAngles( const char *key, const char *defaultString, idAngles &out ) const {
bool found;
const char *s;
if ( !defaultString ) {
defaultString = "0 0 0";
}
found = GetString( key, defaultString, &s );
out.Zero();
sscanf( s, "%f %f %f", &out.pitch, &out.yaw, &out.roll );
return found;
}
/*
================
idDict::GetVector
================
*/
bool idDict::GetVector( const char *key, const char *defaultString, idVec3 &out ) const {
bool found;
const char *s;
if ( !defaultString ) {
defaultString = "0 0 0";
}
found = GetString( key, defaultString, &s );
out.Zero();
sscanf( s, "%f %f %f", &out.x, &out.y, &out.z );
return found;
}
/*
================
idDict::GetVec2
================
*/
bool idDict::GetVec2( const char *key, const char *defaultString, idVec2 &out ) const {
bool found;
const char *s;
if ( !defaultString ) {
defaultString = "0 0";
}
found = GetString( key, defaultString, &s );
out.Zero();
sscanf( s, "%f %f", &out.x, &out.y );
return found;
}
/*
================
idDict::GetVec4
================
*/
bool idDict::GetVec4( const char *key, const char *defaultString, idVec4 &out ) const {
bool found;
const char *s;
if ( !defaultString ) {
defaultString = "0 0 0 0";
}
found = GetString( key, defaultString, &s );
out.Zero();
sscanf( s, "%f %f %f %f", &out.x, &out.y, &out.z, &out.w );
return found;
}
/*
================
idDict::GetMatrix
================
*/
bool idDict::GetMatrix( const char *key, const char *defaultString, idMat3 &out ) const {
const char *s;
bool found;
if ( !defaultString ) {
defaultString = "1 0 0 0 1 0 0 0 1";
}
found = GetString( key, defaultString, &s );
out.Identity(); // sccanf has a bug in it on Mac OS 9. Sigh.
sscanf( s, "%f %f %f %f %f %f %f %f %f", &out[0].x, &out[0].y, &out[0].z, &out[1].x, &out[1].y, &out[1].z, &out[2].x, &out[2].y, &out[2].z );
return found;
}
/*
================
WriteString
================
*/
static void WriteString( const char *s, idFile *f ) {
int len = strlen( s );
if ( len >= MAX_STRING_CHARS-1 ) {
idLib::common->Error( "idDict::WriteToFileHandle: bad string" );
}
f->Write( s, strlen(s) + 1 );
}
/*
================
idDict::FindKey
================
*/
const idKeyValue *idDict::FindKey( const char *key ) const {
int i, hash;
if ( key == NULL || key[0] == '\0' ) {
idLib::common->DWarning( "idDict::FindKey: empty key" );
return NULL;
}
hash = argHash.GenerateKey( key, false );
for ( i = argHash.First( hash ); i != -1; i = argHash.Next( i ) ) {
if ( args[i].GetKey().Icmp( key ) == 0 ) {
return &args[i];
}
}
return NULL;
}
/*
================
idDict::FindKeyIndex
================
*/
int idDict::FindKeyIndex( const char *key ) const {
if ( key == NULL || key[0] == '\0' ) {
idLib::common->DWarning( "idDict::FindKeyIndex: empty key" );
return 0;
}
int hash = argHash.GenerateKey( key, false );
for ( int i = argHash.First( hash ); i != -1; i = argHash.Next( i ) ) {
if ( args[i].GetKey().Icmp( key ) == 0 ) {
return i;
}
}
return -1;
}
/*
================
idDict::Delete
================
*/
void idDict::Delete( const char *key ) {
int hash, i;
hash = argHash.GenerateKey( key, false );
for ( i = argHash.First( hash ); i != -1; i = argHash.Next( i ) ) {
if ( args[i].GetKey().Icmp( key ) == 0 ) {
globalKeys.FreeString( args[i].key );
globalValues.FreeString( args[i].value );
args.RemoveIndex( i );
argHash.RemoveIndex( hash, i );
break;
}
}
#if 0
// make sure all keys can still be found in the hash index
for ( i = 0; i < args.Num(); i++ ) {
assert( FindKey( args[i].GetKey() ) != NULL );
}
#endif
}
/*
================
idDict::MatchPrefix
================
*/
const idKeyValue *idDict::MatchPrefix( const char *prefix, const idKeyValue *lastMatch ) const {
int i;
int len;
int start;
assert( prefix );
len = strlen( prefix );
start = -1;
if ( lastMatch ) {
start = args.FindIndex( *lastMatch );
assert( start >= 0 );
if ( start < 1 ) {
start = 0;
}
}
for( i = start + 1; i < args.Num(); i++ ) {
if ( !args[i].GetKey().Icmpn( prefix, len ) ) {
return &args[i];
}
}
return NULL;
}
/*
================
idDict::RandomPrefix
================
*/
const char *idDict::RandomPrefix( const char *prefix, idRandom &random ) const {
int count;
const int MAX_RANDOM_KEYS = 2048;
const char *list[MAX_RANDOM_KEYS];
const idKeyValue *kv;
list[0] = "";
for ( count = 0, kv = MatchPrefix( prefix ); kv != NULL && count < MAX_RANDOM_KEYS; kv = MatchPrefix( prefix, kv ) ) {
list[count++] = kv->GetValue().c_str();
}
return list[random.RandomInt( count )];
}
/*
================
idDict::WriteToFileHandle
================
*/
void idDict::WriteToFileHandle( idFile *f ) const {
int c = LittleLong( args.Num() );
f->Write( &c, sizeof( c ) );
for ( int i = 0; i < args.Num(); i++ ) { // don't loop on the swapped count use the original
WriteString( args[i].GetKey().c_str(), f );
WriteString( args[i].GetValue().c_str(), f );
}
}
/*
================
ReadString
================
*/
static idStr ReadString( idFile *f ) {
char str[MAX_STRING_CHARS];
int len;
for ( len = 0; len < MAX_STRING_CHARS; len++ ) {
f->Read( (void *)&str[len], 1 );
if ( str[len] == 0 ) {
break;
}
}
if ( len == MAX_STRING_CHARS ) {
idLib::common->Error( "idDict::ReadFromFileHandle: bad string" );
}
return idStr( str );
}
/*
================
idDict::ReadFromFileHandle
================
*/
void idDict::ReadFromFileHandle( idFile *f ) {
int c;
idStr key, val;
Clear();
f->Read( &c, sizeof( c ) );
c = LittleLong( c );
for ( int i = 0; i < c; i++ ) {
key = ReadString( f );
val = ReadString( f );
Set( key, val );
}
}
/*
========================
idDict::Serialize
========================
*/
void idDict::Serialize( idSerializer & ser ) {
if ( ser.IsReading() ) {
Clear();
}
int num = args.Num();
ser.SerializePacked( num );
for ( int i = 0; i < num; i++ ) {
idStr key;
idStr val;
if ( ser.IsWriting() ) {
key = args[i].GetKey();
val = args[i].GetValue();
}
ser.SerializeString( key );
ser.SerializeString( val );
if ( ser.IsReading() ) {
Set( key.c_str(), val.c_str() );
}
}
}
/*
================
idDict::WriteToIniFile
================
*/
void idDict::WriteToIniFile( idFile * f ) const {
// make a copy so we don't affect the checksum of the original dict
idList< idKeyValue > sortedArgs( args );
sortedArgs.SortWithTemplate( idSort_KeyValue() );
idList< idStr > prefixList;
idTempArray< int > prefixIndex( sortedArgs.Num() ); // for each keyValue in the args, this is an index into which prefix it uses.
// 0 means no prefix, otherwise, it's an index + (-1) into prefixList
// we do this so we can print all the non-prefix based pairs first
idStr prevPrefix = "";
idStr skipFirstLine = "";
// Scan for all the prefixes
for ( int i = 0; i < sortedArgs.Num(); i++ ) {
const idKeyValue * kv = &sortedArgs[i];
int slashPosition = kv->GetKey().Last( '/' );
if ( slashPosition != idStr::INVALID_POSITION ) {
idStr prefix = kv->GetKey().Mid( 0, slashPosition );
if ( prefix != prevPrefix ) {
prevPrefix = prefix;
prefixList.Append( prefix );
}
prefixIndex[i] = prefixList.Num();
} else {
prefixIndex[i] = 0;
// output all the prefix-less first
idStr str = va( "%s=%s\n", kv->GetKey().c_str(), idStr::CStyleQuote( kv->GetValue() ) );
f->Write( (void *)str.c_str(), str.Length() );
skipFirstLine = "\n";
}
}
int prevPrefixIndex = 0;
int prefixLength = 0;
// output all the rest without their prefix
for ( int i = 0; i < sortedArgs.Num(); i++ ) {
if ( prefixIndex[i] == 0 ) {
continue;
}
if ( prefixIndex[i] != prevPrefixIndex ) {
prevPrefixIndex = prefixIndex[i];
prefixLength = prefixList[prevPrefixIndex - 1].Length() + 1; // to skip past the '/' too
// output prefix
idStr str = va( "%s[%s]\n", skipFirstLine.c_str(), prefixList[prevPrefixIndex - 1].c_str() );
f->Write( (void *)str.c_str(), str.Length() );
}
const idKeyValue * kv = &sortedArgs[i];
idStr str = va( "%s=%s\n", kv->GetKey().c_str() + prefixLength, idStr::CStyleQuote( kv->GetValue() ) );
f->Write( (void *)str.c_str(), str.Length() );
}
}
/*
================
idDict::ReadFromIniFile
================
*/
bool idDict::ReadFromIniFile( idFile * f ) {
int length = f->Length();
idTempArray< char > buffer( length );
if ( (int)f->Read( buffer.Ptr(), length ) != length ) {
return false;
}
buffer[length-1] = NULL; // Since the .ini files are not null terminated, make sure we mark where the end of the .ini file is in our read buffer
idLexer parser( LEXFL_NOFATALERRORS | LEXFL_ALLOWPATHNAMES /*| LEXFL_ONLYSTRINGS */);
idStr name = f->GetName();
name.Append( " dictionary INI reader" );
if ( !parser.LoadMemory( ( const char* )buffer.Ptr(), length, name.c_str() ) ) {
return false;
}
idToken token;
idToken token2;
idStr prefix = "";
idStr valueStr;
bool success = true;
Clear();
const punctuation_t ini_punctuations[] = {
{ "[", P_SQBRACKETOPEN },
{ "]", P_SQBRACKETCLOSE },
{ "=", P_ASSIGN },
{ NULL, 0 }
};
parser.SetPunctuations( ini_punctuations );
while ( success && !parser.EndOfFile() ) {
if ( parser.PeekTokenType( TT_PUNCTUATION, P_SQBRACKETOPEN, &token ) ) {
success = success && parser.ExpectTokenType( TT_PUNCTUATION, P_SQBRACKETOPEN, &token );
success = success && parser.ReadToken( &token );
prefix = token.c_str();
prefix.Append( '/' );
success = success && parser.ExpectTokenType( TT_PUNCTUATION, P_SQBRACKETCLOSE, &token );
}
if ( !parser.PeekTokenType( TT_NAME, 0, &token ) ) {
// end of file most likely
break;
}
success = success && parser.ExpectTokenType( TT_NAME, 0, &token );
success = success && parser.ExpectTokenType( TT_PUNCTUATION, P_ASSIGN, &token2 );
success = success && ( parser.ParseRestOfLine( valueStr ) != NULL );
valueStr = idStr::CStyleUnQuote( valueStr );
idStr key = va( "%s%s", prefix.c_str(), token.c_str() );
if ( FindKey( key.c_str() ) ) {
parser.Warning( "'%s' already defined", key.c_str() );
}
Set( key.c_str(), valueStr.c_str() );
}
return success;
}
CONSOLE_COMMAND( TestDictIniFile, "Tests the writing/reading of various items in a dict to/from an ini file", 0 ) {
// Write to the file
idFile * file = fileSystem->OpenFileWrite( "idDict_ini_test.ini" );
if ( file == NULL ) {
idLib::Printf( "[^1FAILED^0] Couldn't open file for writing.\n" );
return;
}
idDict vars;
vars.SetInt( "section1/section3/a", -1 );
vars.SetInt( "section1/section3/b", 0 );
vars.SetInt( "section1/section3/c", 3 );
vars.SetFloat( "section2/d", 4.0f );
vars.SetFloat( "section2/e", -5.0f );
vars.SetBool( "section2/f", true );
vars.SetBool( "section1/g", false );
vars.Set( "section1/h", "test1" );
vars.Set( "i", "1234" );
vars.SetInt( "j", 9 );
vars.WriteToIniFile( file );
delete file;
// Read from the file
file = fileSystem->OpenFileRead( "idDict_ini_test.ini" );
if ( file == NULL ) {
idLib::Printf( "[^1FAILED^0] Couldn't open file for reading.\n" );
}
idDict readVars;
readVars.ReadFromIniFile( file );
delete file;
if ( vars.Checksum() != readVars.Checksum() ) {
idLib::Printf( "[^1FAILED^0] Dictionaries do not match.\n" );
} else {
idLib::Printf( "[^2PASSED^0] Dictionaries match.\n" );
}
// Output results
for ( int i = 0; i < readVars.GetNumKeyVals(); i++ ) {
const idKeyValue * kv = readVars.GetKeyVal( i );
idLib::Printf( "%s=%s\n", kv->GetKey().c_str(), kv->GetValue().c_str() );
}
}
/*
================
idDict::Init
================
*/
void idDict::Init() {
globalKeys.SetCaseSensitive( false );
globalValues.SetCaseSensitive( true );
}
/*
================
idDict::Shutdown
================
*/
void idDict::Shutdown() {
globalKeys.Clear();
globalValues.Clear();
}
/*
================
idDict::ShowMemoryUsage_f
================
*/
void idDict::ShowMemoryUsage_f( const idCmdArgs &args ) {
idLib::common->Printf( "%5d KB in %d keys\n", globalKeys.Size() >> 10, globalKeys.Num() );
idLib::common->Printf( "%5d KB in %d values\n", globalValues.Size() >> 10, globalValues.Num() );
}
/*
================
idDict::ListKeys_f
================
*/
void idDict::ListKeys_f( const idCmdArgs &args ) {
idLib::Printf( "Not implemented due to sort impl issues.\n" );
//int i;
//idList<const idPoolStr *> keyStrings;
//for ( i = 0; i < globalKeys.Num(); i++ ) {
// keyStrings.Append( globalKeys[i] );
//}
//keyStrings.SortWithTemplate( idSort_PoolStrPtr() );
//for ( i = 0; i < keyStrings.Num(); i++ ) {
// idLib::common->Printf( "%s\n", keyStrings[i]->c_str() );
//}
//idLib::common->Printf( "%5d keys\n", keyStrings.Num() );
}
/*
================
idDict::ListValues_f
================
*/
void idDict::ListValues_f( const idCmdArgs &args ) {
idLib::Printf( "Not implemented due to sort impl issues.\n" );
//int i;
//idList<const idPoolStr *> valueStrings;
//for ( i = 0; i < globalValues.Num(); i++ ) {
// valueStrings.Append( globalValues[i] );
//}
//valueStrings.SortWithTemplate( idSort_PoolStrPtr() );
//for ( i = 0; i < valueStrings.Num(); i++ ) {
// idLib::common->Printf( "%s\n", valueStrings[i]->c_str() );
//}
//idLib::common->Printf( "%5d values\n", valueStrings.Num() );
}

348
neo/idlib/Dict.h Normal file
View File

@@ -0,0 +1,348 @@
/*
===========================================================================
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 __DICT_H__
#define __DICT_H__
class idSerializer;
/*
===============================================================================
Key/value dictionary
This is a dictionary class that tracks an arbitrary number of key / value
pair combinations. It is used for map entity spawning, GUI state management,
and other things.
Keys are compared case-insensitive.
Does not allocate memory until the first key/value pair is added.
===============================================================================
*/
class idKeyValue {
friend class idDict;
public:
const idStr & GetKey() const { return *key; }
const idStr & GetValue() const { return *value; }
size_t Allocated() const { return key->Allocated() + value->Allocated(); }
size_t Size() const { return sizeof( *this ) + key->Size() + value->Size(); }
bool operator==( const idKeyValue &kv ) const { return ( key == kv.key && value == kv.value ); }
private:
const idPoolStr * key;
const idPoolStr * value;
};
/*
================================================
idSort_KeyValue
================================================
*/
class idSort_KeyValue : public idSort_Quick< idKeyValue, idSort_KeyValue > {
public:
int Compare( const idKeyValue & a, const idKeyValue & b ) const { return a.GetKey().Icmp( b.GetKey() ); }
};
class idDict {
public:
idDict();
idDict( const idDict &other ); // allow declaration with assignment
~idDict();
// set the granularity for the index
void SetGranularity( int granularity );
// set hash size
void SetHashSize( int hashSize );
// clear existing key/value pairs and copy all key/value pairs from other
idDict & operator=( const idDict &other );
// copy from other while leaving existing key/value pairs in place
void Copy( const idDict &other );
// clear existing key/value pairs and transfer key/value pairs from other
void TransferKeyValues( idDict &other );
// parse dict from parser
bool Parse( idParser &parser );
// copy key/value pairs from other dict not present in this dict
void SetDefaults( const idDict *dict );
// clear dict freeing up memory
void Clear();
// print the dict
void Print() const;
size_t Allocated() const;
size_t Size() const { return sizeof( *this ) + Allocated(); }
void Set( const char *key, const char *value );
void SetFloat( const char *key, float val );
void SetInt( const char *key, int val );
void SetBool( const char *key, bool val );
void SetVector( const char *key, const idVec3 &val );
void SetVec2( const char *key, const idVec2 &val );
void SetVec4( const char *key, const idVec4 &val );
void SetAngles( const char *key, const idAngles &val );
void SetMatrix( const char *key, const idMat3 &val );
// these return default values of 0.0, 0 and false
const char * GetString( const char *key, const char *defaultString = "" ) const;
float GetFloat( const char *key, const char *defaultString ) const;
int GetInt( const char *key, const char *defaultString ) const;
bool GetBool( const char *key, const char *defaultString ) const;
float GetFloat( const char *key, const float defaultFloat = 0.0f ) const;
int GetInt( const char *key, const int defaultInt = 0 ) const;
bool GetBool( const char *key, const bool defaultBool = false ) const;
idVec3 GetVector( const char *key, const char *defaultString = NULL ) const;
idVec2 GetVec2( const char *key, const char *defaultString = NULL ) const;
idVec4 GetVec4( const char *key, const char *defaultString = NULL ) const;
idAngles GetAngles( const char *key, const char *defaultString = NULL ) const;
idMat3 GetMatrix( const char *key, const char *defaultString = NULL ) const;
bool GetString( const char *key, const char *defaultString, const char **out ) const;
bool GetString( const char *key, const char *defaultString, idStr &out ) const;
bool GetFloat( const char *key, const char *defaultString, float &out ) const;
bool GetInt( const char *key, const char *defaultString, int &out ) const;
bool GetBool( const char *key, const char *defaultString, bool &out ) const;
bool GetFloat( const char *key, const float defaultFloat, float &out ) const;
bool GetInt( const char *key, const int defaultInt, int &out ) const;
bool GetBool( const char *key, const bool defaultBool, bool &out ) const;
bool GetVector( const char *key, const char *defaultString, idVec3 &out ) const;
bool GetVec2( const char *key, const char *defaultString, idVec2 &out ) const;
bool GetVec4( const char *key, const char *defaultString, idVec4 &out ) const;
bool GetAngles( const char *key, const char *defaultString, idAngles &out ) const;
bool GetMatrix( const char *key, const char *defaultString, idMat3 &out ) const;
int GetNumKeyVals() const;
const idKeyValue * GetKeyVal( int index ) const;
// returns the key/value pair with the given key
// returns NULL if the key/value pair does not exist
const idKeyValue * FindKey( const char *key ) const;
// returns the index to the key/value pair with the given key
// returns -1 if the key/value pair does not exist
int FindKeyIndex( const char *key ) const;
// delete the key/value pair with the given key
void Delete( const char *key );
// finds the next key/value pair with the given key prefix.
// lastMatch can be used to do additional searches past the first match.
const idKeyValue * MatchPrefix( const char *prefix, const idKeyValue *lastMatch = NULL ) const;
// randomly chooses one of the key/value pairs with the given key prefix and returns it's value
const char * RandomPrefix( const char *prefix, idRandom &random ) const;
void WriteToFileHandle( idFile *f ) const;
void ReadFromFileHandle( idFile *f );
void WriteToIniFile( idFile * f ) const;
bool ReadFromIniFile( idFile * f );
void Serialize( idSerializer & ser );
// returns a unique checksum for this dictionary's content
int Checksum() const;
static void Init();
static void Shutdown();
static void ShowMemoryUsage_f( const idCmdArgs &args );
static void ListKeys_f( const idCmdArgs &args );
static void ListValues_f( const idCmdArgs &args );
private:
idList<idKeyValue> args;
idHashIndex argHash;
static idStrPool globalKeys;
static idStrPool globalValues;
};
ID_INLINE idDict::idDict() {
args.SetGranularity( 16 );
argHash.SetGranularity( 16 );
argHash.Clear( 128, 16 );
}
ID_INLINE idDict::idDict( const idDict &other ) {
*this = other;
}
ID_INLINE idDict::~idDict() {
Clear();
}
ID_INLINE void idDict::SetGranularity( int granularity ) {
args.SetGranularity( granularity );
argHash.SetGranularity( granularity );
}
ID_INLINE void idDict::SetHashSize( int hashSize ) {
if ( args.Num() == 0 ) {
argHash.Clear( hashSize, 16 );
}
}
ID_INLINE void idDict::SetFloat( const char *key, float val ) {
Set( key, va( "%f", val ) );
}
ID_INLINE void idDict::SetInt( const char *key, int val ) {
Set( key, va( "%i", val ) );
}
ID_INLINE void idDict::SetBool( const char *key, bool val ) {
Set( key, va( "%i", val ) );
}
ID_INLINE void idDict::SetVector( const char *key, const idVec3 &val ) {
Set( key, val.ToString() );
}
ID_INLINE void idDict::SetVec4( const char *key, const idVec4 &val ) {
Set( key, val.ToString() );
}
ID_INLINE void idDict::SetVec2( const char *key, const idVec2 &val ) {
Set( key, val.ToString() );
}
ID_INLINE void idDict::SetAngles( const char *key, const idAngles &val ) {
Set( key, val.ToString() );
}
ID_INLINE void idDict::SetMatrix( const char *key, const idMat3 &val ) {
Set( key, val.ToString() );
}
ID_INLINE bool idDict::GetString( const char *key, const char *defaultString, const char **out ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
*out = kv->GetValue();
return true;
}
*out = defaultString;
return false;
}
ID_INLINE bool idDict::GetString( const char *key, const char *defaultString, idStr &out ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
out = kv->GetValue();
return true;
}
out = defaultString;
return false;
}
ID_INLINE const char *idDict::GetString( const char *key, const char *defaultString ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
return kv->GetValue();
}
return defaultString;
}
ID_INLINE float idDict::GetFloat( const char *key, const char *defaultString ) const {
return atof( GetString( key, defaultString ) );
}
ID_INLINE int idDict::GetInt( const char *key, const char *defaultString ) const {
return atoi( GetString( key, defaultString ) );
}
ID_INLINE bool idDict::GetBool( const char *key, const char *defaultString ) const {
return ( atoi( GetString( key, defaultString ) ) != 0 );
}
ID_INLINE float idDict::GetFloat( const char *key, const float defaultFloat ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
return atof( kv->GetValue() );
}
return defaultFloat;
}
ID_INLINE int idDict::GetInt( const char *key, int defaultInt ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
return atoi( kv->GetValue() );
}
return defaultInt;
}
ID_INLINE bool idDict::GetBool( const char *key, const bool defaultBool ) const {
const idKeyValue *kv = FindKey( key );
if ( kv ) {
return atoi( kv->GetValue() ) != 0;
}
return defaultBool;
}
ID_INLINE idVec3 idDict::GetVector( const char *key, const char *defaultString ) const {
idVec3 out;
GetVector( key, defaultString, out );
return out;
}
ID_INLINE idVec2 idDict::GetVec2( const char *key, const char *defaultString ) const {
idVec2 out;
GetVec2( key, defaultString, out );
return out;
}
ID_INLINE idVec4 idDict::GetVec4( const char *key, const char *defaultString ) const {
idVec4 out;
GetVec4( key, defaultString, out );
return out;
}
ID_INLINE idAngles idDict::GetAngles( const char *key, const char *defaultString ) const {
idAngles out;
GetAngles( key, defaultString, out );
return out;
}
ID_INLINE idMat3 idDict::GetMatrix( const char *key, const char *defaultString ) const {
idMat3 out;
GetMatrix( key, defaultString, out );
return out;
}
ID_INLINE int idDict::GetNumKeyVals() const {
return args.Num();
}
ID_INLINE const idKeyValue *idDict::GetKeyVal( int index ) const {
if ( index >= 0 && index < args.Num() ) {
return &args[ index ];
}
return NULL;
}
#endif /* !__DICT_H__ */

86
neo/idlib/Heap.cpp Normal file
View File

@@ -0,0 +1,86 @@
/*
===========================================================================
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 "../idlib/precompiled.h"
//===============================================================
//
// memory allocation all in one place
//
//===============================================================
#undef new
/*
==================
Mem_Alloc16
==================
*/
void * Mem_Alloc16( const int size, const memTag_t tag ) {
if ( !size ) {
return NULL;
}
const int paddedSize = ( size + 15 ) & ~15;
return _aligned_malloc( paddedSize, 16 );
}
/*
==================
Mem_Free16
==================
*/
void Mem_Free16( void *ptr ) {
if ( ptr == NULL ) {
return;
}
_aligned_free( ptr );
}
/*
==================
Mem_ClearedAlloc
==================
*/
void * Mem_ClearedAlloc( const int size, const memTag_t tag ) {
void * mem = Mem_Alloc( size, tag );
SIMDProcessor->Memset( mem, 0, size );
return mem;
}
/*
==================
Mem_CopyString
==================
*/
char *Mem_CopyString( const char *in ) {
char * out = (char *)Mem_Alloc( strlen(in) + 1, TAG_STRING );
strcpy( out, in );
return out;
}

1079
neo/idlib/Heap.h Normal file

File diff suppressed because it is too large Load Diff

600
neo/idlib/LangDict.cpp Normal file
View File

@@ -0,0 +1,600 @@
/*
===========================================================================
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"
// This is the default language dict that the entire system uses, but you can instantiate your own idLangDict classes to manipulate a language dictionary in a tool
idLangDict idLocalization::languageDict;
idCVar lang_maskLocalizedStrings( "lang_maskLocalizedStrings", "0", CVAR_BOOL, "Masks all localized strings to help debugging. When set will replace strings with an equal length of W's and ending in an X. Note: The masking occurs at string table load time." );
/*
========================
idLocalization::ClearDictionary
========================
*/
void idLocalization::ClearDictionary() {
languageDict.Clear();
}
/*
========================
idLocalization::LoadDictionary
========================
*/
bool idLocalization::LoadDictionary( const byte * data, int dataLen, const char * fileName ) {
return languageDict.Load( data, dataLen, fileName );
}
/*
========================
idLocalization::GetString
========================
*/
const char * idLocalization::GetString( const char * inString ) {
return languageDict.GetString( inString );
}
/*
========================
idLocalization::FindString
========================
*/
const char * idLocalization::FindString( const char * inString ) {
return languageDict.FindString( inString );
}
/*
========================
idLocalization::VerifyUTF8
========================
*/
utf8Encoding_t idLocalization::VerifyUTF8( const uint8 * buffer, const int bufferLen, const char * name ) {
utf8Encoding_t encoding;
idStr::IsValidUTF8( buffer, bufferLen, encoding );
if ( encoding == UTF8_INVALID ) {
idLib::FatalError( "Language file %s is not valid UTF-8 or plain ASCII.", name );
} else if ( encoding == UTF8_INVALID_BOM ) {
idLib::FatalError( "Language file %s is marked as UTF-8 but has invalid encoding.", name );
} else if ( encoding == UTF8_ENCODED_NO_BOM ) {
idLib::FatalError( "Language file %s has no byte order marker. Fix this or roll back to a version that has the marker.", name );
} else if ( encoding != UTF8_ENCODED_BOM && encoding != UTF8_PURE_ASCII ) {
idLib::FatalError( "Language file %s has unknown utf8Encoding_t.", name );
}
return encoding;
}
// string entries can refer to other string entries,
// recursing up to this many times before we decided someone did something stupid
const char * idLangDict::KEY_PREFIX = "#str_"; // all keys should be prefixed with this for redirection to work
const int idLangDict::KEY_PREFIX_LEN = idStr::Length( KEY_PREFIX );
/*
========================
idLangDict::idLangDict
========================
*/
idLangDict::idLangDict() : keyIndex( 4096, 4096 ) {
}
/*
========================
idLangDict::~idLangDict
========================
*/
idLangDict::~idLangDict() {
Clear();
}
/*
========================
idLangDict::Clear
========================
*/
void idLangDict::Clear() {
//mem.PushHeap();
for ( int i = 0; i < keyVals.Num(); i++ ) {
if ( keyVals[i].value == NULL ) {
continue;
}
blockAlloc.Free( keyVals[i].value );
keyVals[i].value = NULL;
}
//mem.PopHeap();
}
/*
========================
idLangDict::Load
========================
*/
bool idLangDict::Load( const byte * buffer, const int bufferLen, const char *name ) {
if ( buffer == NULL || bufferLen <= 0 ) {
// let whoever called us deal with the failure (so sys_lang can be reset)
return false;
}
idLib::Printf( "Reading %s", name );
bool utf8 = false;
// in all but retail builds, ensure that the byte-order mark is NOT MISSING so that
// we can avoid debugging UTF-8 code
#ifndef ID_RETAIL
utf8Encoding_t encoding = idLocalization::VerifyUTF8( buffer, bufferLen, name );
if ( encoding == UTF8_ENCODED_BOM ) {
utf8 = true;
} else if ( encoding == UTF8_PURE_ASCII ) {
utf8 = false;
} else {
assert( false ); // this should have been handled in VerifyUTF8 with a FatalError
return false;
}
#else
// in release we just check the BOM so we're not scanning the lang file twice on startup
if ( bufferLen > 3 && buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF ) {
utf8 = true;
}
#endif
if ( utf8 ) {
idLib::Printf( " as UTF-8\n" );
} else {
idLib::Printf( " as ASCII\n" );
}
idStr tempKey;
idStr tempVal;
int line = 0;
int numStrings = 0;
int i = 0;
while ( i < bufferLen ) {
uint32 c = buffer[i++];
if ( c == '/' ) { // comment, read until new line
while ( i < bufferLen ) {
c = buffer[i++];
if ( c == '\n' ) {
line++;
break;
}
}
} else if ( c == '}' ) {
break;
} else if ( c == '\n' ) {
line++;
} else if ( c == '\"' ) {
int keyStart = i;
int keyEnd = -1;
while ( i < bufferLen ) {
c = buffer[i++];
if ( c == '\"' ) {
keyEnd = i - 1;
break;
}
}
if ( keyEnd < keyStart ) {
idLib::FatalError( "%s File ended while reading key at line %d", name, line );
}
tempKey.CopyRange( (char *)buffer, keyStart, keyEnd );
int valStart = -1;
while ( i < bufferLen ) {
c = buffer[i++];
if ( c == '\"' ) {
valStart = i;
break;
}
}
if ( valStart < 0 ) {
idLib::FatalError( "%s File ended while reading value at line %d", name, line );
}
int valEnd = -1;
tempVal.CapLength( 0 );
while ( i < bufferLen ) {
c = utf8 ? idStr::UTF8Char( buffer, i ) : buffer[i++];
if ( !utf8 && c >= 0x80 ) {
// this is a serious error and we must check this to avoid accidentally shipping a file where someone squased UTF-8 encodings
idLib::FatalError( "Language file %s is supposed to be plain ASCII, but has byte values > 127!", name );
}
if ( c == '\"' ) {
valEnd = i - 1;
continue;
}
if ( c == '\n' ) {
line++;
break;
}
if ( c == '\r' ) {
continue;
}
if ( c == '\\' ) {
c = utf8 ? idStr::UTF8Char( buffer, i ) : buffer[i++];
if ( c == 'n' ) {
c = '\n';
} else if ( c == 't' ) {
c = '\t';
} else if ( c == '\"' ) {
c = '\"';
} else if ( c == '\\' ) {
c = '\\';
} else {
idLib::Warning( "Unknown escape sequence %x at line %d", c, line );
}
}
tempVal.AppendUTF8Char( c );
}
if ( valEnd < valStart ) {
idLib::FatalError( "%s File ended while reading value at line %d", name, line );
}
if ( lang_maskLocalizedStrings.GetBool() && tempVal.Length() > 0 && tempKey.Find( "#font_" ) == -1 ) {
int len = tempVal.Length();
if ( len > 0 ) {
tempVal.Fill( 'W', len - 1 );
} else {
tempVal.Empty();
}
tempVal.Append( 'X' );
}
AddKeyVal( tempKey, tempVal );
numStrings++;
}
}
idLib::Printf( "%i strings read\n", numStrings );
// get rid of any waste due to geometric list growth
//mem.PushHeap();
keyVals.Condense();
//mem.PopHeap();
return true;
}
/*
========================
idLangDict::Save
========================
*/
bool idLangDict::Save( const char * fileName ) {
idFile * outFile = fileSystem->OpenFileWrite( fileName );
if ( outFile == NULL ) {
idLib::Warning( "Error saving: %s", fileName );
return false;
}
byte bof[3] = { 0xEF, 0xBB, 0xBF };
outFile->Write( bof, 3 );
outFile->WriteFloatString( "// string table\n//\n\n{\n" );
for ( int j = 0; j < keyVals.Num(); j++ ) {
const idLangKeyValue & kvp = keyVals[j];
if ( kvp.value == NULL ) {
continue;
}
outFile->WriteFloatString( "\t\"%s\"\t\"", kvp.key );
for ( int k = 0; kvp.value[k] != 0; k++ ) {
char ch = kvp.value[k];
if ( ch == '\t' ) {
outFile->Write( "\\t", 2 );
} else if ( ch == '\n' || ch == '\r' ) {
outFile->Write( "\\n", 2 );
} else if ( ch == '"' ) {
outFile->Write( "\\\"", 2 );
} else if ( ch == '\\' ) {
outFile->Write( "\\\\", 2 );
} else {
outFile->Write( &ch, 1 );
}
}
outFile->WriteFloatString( "\"\n" );
}
outFile->WriteFloatString( "\n}\n" );
delete outFile;
return true;
}
/*
========================
idLangDict::GetString
========================
*/
const char * idLangDict::GetString( const char * str ) const {
const char * localized = FindString( str );
if ( localized == NULL ) {
return str;
}
return localized;
}
/*
========================
idLangDict::FindStringIndex
========================
*/
int idLangDict::FindStringIndex( const char * str ) const {
if ( str == NULL ) {
return -1;
}
int hash = idStr::IHash( str );
for ( int i = keyIndex.GetFirst( hash ); i >= 0; i = keyIndex.GetNext( i ) ) {
if ( idStr::Icmp( str, keyVals[i].key ) == 0 ) {
return i;
}
}
return -1;
}
/*
========================
idLangDict::FindString_r
========================
*/
const char * idLangDict::FindString_r( const char * str, int & depth ) const {
depth++;
if ( depth > MAX_REDIRECTION_DEPTH ) {
// This isn't an error because we assume the error will be obvious somewhere in a GUI or something,
// and the whole point of tracking the depth is to avoid a crash.
idLib::Warning( "String '%s', indirection depth > %d", str, MAX_REDIRECTION_DEPTH );
return NULL;
}
if ( str == NULL || str[0] == '\0' ) {
return NULL;
}
int index = FindStringIndex( str );
if ( index < 0 ) {
return NULL;
}
const char * value = keyVals[index].value;
if ( value == NULL ) {
return NULL;
}
if ( IsStringId( value ) ) {
// this string is re-directed to another entry
return FindString_r( value, depth );
}
return value;
}
/*
========================
idLangDict::FindString
========================
*/
const char * idLangDict::FindString( const char * str ) const {
int depth = 0;
return FindString_r( str, depth );
}
/*
========================
idLangDict::DeleteString
========================
*/
bool idLangDict::DeleteString( const char * key ) {
return DeleteString( FindStringIndex( key ) );
}
/*
========================
idLangDict::DeleteString
========================
*/
bool idLangDict::DeleteString( const int idx ) {
if ( idx < 0 || idx >= keyVals.Num() ) {
return false;
}
//mem.PushHeap();
blockAlloc.Free( keyVals[idx].value );
keyVals[idx].value = NULL;
//mem.PopHeap();
return true;
}
/*
========================
idLangDict::RenameStringKey
========================
*/
bool idLangDict::RenameStringKey( const char * oldKey, const char * newKey ) {
int index = FindStringIndex( oldKey );
if ( index < 0 ) {
return false;
}
//mem.PushHeap();
blockAlloc.Free( keyVals[index].key );
int newKeyLen = idStr::Length( newKey );
keyVals[index].key = blockAlloc.Alloc( newKeyLen + 1 );
idStr::Copynz( keyVals[index].key, newKey, newKeyLen + 1 );
int oldHash = idStr::IHash( oldKey );
int newHash = idStr::IHash( newKey );
if ( oldHash != newHash ) {
keyIndex.Remove( oldHash, index );
keyIndex.Add( newHash, index );
}
//mem.PopHeap();
return true;
}
/*
========================
idLangDict::SetString
========================
*/
bool idLangDict::SetString( const char * key, const char * val ) {
int index = FindStringIndex( key );
if ( index < 0 ) {
return false;
}
//mem.PushHeap();
if ( keyVals[index].value != NULL ) {
blockAlloc.Free( keyVals[index].value );
}
int valLen = idStr::Length( val );
keyVals[index].value = blockAlloc.Alloc( valLen + 1 );
idStr::Copynz( keyVals[index].value, val, valLen + 1 );
//mem.PopHeap();
return true;
}
/*
========================
idLangDict::AddKeyVal
========================
*/
void idLangDict::AddKeyVal( const char * key, const char * val ) {
if ( SetString( key, val ) ) {
return;
}
//mem.PushHeap();
int keyLen = idStr::Length( key );
char * k = blockAlloc.Alloc( keyLen + 1 );
idStr::Copynz( k, key, keyLen + 1 );
char * v = NULL;
if ( val != NULL ) {
int valLen = idStr::Length( val );
v = blockAlloc.Alloc( valLen + 1 );
idStr::Copynz( v, val, valLen + 1 );
}
int index = keyVals.Append( idLangKeyValue( k, v ) );
int hash = idStr::IHash( key );
keyIndex.Add( hash, index );
//mem.PopHeap();
}
/*
========================
idLangDict::AddString
========================
*/
const char * idLangDict::AddString( const char * val ) {
int i = Sys_Milliseconds();
idStr key;
sprintf( key, "#str_%06d", ( i++ % 1000000 ) );
while ( FindStringIndex( key ) > 0 ) {
sprintf( key, "#str_%06d", ( i++ % 1000000 ) );
}
AddKeyVal( key, val );
int index = FindStringIndex( key );
return keyVals[index].key;
}
/*
========================
idLangDict::GetNumKeyVals
========================
*/
int idLangDict::GetNumKeyVals() const {
return keyVals.Num();
}
/*
========================
idLangDict::GetKeyVal
========================
*/
const idLangKeyValue * idLangDict::GetKeyVal( int i ) const {
return &keyVals[i];
}
/*
========================
idLangDict::IsStringId
========================
*/
bool idLangDict::IsStringId( const char * str ) {
return idStr::Icmpn( str, KEY_PREFIX, KEY_PREFIX_LEN ) == 0;
}
/*
========================
idLangDict::GetLocalizedString
========================
*/
const char * idLangDict::GetLocalizedString( const idStrId & strId ) const {
if ( strId.GetIndex() >= 0 && strId.GetIndex() < keyVals.Num() ) {
if ( keyVals[ strId.GetIndex() ].value == NULL ) {
return keyVals[ strId.GetIndex() ].key;
} else {
return keyVals[ strId.GetIndex() ].value;
}
}
return "";
}
/*
================================================================================================
idStrId
================================================================================================
*/
/*
========================
idStrId::Set
========================
*/
void idStrId::Set( const char * key ) {
if ( key == NULL || key[0] == 0 ) {
index = -1;
} else {
index = idLocalization::languageDict.FindStringIndex( key );
if ( index < 0 ) {
// don't allow setting of string ID's to an unknown ID... this should only be allowed from
// the string table tool because additions from anywhere else are not guaranteed to be
// saved to the .lang file.
idLib::Warning( "Attempted to set unknown string ID '%s'", key );
}
}
}
/*
========================
idStrId::GetKey
========================
*/
const char * idStrId::GetKey() const {
if ( index >= 0 && index < idLocalization::languageDict.keyVals.Num() ) {
return idLocalization::languageDict.keyVals[index].key;
}
return "";
}
/*
========================
idStrId::GetLocalizedString
========================
*/
const char * idStrId::GetLocalizedString() const {
return idLocalization::languageDict.GetLocalizedString( *this );
}

150
neo/idlib/LangDict.h Normal file
View File

@@ -0,0 +1,150 @@
/*
===========================================================================
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 __LANGDICT_H__
#define __LANGDICT_H__
class idLangKeyValue {
public:
idLangKeyValue() : key( NULL ), value( NULL ) { }
idLangKeyValue( char * k, char * v ) : key ( k ), value( v ) { }
char * key;
char * value;
};
class idStrId;
/*
================================================
idLangDict is a simple Dictionary used specifically for the
LocalizedStringTables.
================================================
*/
class idLangDict {
public:
static const char * KEY_PREFIX;
static const int KEY_PREFIX_LEN;
static const int MAX_REDIRECTION_DEPTH = 2;
idLangDict();
~idLangDict();
void Clear();
bool Load( const byte * buffer, const int bufferLen, const char * name );
bool Save( const char * fileName );
const char * GetString( const char * str ) const; // returns str if string not found
const char * FindString( const char * str ) const; // returns NULL if string not found
const char * AddString( const char * str ); // returns a randomly generated key
bool DeleteString( const char * key ); // returns false if the key doesn't exist
bool RenameStringKey( const char * oldKey, const char * newKey );
bool SetString( const char * key, const char * val ); // Returns false if the key doesn't exist
void AddKeyVal( const char * key, const char * val ); // Like SetString, but adds it if it doesn't already exist
int GetNumKeyVals() const;
const idLangKeyValue * GetKeyVal( int i ) const;
bool DeleteString( const int idx );
const char * GetLocalizedString( const idStrId & strId ) const;
// returns true if the string starts with the KEY_PREFIX string
static bool IsStringId( const char * str );
private:
idDynamicBlockAlloc< char, 100 * 1024, 16 > blockAlloc;
idList< idLangKeyValue > keyVals;
idHashIndex keyIndex;
private:
int FindStringIndex( const char * str ) const;
const char * FindString_r( const char * str, int & depth ) const;
friend class idStrId;
};
/*
================================================
idLocalization
================================================
*/
class idLocalization {
public:
static const char * GetString( const char * inString ); // returns inString if string not found
static const char * FindString( const char * inString ); // Returns NULL if string not found
static void ClearDictionary();
static bool LoadDictionary( const byte * buffer, const int bufferLen, const char * name );
// This is only here for tools, normal code should only ever call GetString
static idLangDict & GetDictionary() { return languageDict; }
static utf8Encoding_t VerifyUTF8( const uint8 * buffer, const int bufferLen, const char * name );
private:
static idLangDict languageDict;
friend class idStrId;
};
/*
================================================
idStrId represents a localized String as a String ID.
================================================
*/
class idStrId {
public:
idStrId() : index( -1 ) { }
idStrId( const idStrId & other ) : index( other.index ) { }
explicit idStrId( int i ) : index( i ) { }
explicit idStrId( const char * key ) { Set( key ); }
explicit idStrId( const idStr & key ) { Set( key ); }
void operator=( const char * key ) { Set( key ); }
void operator=( const idStr & key ) { Set( key ); }
void operator=( const idStrId & other ) { index = other.index; }
bool operator==( const idStrId & other ) const { return index == other.index; }
bool operator!=( const idStrId & other ) const { return index != other.index; }
void Set( const char * key );
void Empty() { index = -1; }
bool IsEmpty() const { return index < 0; }
const char * GetKey() const;
const char * GetLocalizedString() const;
int GetIndex() const { return index; }
void SetIndex( int i ) { index = i; }
private:
int index; // Index into the language dictionary
};
#endif // !__LANGDICT_H__

1918
neo/idlib/Lexer.cpp Normal file

File diff suppressed because it is too large Load Diff

311
neo/idlib/Lexer.h Normal file
View File

@@ -0,0 +1,311 @@
/*
===========================================================================
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 __LEXER_H__
#define __LEXER_H__
/*
===============================================================================
Lexicographical parser
Does not use memory allocation during parsing. The lexer uses no
memory allocation if a source is loaded with LoadMemory().
However, idToken may still allocate memory for large strings.
A number directly following the escape character '\' in a string is
assumed to be in decimal format instead of octal. Binary numbers of
the form 0b.. or 0B.. can also be used.
===============================================================================
*/
// lexer flags
typedef enum {
LEXFL_NOERRORS = BIT(0), // don't print any errors
LEXFL_NOWARNINGS = BIT(1), // don't print any warnings
LEXFL_NOFATALERRORS = BIT(2), // errors aren't fatal
LEXFL_NOSTRINGCONCAT = BIT(3), // multiple strings seperated by whitespaces are not concatenated
LEXFL_NOSTRINGESCAPECHARS = BIT(4), // no escape characters inside strings
LEXFL_NODOLLARPRECOMPILE = BIT(5), // don't use the $ sign for precompilation
LEXFL_NOBASEINCLUDES = BIT(6), // don't include files embraced with < >
LEXFL_ALLOWPATHNAMES = BIT(7), // allow path seperators in names
LEXFL_ALLOWNUMBERNAMES = BIT(8), // allow names to start with a number
LEXFL_ALLOWIPADDRESSES = BIT(9), // allow ip addresses to be parsed as numbers
LEXFL_ALLOWFLOATEXCEPTIONS = BIT(10), // allow float exceptions like 1.#INF or 1.#IND to be parsed
LEXFL_ALLOWMULTICHARLITERALS = BIT(11), // allow multi character literals
LEXFL_ALLOWBACKSLASHSTRINGCONCAT = BIT(12), // allow multiple strings seperated by '\' to be concatenated
LEXFL_ONLYSTRINGS = BIT(13) // parse as whitespace deliminated strings (quoted strings keep quotes)
} lexerFlags_t;
// punctuation ids
#define P_RSHIFT_ASSIGN 1
#define P_LSHIFT_ASSIGN 2
#define P_PARMS 3
#define P_PRECOMPMERGE 4
#define P_LOGIC_AND 5
#define P_LOGIC_OR 6
#define P_LOGIC_GEQ 7
#define P_LOGIC_LEQ 8
#define P_LOGIC_EQ 9
#define P_LOGIC_UNEQ 10
#define P_MUL_ASSIGN 11
#define P_DIV_ASSIGN 12
#define P_MOD_ASSIGN 13
#define P_ADD_ASSIGN 14
#define P_SUB_ASSIGN 15
#define P_INC 16
#define P_DEC 17
#define P_BIN_AND_ASSIGN 18
#define P_BIN_OR_ASSIGN 19
#define P_BIN_XOR_ASSIGN 20
#define P_RSHIFT 21
#define P_LSHIFT 22
#define P_POINTERREF 23
#define P_CPP1 24
#define P_CPP2 25
#define P_MUL 26
#define P_DIV 27
#define P_MOD 28
#define P_ADD 29
#define P_SUB 30
#define P_ASSIGN 31
#define P_BIN_AND 32
#define P_BIN_OR 33
#define P_BIN_XOR 34
#define P_BIN_NOT 35
#define P_LOGIC_NOT 36
#define P_LOGIC_GREATER 37
#define P_LOGIC_LESS 38
#define P_REF 39
#define P_COMMA 40
#define P_SEMICOLON 41
#define P_COLON 42
#define P_QUESTIONMARK 43
#define P_PARENTHESESOPEN 44
#define P_PARENTHESESCLOSE 45
#define P_BRACEOPEN 46
#define P_BRACECLOSE 47
#define P_SQBRACKETOPEN 48
#define P_SQBRACKETCLOSE 49
#define P_BACKSLASH 50
#define P_PRECOMP 51
#define P_DOLLAR 52
// punctuation
typedef struct punctuation_s
{
char *p; // punctuation character(s)
int n; // punctuation id
} punctuation_t;
class idLexer {
friend class idParser;
public:
// constructor
idLexer();
idLexer( int flags );
idLexer( const char *filename, int flags = 0, bool OSPath = false );
idLexer( const char *ptr, int length, const char *name, int flags = 0 );
// destructor
~idLexer();
// load a script from the given file at the given offset with the given length
int LoadFile( const char *filename, bool OSPath = false );
// load a script from the given memory with the given length and a specified line offset,
// so source strings extracted from a file can still refer to proper line numbers in the file
// NOTE: the ptr is expected to point at a valid C string: ptr[length] == '\0'
int LoadMemory( const char *ptr, int length, const char *name, int startLine = 1 );
// free the script
void FreeSource();
// returns true if a script is loaded
int IsLoaded() { return idLexer::loaded; };
// read a token
int ReadToken( idToken *token );
// expect a certain token, reads the token when available
int ExpectTokenString( const char *string );
// expect a certain token type
int ExpectTokenType( int type, int subtype, idToken *token );
// expect a token
int ExpectAnyToken( idToken *token );
// returns true when the token is available
int CheckTokenString( const char *string );
// returns true an reads the token when a token with the given type is available
int CheckTokenType( int type, int subtype, idToken *token );
// returns true if the next token equals the given string but does not remove the token from the source
int PeekTokenString( const char *string );
// returns true if the next token equals the given type but does not remove the token from the source
int PeekTokenType( int type, int subtype, idToken *token );
// skip tokens until the given token string is read
int SkipUntilString( const char *string );
// skip the rest of the current line
int SkipRestOfLine();
// skip the braced section
int SkipBracedSection( bool parseFirstBrace = true );
// skips spaces, tabs, C-like comments etc. Returns false if there is no token left to read.
bool SkipWhiteSpace( bool currentLine );
// unread the given token
void UnreadToken( const idToken *token );
// read a token only if on the same line
int ReadTokenOnLine( idToken *token );
//Returns the rest of the current line
const char* ReadRestOfLine(idStr& out);
// read a signed integer
int ParseInt();
// read a boolean
bool ParseBool();
// read a floating point number. If errorFlag is NULL, a non-numeric token will
// issue an Error(). If it isn't NULL, it will issue a Warning() and set *errorFlag = true
float ParseFloat( bool *errorFlag = NULL );
// parse matrices with floats
int Parse1DMatrix( int x, float *m );
int Parse2DMatrix( int y, int x, float *m );
int Parse3DMatrix( int z, int y, int x, float *m );
// parse a braced section into a string
const char * ParseBracedSection( idStr &out );
// parse a braced section into a string, maintaining indents and newlines
const char * ParseBracedSectionExact ( idStr &out, int tabs = -1 );
// parse the rest of the line
const char * ParseRestOfLine( idStr &out );
// pulls the entire line, including the \n at the end
const char * ParseCompleteLine( idStr &out );
// retrieves the white space characters before the last read token
int GetLastWhiteSpace( idStr &whiteSpace ) const;
// returns start index into text buffer of last white space
int GetLastWhiteSpaceStart() const;
// returns end index into text buffer of last white space
int GetLastWhiteSpaceEnd() const;
// set an array with punctuations, NULL restores default C/C++ set, see default_punctuations for an example
void SetPunctuations( const punctuation_t *p );
// returns a pointer to the punctuation with the given id
const char * GetPunctuationFromId( int id );
// get the id for the given punctuation
int GetPunctuationId( const char *p );
// set lexer flags
void SetFlags( int flags );
// get lexer flags
int GetFlags();
// reset the lexer
void Reset();
// returns true if at the end of the file
bool EndOfFile();
// returns the current filename
const char * GetFileName();
// get offset in script
const int GetFileOffset();
// get file time
const ID_TIME_T GetFileTime();
// returns the current line number
const int GetLineNum();
// print an error message
void Error( VERIFY_FORMAT_STRING const char *str, ... );
// print a warning message
void Warning( VERIFY_FORMAT_STRING const char *str, ... );
// returns true if Error() was called with LEXFL_NOFATALERRORS or LEXFL_NOERRORS set
bool HadError() const;
// set the base folder to load files from
static void SetBaseFolder( const char *path );
private:
int loaded; // set when a script file is loaded from file or memory
idStr filename; // file name of the script
int allocated; // true if buffer memory was allocated
const char * buffer; // buffer containing the script
const char * script_p; // current pointer in the script
const char * end_p; // pointer to the end of the script
const char * lastScript_p; // script pointer before reading token
const char * whiteSpaceStart_p; // start of last white space
const char * whiteSpaceEnd_p; // end of last white space
ID_TIME_T fileTime; // file time
int length; // length of the script in bytes
int line; // current line in script
int lastline; // line before reading token
int tokenavailable; // set by unreadToken
int flags; // several script flags
const punctuation_t *punctuations; // the punctuations used in the script
int * punctuationtable; // ASCII table with punctuations
int * nextpunctuation; // next punctuation in chain
idToken token; // available token
idLexer * next; // next script in a chain
bool hadError; // set by idLexer::Error, even if the error is supressed
static char baseFolder[ 256 ]; // base folder to load files from
private:
void CreatePunctuationTable( const punctuation_t *punctuations );
int ReadWhiteSpace();
int ReadEscapeCharacter( char *ch );
int ReadString( idToken *token, int quote );
int ReadName( idToken *token );
int ReadNumber( idToken *token );
int ReadPunctuation( idToken *token );
int ReadPrimitive( idToken *token );
int CheckString( const char *str ) const;
int NumLinesCrossed();
};
ID_INLINE const char *idLexer::GetFileName() {
return idLexer::filename;
}
ID_INLINE const int idLexer::GetFileOffset() {
return idLexer::script_p - idLexer::buffer;
}
ID_INLINE const ID_TIME_T idLexer::GetFileTime() {
return idLexer::fileTime;
}
ID_INLINE const int idLexer::GetLineNum() {
return idLexer::line;
}
ID_INLINE void idLexer::SetFlags( int flags ) {
idLexer::flags = flags;
}
ID_INLINE int idLexer::GetFlags() {
return idLexer::flags;
}
#endif /* !__LEXER_H__ */

608
neo/idlib/Lib.cpp Normal file
View File

@@ -0,0 +1,608 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#if defined( MACOS_X )
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#endif
/*
===============================================================================
idLib
===============================================================================
*/
idSys * idLib::sys = NULL;
idCommon * idLib::common = NULL;
idCVarSystem * idLib::cvarSystem = NULL;
idFileSystem * idLib::fileSystem = NULL;
int idLib::frameNumber = 0;
bool idLib::mainThreadInitialized = 0;
ID_TLS idLib::isMainThread = 0;
char idException::error[2048];
/*
================
idLib::Init
================
*/
void idLib::Init() {
assert( sizeof( bool ) == 1 );
isMainThread = 1;
mainThreadInitialized = 1; // note that the thread-local isMainThread is now valid
// initialize little/big endian conversion
Swap_Init();
// init string memory allocator
idStr::InitMemory();
// initialize generic SIMD implementation
idSIMD::Init();
// initialize math
idMath::Init();
// test idMatX
//idMatX::Test();
// test idPolynomial
#ifdef _DEBUG
idPolynomial::Test();
#endif
// initialize the dictionary string pools
idDict::Init();
}
/*
================
idLib::ShutDown
================
*/
void idLib::ShutDown() {
// shut down the dictionary string pools
idDict::Shutdown();
// shut down the string memory allocator
idStr::ShutdownMemory();
// shut down the SIMD engine
idSIMD::Shutdown();
}
/*
===============================================================================
Colors
===============================================================================
*/
idVec4 colorBlack = idVec4( 0.00f, 0.00f, 0.00f, 1.00f );
idVec4 colorWhite = idVec4( 1.00f, 1.00f, 1.00f, 1.00f );
idVec4 colorRed = idVec4( 1.00f, 0.00f, 0.00f, 1.00f );
idVec4 colorGreen = idVec4( 0.00f, 1.00f, 0.00f, 1.00f );
idVec4 colorBlue = idVec4( 0.00f, 0.00f, 1.00f, 1.00f );
idVec4 colorYellow = idVec4( 1.00f, 1.00f, 0.00f, 1.00f );
idVec4 colorMagenta= idVec4( 1.00f, 0.00f, 1.00f, 1.00f );
idVec4 colorCyan = idVec4( 0.00f, 1.00f, 1.00f, 1.00f );
idVec4 colorOrange = idVec4( 1.00f, 0.50f, 0.00f, 1.00f );
idVec4 colorPurple = idVec4( 0.60f, 0.00f, 0.60f, 1.00f );
idVec4 colorPink = idVec4( 0.73f, 0.40f, 0.48f, 1.00f );
idVec4 colorBrown = idVec4( 0.40f, 0.35f, 0.08f, 1.00f );
idVec4 colorLtGrey = idVec4( 0.75f, 0.75f, 0.75f, 1.00f );
idVec4 colorMdGrey = idVec4( 0.50f, 0.50f, 0.50f, 1.00f );
idVec4 colorDkGrey = idVec4( 0.25f, 0.25f, 0.25f, 1.00f );
/*
================
PackColor
================
*/
dword PackColor( const idVec4 &color ) {
byte dx = idMath::Ftob( color.x * 255.0f );
byte dy = idMath::Ftob( color.y * 255.0f );
byte dz = idMath::Ftob( color.z * 255.0f );
byte dw = idMath::Ftob( color.w * 255.0f );
return ( dx << 0 ) | ( dy << 8 ) | ( dz << 16 ) | ( dw << 24 );
}
/*
================
UnpackColor
================
*/
void UnpackColor( const dword color, idVec4 &unpackedColor ) {
unpackedColor.Set( ( ( color >> 0 ) & 255 ) * ( 1.0f / 255.0f ),
( ( color >> 8 ) & 255 ) * ( 1.0f / 255.0f ),
( ( color >> 16 ) & 255 ) * ( 1.0f / 255.0f ),
( ( color >> 24 ) & 255 ) * ( 1.0f / 255.0f ) );
}
/*
================
PackColor
================
*/
dword PackColor( const idVec3 &color ) {
byte dx = idMath::Ftob( color.x * 255.0f );
byte dy = idMath::Ftob( color.y * 255.0f );
byte dz = idMath::Ftob( color.z * 255.0f );
return ( dx << 0 ) | ( dy << 8 ) | ( dz << 16 );
}
/*
================
UnpackColor
================
*/
void UnpackColor( const dword color, idVec3 &unpackedColor ) {
unpackedColor.Set( ( ( color >> 0 ) & 255 ) * ( 1.0f / 255.0f ),
( ( color >> 8 ) & 255 ) * ( 1.0f / 255.0f ),
( ( color >> 16 ) & 255 ) * ( 1.0f / 255.0f ) );
}
/*
===============
idLib::FatalError
===============
*/
void idLib::FatalError( const char *fmt, ... ) {
va_list argptr;
char text[MAX_STRING_CHARS];
va_start( argptr, fmt );
idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
common->FatalError( "%s", text );
}
/*
===============
idLib::Error
===============
*/
void idLib::Error( const char *fmt, ... ) {
va_list argptr;
char text[MAX_STRING_CHARS];
va_start( argptr, fmt );
idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
common->Error( "%s", text );
}
/*
===============
idLib::Warning
===============
*/
void idLib::Warning( const char *fmt, ... ) {
va_list argptr;
char text[MAX_STRING_CHARS];
va_start( argptr, fmt );
idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
common->Warning( "%s", text );
}
/*
===============
idLib::WarningIf
===============
*/
void idLib::WarningIf( const bool test, const char *fmt, ... ) {
if ( !test ) {
return;
}
va_list argptr;
char text[MAX_STRING_CHARS];
va_start( argptr, fmt );
idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
common->Warning( "%s", text );
}
/*
===============
idLib::Printf
===============
*/
void idLib::Printf( const char *fmt, ... ) {
va_list argptr;
va_start( argptr, fmt );
if ( common ) {
common->VPrintf( fmt, argptr );
}
va_end( argptr );
}
/*
===============
idLib::PrintfIf
===============
*/
void idLib::PrintfIf( const bool test, const char *fmt, ... ) {
if ( !test ) {
return;
}
va_list argptr;
va_start( argptr, fmt );
common->VPrintf( fmt, argptr );
va_end( argptr );
}
/*
===============================================================================
Byte order functions
===============================================================================
*/
// can't just use function pointers, or dll linkage can mess up
static short (*_BigShort)( short l );
static short (*_LittleShort)( short l );
static int (*_BigLong)( int l );
static int (*_LittleLong)( int l );
static float (*_BigFloat)( float l );
static float (*_LittleFloat)( float l );
static void (*_BigRevBytes)( void *bp, int elsize, int elcount );
static void (*_LittleRevBytes)( void *bp, int elsize, int elcount );
static void (*_LittleBitField)( void *bp, int elsize );
static void (*_SixtetsForInt)( byte *out, int src );
static int (*_IntForSixtets)( byte *in );
short BigShort( short l ) { return _BigShort( l ); }
short LittleShort( short l ) { return _LittleShort( l ); }
int BigLong( int l ) { return _BigLong( l ); }
int LittleLong( int l ) { return _LittleLong( l ); }
float BigFloat( float l ) { return _BigFloat( l ); }
float LittleFloat( float l ) { return _LittleFloat( l ); }
void BigRevBytes( void *bp, int elsize, int elcount ) { _BigRevBytes( bp, elsize, elcount ); }
void LittleRevBytes( void *bp, int elsize, int elcount ){ _LittleRevBytes( bp, elsize, elcount ); }
void LittleBitField( void *bp, int elsize ){ _LittleBitField( bp, elsize ); }
void SixtetsForInt( byte *out, int src) { _SixtetsForInt( out, src ); }
int IntForSixtets( byte *in ) { return _IntForSixtets( in ); }
/*
================
ShortSwap
================
*/
short ShortSwap( short l ) {
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
/*
================
ShortNoSwap
================
*/
short ShortNoSwap( short l ) {
return l;
}
/*
================
LongSwap
================
*/
int LongSwap ( int l ) {
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
/*
================
LongNoSwap
================
*/
int LongNoSwap( int l ) {
return l;
}
/*
================
FloatSwap
================
*/
float FloatSwap( float f ) {
union {
float f;
byte b[4];
} dat1, dat2;
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
dat2.b[2] = dat1.b[1];
dat2.b[3] = dat1.b[0];
return dat2.f;
}
/*
================
FloatNoSwap
================
*/
float FloatNoSwap( float f ) {
return f;
}
/*
=====================================================================
RevBytesSwap
Reverses byte order in place.
INPUTS
bp bytes to reverse
elsize size of the underlying data type
elcount number of elements to swap
RESULTS
Reverses the byte order in each of elcount elements.
===================================================================== */
void RevBytesSwap( void *bp, int elsize, int elcount ) {
register unsigned char *p, *q;
p = ( unsigned char * ) bp;
if ( elsize == 2 ) {
q = p + 1;
while ( elcount-- ) {
*p ^= *q;
*q ^= *p;
*p ^= *q;
p += 2;
q += 2;
}
return;
}
while ( elcount-- ) {
q = p + elsize - 1;
while ( p < q ) {
*p ^= *q;
*q ^= *p;
*p ^= *q;
++p;
--q;
}
p += elsize >> 1;
}
}
/*
=====================================================================
RevBytesSwap
Reverses byte order in place, then reverses bits in those bytes
INPUTS
bp bitfield structure to reverse
elsize size of the underlying data type
RESULTS
Reverses the bitfield of size elsize.
===================================================================== */
void RevBitFieldSwap( void *bp, int elsize) {
int i;
unsigned char *p, t, v;
LittleRevBytes( bp, elsize, 1 );
p = (unsigned char *) bp;
while ( elsize-- ) {
v = *p;
t = 0;
for (i = 7; i>=0; i--) {
t <<= 1;
v >>= 1;
t |= v & 1;
}
*p++ = t;
}
}
/*
================
RevBytesNoSwap
================
*/
void RevBytesNoSwap( void *bp, int elsize, int elcount ) {
return;
}
/*
================
RevBytesNoSwap
================
*/
void RevBitFieldNoSwap( void *bp, int elsize ) {
return;
}
/*
================
SixtetsForIntLittle
================
*/
void SixtetsForIntLittle( byte *out, int src) {
byte *b = (byte *)&src;
out[0] = ( b[0] & 0xfc ) >> 2;
out[1] = ( ( b[0] & 0x3 ) << 4 ) + ( ( b[1] & 0xf0 ) >> 4 );
out[2] = ( ( b[1] & 0xf ) << 2 ) + ( ( b[2] & 0xc0 ) >> 6 );
out[3] = b[2] & 0x3f;
}
/*
================
SixtetsForIntBig
TTimo: untested - that's the version from initial base64 encode
================
*/
void SixtetsForIntBig( byte *out, int src) {
for( int i = 0 ; i < 4 ; i++ ) {
out[i] = src & 0x3f;
src >>= 6;
}
}
/*
================
IntForSixtetsLittle
================
*/
int IntForSixtetsLittle( byte *in ) {
int ret = 0;
byte *b = (byte *)&ret;
b[0] |= in[0] << 2;
b[0] |= ( in[1] & 0x30 ) >> 4;
b[1] |= ( in[1] & 0xf ) << 4;
b[1] |= ( in[2] & 0x3c ) >> 2;
b[2] |= ( in[2] & 0x3 ) << 6;
b[2] |= in[3];
return ret;
}
/*
================
IntForSixtetsBig
TTimo: untested - that's the version from initial base64 decode
================
*/
int IntForSixtetsBig( byte *in ) {
int ret = 0;
ret |= in[0];
ret |= in[1] << 6;
ret |= in[2] << 2*6;
ret |= in[3] << 3*6;
return ret;
}
/*
================
Swap_Init
================
*/
void Swap_Init() {
byte swaptest[2] = {1,0};
// set the byte swapping variables in a portable manner
if ( *(short *)swaptest == 1) {
// little endian ex: x86
_BigShort = ShortSwap;
_LittleShort = ShortNoSwap;
_BigLong = LongSwap;
_LittleLong = LongNoSwap;
_BigFloat = FloatSwap;
_LittleFloat = FloatNoSwap;
_BigRevBytes = RevBytesSwap;
_LittleRevBytes = RevBytesNoSwap;
_LittleBitField = RevBitFieldNoSwap;
_SixtetsForInt = SixtetsForIntLittle;
_IntForSixtets = IntForSixtetsLittle;
} else {
// big endian ex: ppc
_BigShort = ShortNoSwap;
_LittleShort = ShortSwap;
_BigLong = LongNoSwap;
_LittleLong = LongSwap;
_BigFloat = FloatNoSwap;
_LittleFloat = FloatSwap;
_BigRevBytes = RevBytesNoSwap;
_LittleRevBytes = RevBytesSwap;
_LittleBitField = RevBitFieldSwap;
_SixtetsForInt = SixtetsForIntBig;
_IntForSixtets = IntForSixtetsBig;
}
}
/*
==========
Swap_IsBigEndian
==========
*/
bool Swap_IsBigEndian() {
byte swaptest[2] = {1,0};
return *(short *)swaptest != 1;
}
/*
========================
BreakOnListGrowth
debug tool to find uses of idlist that are dynamically growing
========================
*/
void BreakOnListGrowth() {
}
/*
========================
BreakOnListDefault
========================
*/
void BreakOnListDefault() {
}

322
neo/idlib/Lib.h Normal file
View File

@@ -0,0 +1,322 @@
/*
===========================================================================
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 __LIB_H__
#define __LIB_H__
#include <stddef.h>
/*
===============================================================================
idLib contains stateless support classes and concrete types. Some classes
do have static variables, but such variables are initialized once and
read-only after initialization (they do not maintain a modifiable state).
The interface pointers idSys, idCommon, idCVarSystem and idFileSystem
should be set before using idLib. The pointers stored here should not
be used by any part of the engine except for idLib.
===============================================================================
*/
class idLib {
private:
static bool mainThreadInitialized;
static ID_TLS isMainThread;
public:
static class idSys * sys;
static class idCommon * common;
static class idCVarSystem * cvarSystem;
static class idFileSystem * fileSystem;
static int frameNumber;
static void Init();
static void ShutDown();
// wrapper to idCommon functions
static void Printf( const char *fmt, ... );
static void PrintfIf( const bool test, const char *fmt, ... );
NO_RETURN static void Error( const char *fmt, ... );
NO_RETURN static void FatalError( const char *fmt, ... );
static void Warning( const char *fmt, ... );
static void WarningIf( const bool test, const char *fmt, ... );
// the extra check for mainThreadInitialized is necessary for this to be accurate
// when called by startup code that happens before idLib::Init
static bool IsMainThread() { return ( 0 == mainThreadInitialized ) || ( 1 == isMainThread ); }
};
/*
===============================================================================
Types and defines used throughout the engine.
===============================================================================
*/
typedef int qhandle_t;
class idFile;
class idVec3;
class idVec4;
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef BIT
#define BIT( num ) ( 1ULL << ( num ) )
#endif
#define MAX_STRING_CHARS 1024 // max length of a string
#define MAX_PRINT_MSG 16384 // buffer size for our various printf routines
// maximum world size
#define MAX_WORLD_COORD ( 128 * 1024 )
#define MIN_WORLD_COORD ( -128 * 1024 )
#define MAX_WORLD_SIZE ( MAX_WORLD_COORD - MIN_WORLD_COORD )
#define SIZE_KB( x ) ( ( (x) + 1023 ) / 1024 )
#define SIZE_MB( x ) ( ( ( SIZE_KB( x ) ) + 1023 ) / 1024 )
#define SIZE_GB( x ) ( ( ( SIZE_MB( x ) ) + 1023 ) / 1024 )
// basic colors
extern idVec4 colorBlack;
extern idVec4 colorWhite;
extern idVec4 colorRed;
extern idVec4 colorGreen;
extern idVec4 colorBlue;
extern idVec4 colorYellow;
extern idVec4 colorMagenta;
extern idVec4 colorCyan;
extern idVec4 colorOrange;
extern idVec4 colorPurple;
extern idVec4 colorPink;
extern idVec4 colorBrown;
extern idVec4 colorLtGrey;
extern idVec4 colorMdGrey;
extern idVec4 colorDkGrey;
// packs color floats in the range [0,1] into an integer
dword PackColor( const idVec3 &color );
void UnpackColor( const dword color, idVec3 &unpackedColor );
dword PackColor( const idVec4 &color );
void UnpackColor( const dword color, idVec4 &unpackedColor );
// little/big endian conversion
short BigShort( short l );
short LittleShort( short l );
int BigLong( int l );
int LittleLong( int l );
float BigFloat( float l );
float LittleFloat( float l );
void BigRevBytes( void *bp, int elsize, int elcount );
void LittleRevBytes( void *bp, int elsize, int elcount );
void LittleBitField( void *bp, int elsize );
void Swap_Init();
bool Swap_IsBigEndian();
// for base64
void SixtetsForInt( byte *out, int src);
int IntForSixtets( byte *in );
/*
================================================
idException
================================================
*/
class idException {
public:
static const int MAX_ERROR_LEN = 2048;
idException( const char *text = "" ) {
strncpy( error, text, MAX_ERROR_LEN );
}
// this really, really should be a const function, but it's referenced too many places to change right now
const char * GetError() {
return error;
}
protected:
// if GetError() were correctly const this would be named GetError(), too
char * GetErrorBuffer() {
return error;
}
int GetErrorBufferSize() {
return MAX_ERROR_LEN;
}
private:
friend class idFatalException;
static char error[MAX_ERROR_LEN];
};
/*
================================================
idFatalException
================================================
*/
class idFatalException {
public:
static const int MAX_ERROR_LEN = 2048;
idFatalException( const char *text = "" ) {
strncpy( idException::error, text, MAX_ERROR_LEN );
}
// this really, really should be a const function, but it's referenced too many places to change right now
const char * GetError() {
return idException::error;
}
protected:
// if GetError() were correctly const this would be named GetError(), too
char * GetErrorBuffer() {
return idException::error;
}
int GetErrorBufferSize() {
return MAX_ERROR_LEN;
}
};
/*
================================================
idNetworkLoadException
================================================
*/
class idNetworkLoadException : public idException {
public:
idNetworkLoadException( const char * text = "" ) : idException( text ) { }
};
/*
===============================================================================
idLib headers.
===============================================================================
*/
// System
#include "sys/sys_assert.h"
#include "sys/sys_threading.h"
// memory management and arrays
#include "Heap.h"
#include "containers/Sort.h"
#include "containers/List.h"
// math
#include "math/Simd.h"
#include "math/Math.h"
#include "math/Random.h"
#include "math/Complex.h"
#include "math/Vector.h"
#include "math/VecX.h"
#include "math/VectorI.h"
#include "math/Matrix.h"
#include "math/MatX.h"
#include "math/Angles.h"
#include "math/Quat.h"
#include "math/Rotation.h"
#include "math/Plane.h"
#include "math/Pluecker.h"
#include "math/Polynomial.h"
#include "math/Extrapolate.h"
#include "math/Interpolate.h"
#include "math/Curve.h"
#include "math/Ode.h"
#include "math/Lcp.h"
// bounding volumes
#include "bv/Sphere.h"
#include "bv/Bounds.h"
#include "bv/Box.h"
// geometry
#include "geometry/RenderMatrix.h"
#include "geometry/JointTransform.h"
#include "geometry/DrawVert.h"
#include "geometry/Winding.h"
#include "geometry/Winding2D.h"
#include "geometry/Surface.h"
#include "geometry/Surface_Patch.h"
#include "geometry/Surface_Polytope.h"
#include "geometry/Surface_SweptSpline.h"
#include "geometry/TraceModel.h"
// text manipulation
#include "Str.h"
#include "StrStatic.h"
#include "Token.h"
#include "Lexer.h"
#include "Parser.h"
#include "Base64.h"
#include "CmdArgs.h"
// containers
#include "containers/Array.h"
#include "containers/BTree.h"
#include "containers/BinSearch.h"
#include "containers/HashIndex.h"
#include "containers/HashTable.h"
#include "containers/StaticList.h"
#include "containers/LinkList.h"
#include "containers/Hierarchy.h"
#include "containers/Queue.h"
#include "containers/Stack.h"
#include "containers/StrList.h"
#include "containers/StrPool.h"
#include "containers/VectorSet.h"
#include "containers/PlaneSet.h"
// hashing
#include "hashing/CRC32.h"
#include "hashing/MD4.h"
#include "hashing/MD5.h"
// misc
#include "Dict.h"
#include "LangDict.h"
#include "DataQueue.h"
#include "BitMsg.h"
#include "MapFile.h"
#include "Timer.h"
#include "Thread.h"
#include "Swap.h"
#include "Callback.h"
#include "ParallelJobList.h"
#include "SoftwareCache.h"
#endif /* !__LIB_H__ */

972
neo/idlib/MapFile.cpp Normal file
View File

@@ -0,0 +1,972 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
/*
===============
FloatCRC
===============
*/
ID_INLINE unsigned int FloatCRC( float f ) {
return *(unsigned int *)&f;
}
/*
===============
StringCRC
===============
*/
ID_INLINE unsigned int StringCRC( const char *str ) {
unsigned int i, crc;
const unsigned char *ptr;
crc = 0;
ptr = reinterpret_cast<const unsigned char*>(str);
for ( i = 0; str[i]; i++ ) {
crc ^= str[i] << (i & 3);
}
return crc;
}
/*
=================
ComputeAxisBase
WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
rotation by (0,RotY,RotZ) assigns X to normal
=================
*/
static void ComputeAxisBase( const idVec3 &normal, idVec3 &texS, idVec3 &texT ) {
float RotY, RotZ;
idVec3 n;
// do some cleaning
n[0] = ( idMath::Fabs( normal[0] ) < 1e-6f ) ? 0.0f : normal[0];
n[1] = ( idMath::Fabs( normal[1] ) < 1e-6f ) ? 0.0f : normal[1];
n[2] = ( idMath::Fabs( normal[2] ) < 1e-6f ) ? 0.0f : normal[2];
RotY = -atan2( n[2], idMath::Sqrt( n[1] * n[1] + n[0] * n[0]) );
RotZ = atan2( n[1], n[0] );
// rotate (0,1,0) and (0,0,1) to compute texS and texT
texS[0] = -sin(RotZ);
texS[1] = cos(RotZ);
texS[2] = 0;
// the texT vector is along -Z ( T texture coorinates axis )
texT[0] = -sin(RotY) * cos(RotZ);
texT[1] = -sin(RotY) * sin(RotZ);
texT[2] = -cos(RotY);
}
/*
=================
idMapBrushSide::GetTextureVectors
=================
*/
void idMapBrushSide::GetTextureVectors( idVec4 v[2] ) const {
int i;
idVec3 texX, texY;
ComputeAxisBase( plane.Normal(), texX, texY );
for ( i = 0; i < 2; i++ ) {
v[i][0] = texX[0] * texMat[i][0] + texY[0] * texMat[i][1];
v[i][1] = texX[1] * texMat[i][0] + texY[1] * texMat[i][1];
v[i][2] = texX[2] * texMat[i][0] + texY[2] * texMat[i][1];
v[i][3] = texMat[i][2] + ( origin * v[i].ToVec3() );
}
}
/*
=================
idMapPatch::Parse
=================
*/
idMapPatch *idMapPatch::Parse( idLexer &src, const idVec3 &origin, bool patchDef3, float version ) {
float info[7];
idDrawVert *vert;
idToken token;
int i, j;
if ( !src.ExpectTokenString( "{" ) ) {
return NULL;
}
// read the material (we had an implicit 'textures/' in the old format...)
if ( !src.ReadToken( &token ) ) {
src.Error( "idMapPatch::Parse: unexpected EOF" );
return NULL;
}
// Parse it
if (patchDef3) {
if ( !src.Parse1DMatrix( 7, info ) ) {
src.Error( "idMapPatch::Parse: unable to Parse patchDef3 info" );
return NULL;
}
} else {
if ( !src.Parse1DMatrix( 5, info ) ) {
src.Error( "idMapPatch::Parse: unable to parse patchDef2 info" );
return NULL;
}
}
idMapPatch *patch = new (TAG_IDLIB) idMapPatch( info[0], info[1] );
patch->SetSize( info[0], info[1] );
if ( version < 2.0f ) {
patch->SetMaterial( "textures/" + token );
} else {
patch->SetMaterial( token );
}
if ( patchDef3 ) {
patch->SetHorzSubdivisions( info[2] );
patch->SetVertSubdivisions( info[3] );
patch->SetExplicitlySubdivided( true );
}
if ( patch->GetWidth() < 0 || patch->GetHeight() < 0 ) {
src.Error( "idMapPatch::Parse: bad size" );
delete patch;
return NULL;
}
// these were written out in the wrong order, IMHO
if ( !src.ExpectTokenString( "(" ) ) {
src.Error( "idMapPatch::Parse: bad patch vertex data" );
delete patch;
return NULL;
}
for ( j = 0; j < patch->GetWidth(); j++ ) {
if ( !src.ExpectTokenString( "(" ) ) {
src.Error( "idMapPatch::Parse: bad vertex row data" );
delete patch;
return NULL;
}
for ( i = 0; i < patch->GetHeight(); i++ ) {
float v[5];
if ( !src.Parse1DMatrix( 5, v ) ) {
src.Error( "idMapPatch::Parse: bad vertex column data" );
delete patch;
return NULL;
}
vert = &((*patch)[i * patch->GetWidth() + j]);
vert->xyz[0] = v[0] - origin[0];
vert->xyz[1] = v[1] - origin[1];
vert->xyz[2] = v[2] - origin[2];
vert->SetTexCoord( v[3], v[4] );
}
if ( !src.ExpectTokenString( ")" ) ) {
delete patch;
src.Error( "idMapPatch::Parse: unable to parse patch control points" );
return NULL;
}
}
if ( !src.ExpectTokenString( ")" ) ) {
src.Error( "idMapPatch::Parse: unable to parse patch control points, no closure" );
delete patch;
return NULL;
}
// read any key/value pairs
while( src.ReadToken( &token ) ) {
if ( token == "}" ) {
src.ExpectTokenString( "}" );
break;
}
if ( token.type == TT_STRING ) {
idStr key = token;
src.ExpectTokenType( TT_STRING, 0, &token );
patch->epairs.Set( key, token );
}
}
return patch;
}
/*
============
idMapPatch::Write
============
*/
bool idMapPatch::Write( idFile *fp, int primitiveNum, const idVec3 &origin ) const {
int i, j;
const idDrawVert *v;
if ( GetExplicitlySubdivided() ) {
fp->WriteFloatString( "// primitive %d\n{\n patchDef3\n {\n", primitiveNum );
fp->WriteFloatString( " \"%s\"\n ( %d %d %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight(), GetHorzSubdivisions(), GetVertSubdivisions());
} else {
fp->WriteFloatString( "// primitive %d\n{\n patchDef2\n {\n", primitiveNum );
fp->WriteFloatString( " \"%s\"\n ( %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight());
}
fp->WriteFloatString( " (\n" );
idVec2 st;
for ( i = 0; i < GetWidth(); i++ ) {
fp->WriteFloatString( " ( " );
for ( j = 0; j < GetHeight(); j++ ) {
v = &verts[ j * GetWidth() + i ];
st = v->GetTexCoord();
fp->WriteFloatString( " ( %f %f %f %f %f )", v->xyz[0] + origin[0],
v->xyz[1] + origin[1], v->xyz[2] + origin[2], st[0], st[1] );
}
fp->WriteFloatString( " )\n" );
}
fp->WriteFloatString( " )\n }\n}\n" );
return true;
}
/*
===============
idMapPatch::GetGeometryCRC
===============
*/
unsigned int idMapPatch::GetGeometryCRC() const {
int i, j;
unsigned int crc;
crc = GetHorzSubdivisions() ^ GetVertSubdivisions();
for ( i = 0; i < GetWidth(); i++ ) {
for ( j = 0; j < GetHeight(); j++ ) {
crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.x );
crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.y );
crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.z );
}
}
crc ^= StringCRC( GetMaterial() );
return crc;
}
/*
=================
idMapBrush::Parse
=================
*/
idMapBrush *idMapBrush::Parse( idLexer &src, const idVec3 &origin, bool newFormat, float version ) {
int i;
idVec3 planepts[3];
idToken token;
idList<idMapBrushSide*> sides;
idMapBrushSide *side;
idDict epairs;
if ( !src.ExpectTokenString( "{" ) ) {
return NULL;
}
do {
if ( !src.ReadToken( &token ) ) {
src.Error( "idMapBrush::Parse: unexpected EOF" );
sides.DeleteContents( true );
return NULL;
}
if ( token == "}" ) {
break;
}
// here we may have to jump over brush epairs ( only used in editor )
do {
// if token is a brace
if ( token == "(" ) {
break;
}
// the token should be a key string for a key/value pair
if ( token.type != TT_STRING ) {
src.Error( "idMapBrush::Parse: unexpected %s, expected ( or epair key string", token.c_str() );
sides.DeleteContents( true );
return NULL;
}
idStr key = token;
if ( !src.ReadTokenOnLine( &token ) || token.type != TT_STRING ) {
src.Error( "idMapBrush::Parse: expected epair value string not found" );
sides.DeleteContents( true );
return NULL;
}
epairs.Set( key, token );
// try to read the next key
if ( !src.ReadToken( &token ) ) {
src.Error( "idMapBrush::Parse: unexpected EOF" );
sides.DeleteContents( true );
return NULL;
}
} while (1);
src.UnreadToken( &token );
side = new (TAG_IDLIB) idMapBrushSide();
sides.Append(side);
if ( newFormat ) {
if ( !src.Parse1DMatrix( 4, side->plane.ToFloatPtr() ) ) {
src.Error( "idMapBrush::Parse: unable to read brush side plane definition" );
sides.DeleteContents( true );
return NULL;
}
} else {
// read the three point plane definition
if (!src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) ) {
src.Error( "idMapBrush::Parse: unable to read brush side plane definition" );
sides.DeleteContents( true );
return NULL;
}
planepts[0] -= origin;
planepts[1] -= origin;
planepts[2] -= origin;
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
}
// read the texture matrix
// this is odd, because the texmat is 2D relative to default planar texture axis
if ( !src.Parse2DMatrix( 2, 3, side->texMat[0].ToFloatPtr() ) ) {
src.Error( "idMapBrush::Parse: unable to read brush side texture matrix" );
sides.DeleteContents( true );
return NULL;
}
side->origin = origin;
// read the material
if ( !src.ReadTokenOnLine( &token ) ) {
src.Error( "idMapBrush::Parse: unable to read brush side material" );
sides.DeleteContents( true );
return NULL;
}
// we had an implicit 'textures/' in the old format...
if ( version < 2.0f ) {
side->material = "textures/" + token;
} else {
side->material = token;
}
// Q2 allowed override of default flags and values, but we don't any more
if ( src.ReadTokenOnLine( &token ) ) {
if ( src.ReadTokenOnLine( &token ) ) {
if ( src.ReadTokenOnLine( &token ) ) {
}
}
}
} while( 1 );
if ( !src.ExpectTokenString( "}" ) ) {
sides.DeleteContents( true );
return NULL;
}
idMapBrush *brush = new (TAG_IDLIB) idMapBrush();
for ( i = 0; i < sides.Num(); i++ ) {
brush->AddSide( sides[i] );
}
brush->epairs = epairs;
return brush;
}
/*
=================
idMapBrush::ParseQ3
=================
*/
idMapBrush *idMapBrush::ParseQ3( idLexer &src, const idVec3 &origin ) {
int i, shift[2], rotate;
float scale[2];
idVec3 planepts[3];
idToken token;
idList<idMapBrushSide*> sides;
idMapBrushSide *side;
idDict epairs;
do {
if ( src.CheckTokenString( "}" ) ) {
break;
}
side = new (TAG_IDLIB) idMapBrushSide();
sides.Append( side );
// read the three point plane definition
if (!src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) ) {
src.Error( "idMapBrush::ParseQ3: unable to read brush side plane definition" );
sides.DeleteContents( true );
return NULL;
}
planepts[0] -= origin;
planepts[1] -= origin;
planepts[2] -= origin;
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
// read the material
if ( !src.ReadTokenOnLine( &token ) ) {
src.Error( "idMapBrush::ParseQ3: unable to read brush side material" );
sides.DeleteContents( true );
return NULL;
}
// we have an implicit 'textures/' in the old format
side->material = "textures/" + token;
// read the texture shift, rotate and scale
shift[0] = src.ParseInt();
shift[1] = src.ParseInt();
rotate = src.ParseInt();
scale[0] = src.ParseFloat();
scale[1] = src.ParseFloat();
side->texMat[0] = idVec3( 0.03125f, 0.0f, 0.0f );
side->texMat[1] = idVec3( 0.0f, 0.03125f, 0.0f );
side->origin = origin;
// Q2 allowed override of default flags and values, but we don't any more
if ( src.ReadTokenOnLine( &token ) ) {
if ( src.ReadTokenOnLine( &token ) ) {
if ( src.ReadTokenOnLine( &token ) ) {
}
}
}
} while( 1 );
idMapBrush *brush = new (TAG_IDLIB) idMapBrush();
for ( i = 0; i < sides.Num(); i++ ) {
brush->AddSide( sides[i] );
}
brush->epairs = epairs;
return brush;
}
/*
============
idMapBrush::Write
============
*/
bool idMapBrush::Write( idFile *fp, int primitiveNum, const idVec3 &origin ) const {
int i;
idMapBrushSide *side;
fp->WriteFloatString( "// primitive %d\n{\n brushDef3\n {\n", primitiveNum );
// write brush epairs
for ( i = 0; i < epairs.GetNumKeyVals(); i++) {
fp->WriteFloatString( " \"%s\" \"%s\"\n", epairs.GetKeyVal(i)->GetKey().c_str(), epairs.GetKeyVal(i)->GetValue().c_str());
}
// write brush sides
for ( i = 0; i < GetNumSides(); i++ ) {
side = GetSide( i );
fp->WriteFloatString( " ( %f %f %f %f ) ", side->plane[0], side->plane[1], side->plane[2], side->plane[3] );
fp->WriteFloatString( "( ( %f %f %f ) ( %f %f %f ) ) \"%s\" 0 0 0\n",
side->texMat[0][0], side->texMat[0][1], side->texMat[0][2],
side->texMat[1][0], side->texMat[1][1], side->texMat[1][2],
side->material.c_str() );
}
fp->WriteFloatString( " }\n}\n" );
return true;
}
/*
===============
idMapBrush::GetGeometryCRC
===============
*/
unsigned int idMapBrush::GetGeometryCRC() const {
int i, j;
idMapBrushSide *mapSide;
unsigned int crc;
crc = 0;
for ( i = 0; i < GetNumSides(); i++ ) {
mapSide = GetSide(i);
for ( j = 0; j < 4; j++ ) {
crc ^= FloatCRC( mapSide->GetPlane()[j] );
}
crc ^= StringCRC( mapSide->GetMaterial() );
}
return crc;
}
/*
================
idMapEntity::Parse
================
*/
idMapEntity *idMapEntity::Parse( idLexer &src, bool worldSpawn, float version ) {
idToken token;
idMapEntity *mapEnt;
idMapPatch *mapPatch;
idMapBrush *mapBrush;
bool worldent;
idVec3 origin;
double v1, v2, v3;
if ( !src.ReadToken(&token) ) {
return NULL;
}
if ( token != "{" ) {
src.Error( "idMapEntity::Parse: { not found, found %s", token.c_str() );
return NULL;
}
mapEnt = new (TAG_IDLIB) idMapEntity();
if ( worldSpawn ) {
mapEnt->primitives.Resize( 1024, 256 );
}
origin.Zero();
worldent = false;
do {
if ( !src.ReadToken(&token) ) {
src.Error( "idMapEntity::Parse: EOF without closing brace" );
return NULL;
}
if ( token == "}" ) {
break;
}
if ( token == "{" ) {
// parse a brush or patch
if ( !src.ReadToken( &token ) ) {
src.Error( "idMapEntity::Parse: unexpected EOF" );
return NULL;
}
if ( worldent ) {
origin.Zero();
}
// if is it a brush: brush, brushDef, brushDef2, brushDef3
if ( token.Icmpn( "brush", 5 ) == 0 ) {
mapBrush = idMapBrush::Parse( src, origin, ( !token.Icmp( "brushDef2" ) || !token.Icmp( "brushDef3" ) ), version );
if ( !mapBrush ) {
return NULL;
}
mapEnt->AddPrimitive( mapBrush );
}
// if is it a patch: patchDef2, patchDef3
else if ( token.Icmpn( "patch", 5 ) == 0 ) {
mapPatch = idMapPatch::Parse( src, origin, !token.Icmp( "patchDef3" ), version );
if ( !mapPatch ) {
return NULL;
}
mapEnt->AddPrimitive( mapPatch );
}
// assume it's a brush in Q3 or older style
else {
src.UnreadToken( &token );
mapBrush = idMapBrush::ParseQ3( src, origin );
if ( !mapBrush ) {
return NULL;
}
mapEnt->AddPrimitive( mapBrush );
}
} else {
idStr key, value;
// parse a key / value pair
key = token;
src.ReadTokenOnLine( &token );
value = token;
// strip trailing spaces that sometimes get accidentally
// added in the editor
value.StripTrailingWhitespace();
key.StripTrailingWhitespace();
mapEnt->epairs.Set( key, value );
if ( !idStr::Icmp( key, "origin" ) ) {
// scanf into doubles, then assign, so it is idVec size independent
v1 = v2 = v3 = 0;
sscanf( value, "%lf %lf %lf", &v1, &v2, &v3 );
origin.x = v1;
origin.y = v2;
origin.z = v3;
}
else if ( !idStr::Icmp( key, "classname" ) && !idStr::Icmp( value, "worldspawn" ) ) {
worldent = true;
}
}
} while( 1 );
return mapEnt;
}
/*
============
idMapEntity::Write
============
*/
bool idMapEntity::Write( idFile *fp, int entityNum ) const {
int i;
idMapPrimitive *mapPrim;
idVec3 origin;
fp->WriteFloatString( "// entity %d\n{\n", entityNum );
// write entity epairs
for ( i = 0; i < epairs.GetNumKeyVals(); i++) {
fp->WriteFloatString( "\"%s\" \"%s\"\n", epairs.GetKeyVal(i)->GetKey().c_str(), epairs.GetKeyVal(i)->GetValue().c_str());
}
epairs.GetVector( "origin", "0 0 0", origin );
// write pritimives
for ( i = 0; i < GetNumPrimitives(); i++ ) {
mapPrim = GetPrimitive( i );
switch( mapPrim->GetType() ) {
case idMapPrimitive::TYPE_BRUSH:
static_cast<idMapBrush*>(mapPrim)->Write( fp, i, origin );
break;
case idMapPrimitive::TYPE_PATCH:
static_cast<idMapPatch*>(mapPrim)->Write( fp, i, origin );
break;
}
}
fp->WriteFloatString( "}\n" );
return true;
}
/*
===============
idMapEntity::RemovePrimitiveData
===============
*/
void idMapEntity::RemovePrimitiveData() {
primitives.DeleteContents(true);
}
/*
===============
idMapEntity::GetGeometryCRC
===============
*/
unsigned int idMapEntity::GetGeometryCRC() const {
int i;
unsigned int crc;
idMapPrimitive *mapPrim;
crc = 0;
for ( i = 0; i < GetNumPrimitives(); i++ ) {
mapPrim = GetPrimitive( i );
switch( mapPrim->GetType() ) {
case idMapPrimitive::TYPE_BRUSH:
crc ^= static_cast<idMapBrush*>(mapPrim)->GetGeometryCRC();
break;
case idMapPrimitive::TYPE_PATCH:
crc ^= static_cast<idMapPatch*>(mapPrim)->GetGeometryCRC();
break;
}
}
return crc;
}
/*
===============
idMapFile::Parse
===============
*/
bool idMapFile::Parse( const char *filename, bool ignoreRegion, bool osPath ) {
// no string concatenation for epairs and allow path names for materials
idLexer src( LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
idToken token;
idStr fullName;
idMapEntity *mapEnt;
int i, j, k;
name = filename;
name.StripFileExtension();
fullName = name;
hasPrimitiveData = false;
if ( !ignoreRegion ) {
// try loading a .reg file first
fullName.SetFileExtension( "reg" );
src.LoadFile( fullName, osPath );
}
if ( !src.IsLoaded() ) {
// now try a .map file
fullName.SetFileExtension( "map" );
src.LoadFile( fullName, osPath );
if ( !src.IsLoaded() ) {
// didn't get anything at all
return false;
}
}
version = OLD_MAP_VERSION;
fileTime = src.GetFileTime();
entities.DeleteContents( true );
if ( src.CheckTokenString( "Version" ) ) {
src.ReadTokenOnLine( &token );
version = token.GetFloatValue();
}
while( 1 ) {
mapEnt = idMapEntity::Parse( src, ( entities.Num() == 0 ), version );
if ( !mapEnt ) {
break;
}
entities.Append( mapEnt );
}
SetGeometryCRC();
// if the map has a worldspawn
if ( entities.Num() ) {
// "removeEntities" "classname" can be set in the worldspawn to remove all entities with the given classname
const idKeyValue *removeEntities = entities[0]->epairs.MatchPrefix( "removeEntities", NULL );
while ( removeEntities ) {
RemoveEntities( removeEntities->GetValue() );
removeEntities = entities[0]->epairs.MatchPrefix( "removeEntities", removeEntities );
}
// "overrideMaterial" "material" can be set in the worldspawn to reset all materials
idStr material;
if ( entities[0]->epairs.GetString( "overrideMaterial", "", material ) ) {
for ( i = 0; i < entities.Num(); i++ ) {
mapEnt = entities[i];
for ( j = 0; j < mapEnt->GetNumPrimitives(); j++ ) {
idMapPrimitive *mapPrimitive = mapEnt->GetPrimitive( j );
switch( mapPrimitive->GetType() ) {
case idMapPrimitive::TYPE_BRUSH: {
idMapBrush *mapBrush = static_cast<idMapBrush *>(mapPrimitive);
for ( k = 0; k < mapBrush->GetNumSides(); k++ ) {
mapBrush->GetSide( k )->SetMaterial( material );
}
break;
}
case idMapPrimitive::TYPE_PATCH: {
static_cast<idMapPatch *>(mapPrimitive)->SetMaterial( material );
break;
}
}
}
}
}
// force all entities to have a name key/value pair
if ( entities[0]->epairs.GetBool( "forceEntityNames" ) ) {
for ( i = 1; i < entities.Num(); i++ ) {
mapEnt = entities[i];
if ( !mapEnt->epairs.FindKey( "name" ) ) {
mapEnt->epairs.Set( "name", va( "%s%d", mapEnt->epairs.GetString( "classname", "forcedName" ), i ) );
}
}
}
// move the primitives of any func_group entities to the worldspawn
if ( entities[0]->epairs.GetBool( "moveFuncGroups" ) ) {
for ( i = 1; i < entities.Num(); i++ ) {
mapEnt = entities[i];
if ( idStr::Icmp( mapEnt->epairs.GetString( "classname" ), "func_group" ) == 0 ) {
entities[0]->primitives.Append( mapEnt->primitives );
mapEnt->primitives.Clear();
}
}
}
}
hasPrimitiveData = true;
return true;
}
/*
============
idMapFile::Write
============
*/
bool idMapFile::Write( const char *fileName, const char *ext, bool fromBasePath ) {
int i;
idStr qpath;
idFile *fp;
qpath = fileName;
qpath.SetFileExtension( ext );
idLib::common->Printf( "writing %s...\n", qpath.c_str() );
if ( fromBasePath ) {
fp = idLib::fileSystem->OpenFileWrite( qpath, "fs_basepath" );
}
else {
fp = idLib::fileSystem->OpenExplicitFileWrite( qpath );
}
if ( !fp ) {
idLib::common->Warning( "Couldn't open %s\n", qpath.c_str() );
return false;
}
fp->WriteFloatString( "Version %f\n", (float) CURRENT_MAP_VERSION );
for ( i = 0; i < entities.Num(); i++ ) {
entities[i]->Write( fp, i );
}
idLib::fileSystem->CloseFile( fp );
return true;
}
/*
===============
idMapFile::SetGeometryCRC
===============
*/
void idMapFile::SetGeometryCRC() {
int i;
geometryCRC = 0;
for ( i = 0; i < entities.Num(); i++ ) {
geometryCRC ^= entities[i]->GetGeometryCRC();
}
}
/*
===============
idMapFile::AddEntity
===============
*/
int idMapFile::AddEntity( idMapEntity *mapEnt ) {
int ret = entities.Append( mapEnt );
return ret;
}
/*
===============
idMapFile::FindEntity
===============
*/
idMapEntity *idMapFile::FindEntity( const char *name ) {
for ( int i = 0; i < entities.Num(); i++ ) {
idMapEntity *ent = entities[i];
if ( idStr::Icmp( ent->epairs.GetString( "name" ), name ) == 0 ) {
return ent;
}
}
return NULL;
}
/*
===============
idMapFile::RemoveEntity
===============
*/
void idMapFile::RemoveEntity( idMapEntity *mapEnt ) {
entities.Remove( mapEnt );
delete mapEnt;
}
/*
===============
idMapFile::RemoveEntity
===============
*/
void idMapFile::RemoveEntities( const char *classname ) {
for ( int i = 0; i < entities.Num(); i++ ) {
idMapEntity *ent = entities[i];
if ( idStr::Icmp( ent->epairs.GetString( "classname" ), classname ) == 0 ) {
delete entities[i];
entities.RemoveIndex( i );
i--;
}
}
}
/*
===============
idMapFile::RemoveAllEntities
===============
*/
void idMapFile::RemoveAllEntities() {
entities.DeleteContents( true );
hasPrimitiveData = false;
}
/*
===============
idMapFile::RemovePrimitiveData
===============
*/
void idMapFile::RemovePrimitiveData() {
for ( int i = 0; i < entities.Num(); i++ ) {
idMapEntity *ent = entities[i];
ent->RemovePrimitiveData();
}
hasPrimitiveData = false;
}
/*
===============
idMapFile::NeedsReload
===============
*/
bool idMapFile::NeedsReload() {
if ( name.Length() ) {
ID_TIME_T time = FILE_NOT_FOUND_TIMESTAMP;
if ( idLib::fileSystem->ReadFile( name, NULL, &time ) > 0 ) {
return ( time > fileTime );
}
}
return true;
}

237
neo/idlib/MapFile.h Normal file
View File

@@ -0,0 +1,237 @@
/*
===========================================================================
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 __MAPFILE_H__
#define __MAPFILE_H__
/*
===============================================================================
Reads or writes the contents of .map files into a standard internal
format, which can then be moved into private formats for collision
detection, map processing, or editor use.
No validation (duplicate planes, null area brushes, etc) is performed.
There are no limits to the number of any of the elements in maps.
The order of entities, brushes, and sides is maintained.
===============================================================================
*/
const int OLD_MAP_VERSION = 1;
const int CURRENT_MAP_VERSION = 2;
const int DEFAULT_CURVE_SUBDIVISION = 4;
const float DEFAULT_CURVE_MAX_ERROR = 4.0f;
const float DEFAULT_CURVE_MAX_ERROR_CD = 24.0f;
const float DEFAULT_CURVE_MAX_LENGTH = -1.0f;
const float DEFAULT_CURVE_MAX_LENGTH_CD = -1.0f;
class idMapPrimitive {
public:
enum { TYPE_INVALID = -1, TYPE_BRUSH, TYPE_PATCH };
idDict epairs;
idMapPrimitive() { type = TYPE_INVALID; }
virtual ~idMapPrimitive() { }
int GetType() const { return type; }
protected:
int type;
};
class idMapBrushSide {
friend class idMapBrush;
public:
idMapBrushSide();
~idMapBrushSide() { }
const char * GetMaterial() const { return material; }
void SetMaterial( const char *p ) { material = p; }
const idPlane & GetPlane() const { return plane; }
void SetPlane( const idPlane &p ) { plane = p; }
void SetTextureMatrix( const idVec3 mat[2] ) { texMat[0] = mat[0]; texMat[1] = mat[1]; }
void GetTextureMatrix( idVec3 &mat1, idVec3 &mat2 ) { mat1 = texMat[0]; mat2 = texMat[1]; }
void GetTextureVectors( idVec4 v[2] ) const;
protected:
idStr material;
idPlane plane;
idVec3 texMat[2];
idVec3 origin;
};
ID_INLINE idMapBrushSide::idMapBrushSide() {
plane.Zero();
texMat[0].Zero();
texMat[1].Zero();
origin.Zero();
}
class idMapBrush : public idMapPrimitive {
public:
idMapBrush() { type = TYPE_BRUSH; sides.Resize( 8, 4 ); }
~idMapBrush() { sides.DeleteContents( true ); }
static idMapBrush * Parse( idLexer &src, const idVec3 &origin, bool newFormat = true, float version = CURRENT_MAP_VERSION );
static idMapBrush * ParseQ3( idLexer &src, const idVec3 &origin );
bool Write( idFile *fp, int primitiveNum, const idVec3 &origin ) const;
int GetNumSides() const { return sides.Num(); }
int AddSide( idMapBrushSide *side ) { return sides.Append( side ); }
idMapBrushSide * GetSide( int i ) const { return sides[i]; }
unsigned int GetGeometryCRC() const;
protected:
int numSides;
idList<idMapBrushSide*, TAG_IDLIB_LIST_MAP> sides;
};
class idMapPatch : public idMapPrimitive, public idSurface_Patch {
public:
idMapPatch();
idMapPatch( int maxPatchWidth, int maxPatchHeight );
~idMapPatch() { }
static idMapPatch * Parse( idLexer &src, const idVec3 &origin, bool patchDef3 = true, float version = CURRENT_MAP_VERSION );
bool Write( idFile *fp, int primitiveNum, const idVec3 &origin ) const;
const char * GetMaterial() const { return material; }
void SetMaterial( const char *p ) { material = p; }
int GetHorzSubdivisions() const { return horzSubdivisions; }
int GetVertSubdivisions() const { return vertSubdivisions; }
bool GetExplicitlySubdivided() const { return explicitSubdivisions; }
void SetHorzSubdivisions( int n ) { horzSubdivisions = n; }
void SetVertSubdivisions( int n ) { vertSubdivisions = n; }
void SetExplicitlySubdivided( bool b ) { explicitSubdivisions = b; }
unsigned int GetGeometryCRC() const;
protected:
idStr material;
int horzSubdivisions;
int vertSubdivisions;
bool explicitSubdivisions;
};
ID_INLINE idMapPatch::idMapPatch() {
type = TYPE_PATCH;
horzSubdivisions = vertSubdivisions = 0;
explicitSubdivisions = false;
width = height = 0;
maxWidth = maxHeight = 0;
expanded = false;
}
ID_INLINE idMapPatch::idMapPatch( int maxPatchWidth, int maxPatchHeight ) {
type = TYPE_PATCH;
horzSubdivisions = vertSubdivisions = 0;
explicitSubdivisions = false;
width = height = 0;
maxWidth = maxPatchWidth;
maxHeight = maxPatchHeight;
verts.SetNum( maxWidth * maxHeight );
expanded = false;
}
class idMapEntity {
friend class idMapFile;
public:
idDict epairs;
public:
idMapEntity() { epairs.SetHashSize( 64 ); }
~idMapEntity() { primitives.DeleteContents( true ); }
static idMapEntity * Parse( idLexer &src, bool worldSpawn = false, float version = CURRENT_MAP_VERSION );
bool Write( idFile *fp, int entityNum ) const;
int GetNumPrimitives() const { return primitives.Num(); }
idMapPrimitive * GetPrimitive( int i ) const { return primitives[i]; }
void AddPrimitive( idMapPrimitive *p ) { primitives.Append( p ); }
unsigned int GetGeometryCRC() const;
void RemovePrimitiveData();
protected:
idList<idMapPrimitive*, TAG_IDLIB_LIST_MAP> primitives;
};
class idMapFile {
public:
idMapFile();
~idMapFile() { entities.DeleteContents( true ); }
// filename does not require an extension
// normally this will use a .reg file instead of a .map file if it exists,
// which is what the game and dmap want, but the editor will want to always
// load a .map file
bool Parse( const char *filename, bool ignoreRegion = false, bool osPath = false );
bool Write( const char *fileName, const char *ext, bool fromBasePath = true );
// get the number of entities in the map
int GetNumEntities() const { return entities.Num(); }
// get the specified entity
idMapEntity * GetEntity( int i ) const { return entities[i]; }
// get the name without file extension
const char * GetName() const { return name; }
// get the file time
ID_TIME_T GetFileTime() const { return fileTime; }
// get CRC for the map geometry
// texture coordinates and entity key/value pairs are not taken into account
unsigned int GetGeometryCRC() const { return geometryCRC; }
// returns true if the file on disk changed
bool NeedsReload();
int AddEntity( idMapEntity *mapentity );
idMapEntity * FindEntity( const char *name );
void RemoveEntity( idMapEntity *mapEnt );
void RemoveEntities( const char *classname );
void RemoveAllEntities();
void RemovePrimitiveData();
bool HasPrimitiveData() { return hasPrimitiveData; }
protected:
float version;
ID_TIME_T fileTime;
unsigned int geometryCRC;
idList<idMapEntity *, TAG_IDLIB_LIST_MAP> entities;
idStr name;
bool hasPrimitiveData;
private:
void SetGeometryCRC();
};
ID_INLINE idMapFile::idMapFile() {
version = CURRENT_MAP_VERSION;
fileTime = 0;
geometryCRC = 0;
entities.Resize( 1024, 256 );
hasPrimitiveData = false;
}
#endif /* !__MAPFILE_H__ */

File diff suppressed because it is too large Load Diff

177
neo/idlib/ParallelJobList.h Normal file
View File

@@ -0,0 +1,177 @@
/*
===========================================================================
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 __PARALLELJOBLIST_H__
#define __PARALLELJOBLIST_H__
struct CellSpursJob128;
class idColor;
typedef void ( * jobRun_t )( void * );
enum jobSyncType_t {
SYNC_NONE,
SYNC_SIGNAL,
SYNC_SYNCHRONIZE
};
// NOTE: keep in sync with jobNames[]
enum jobListId_t {
JOBLIST_RENDERER_FRONTEND = 0,
JOBLIST_RENDERER_BACKEND = 1,
JOBLIST_UTILITY = 9, // won't print over-time warnings
MAX_JOBLISTS = 32 // the editor may cause quite a few to be allocated
};
compile_time_assert( CONST_ISPOWEROFTWO( MAX_JOBLISTS ) );
enum jobListPriority_t {
JOBLIST_PRIORITY_NONE,
JOBLIST_PRIORITY_LOW,
JOBLIST_PRIORITY_MEDIUM,
JOBLIST_PRIORITY_HIGH
};
enum jobListParallelism_t {
JOBLIST_PARALLELISM_DEFAULT = -1, // use "jobs_numThreads" number of threads
JOBLIST_PARALLELISM_MAX_CORES = -2, // use a thread for each logical core (includes hyperthreads)
JOBLIST_PARALLELISM_MAX_THREADS = -3 // use the maximum number of job threads, which can help if there is IO to overlap
};
#define assert_spu_local_store( ptr )
#define assert_not_spu_local_store( ptr )
/*
================================================
idParallelJobList
A job should be at least a couple of 1000 clock cycles in
order to outweigh any job switching overhead. On the other
hand a job should consume no more than a couple of
100,000 clock cycles to maintain a good load balance over
multiple processing units.
================================================
*/
class idParallelJobList {
friend class idParallelJobManagerLocal;
public:
void AddJob( jobRun_t function, void * data );
CellSpursJob128 * AddJobSPURS();
void InsertSyncPoint( jobSyncType_t syncType );
// Submit the jobs in this list.
void Submit( idParallelJobList * waitForJobList = NULL, int parallelism = JOBLIST_PARALLELISM_DEFAULT );
// Wait for the jobs in this list to finish. Will spin in place if any jobs are not done.
void Wait();
// Try to wait for the jobs in this list to finish but either way return immediately. Returns true if all jobs are done.
bool TryWait();
// returns true if the job list has been submitted.
bool IsSubmitted() const;
// Get the number of jobs executed in this job list.
unsigned int GetNumExecutedJobs() const;
// Get the number of sync points.
unsigned int GetNumSyncs() const;
// Time at which the job list was submitted.
uint64 GetSubmitTimeMicroSec() const;
// Time at which execution of this job list started.
uint64 GetStartTimeMicroSec() const;
// Time at which all jobs in the list were executed.
uint64 GetFinishTimeMicroSec() const;
// Time the host thread waited for this job list to finish.
uint64 GetWaitTimeMicroSec() const;
// Get the total time all units spent processing this job list.
uint64 GetTotalProcessingTimeMicroSec() const;
// Get the total time all units wasted while processing this job list.
uint64 GetTotalWastedTimeMicroSec() const;
// Time the given unit spent processing this job list.
uint64 GetUnitProcessingTimeMicroSec( int unit ) const;
// Time the given unit wasted while processing this job list.
uint64 GetUnitWastedTimeMicroSec( int unit ) const;
// Get the job list ID
jobListId_t GetId() const;
// Get the color for profiling.
const idColor * GetColor() const { return this->color; }
private:
class idParallelJobList_Threads * jobListThreads;
const idColor * color;
idParallelJobList( jobListId_t id, jobListPriority_t priority, unsigned int maxJobs, unsigned int maxSyncs, const idColor * color );
~idParallelJobList();
};
/*
================================================
idParallelJobManager
This is the only interface through which job lists
should be allocated or freed.
================================================
*/
class idParallelJobManager {
public:
virtual ~idParallelJobManager() {}
virtual void Init() = 0;
virtual void Shutdown() = 0;
virtual idParallelJobList * AllocJobList( jobListId_t id, jobListPriority_t priority, unsigned int maxJobs, unsigned int maxSyncs, const idColor * color ) = 0;
virtual void FreeJobList( idParallelJobList * jobList ) = 0;
virtual int GetNumJobLists() const = 0;
virtual int GetNumFreeJobLists() const = 0;
virtual idParallelJobList * GetJobList( int index ) = 0;
virtual int GetNumProcessingUnits() = 0;
virtual void WaitForAllJobLists() = 0;
};
extern idParallelJobManager * parallelJobManager;
// jobRun_t functions can have the debug name associated with them
// by explicitly calling this, or using the REGISTER_PARALLEL_JOB()
// static variable macro.
void RegisterJob( jobRun_t function, const char * name );
/*
================================================
idParallelJobRegistration
================================================
*/
class idParallelJobRegistration {
public:
idParallelJobRegistration( jobRun_t function, const char * name );
};
#define REGISTER_PARALLEL_JOB( function, name ) static idParallelJobRegistration register_##function( (jobRun_t) function, name )
#endif // !__PARALLELJOBLIST_H__

View File

@@ -0,0 +1,67 @@
/*
===========================================================================
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 __PARALLELJOBLIST_JOBHEADERS_H__
#define __PARALLELJOBLIST_JOBHEADERS_H__
/*
================================================================================================
Minimum set of headers needed to compile the code for a job.
================================================================================================
*/
#include "sys/sys_defines.h"
#include <stddef.h> // for offsetof
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <basetsd.h> // for UINT_PTR
#include <intrin.h>
#pragma warning( disable : 4100 ) // unreferenced formal parameter
#pragma warning( disable : 4127 ) // conditional expression is constant
#include "sys/sys_assert.h"
#include "sys/sys_types.h"
#include "sys/sys_intrinsics.h"
#include "math/Math.h"
#include "ParallelJobList.h"
#if _MSC_VER >= 1600
#undef NULL
#define NULL 0
#endif
#endif // !__PARALLELJOBLIST_JOBHEADERS_H__

3288
neo/idlib/Parser.cpp Normal file

File diff suppressed because it is too large Load Diff

284
neo/idlib/Parser.h Normal file
View File

@@ -0,0 +1,284 @@
/*
===========================================================================
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 __PARSER_H__
#define __PARSER_H__
/*
===============================================================================
C/C++ compatible pre-compiler
===============================================================================
*/
#define DEFINE_FIXED 0x0001
#define BUILTIN_LINE 1
#define BUILTIN_FILE 2
#define BUILTIN_DATE 3
#define BUILTIN_TIME 4
#define BUILTIN_STDC 5
#define INDENT_IF 0x0001
#define INDENT_ELSE 0x0002
#define INDENT_ELIF 0x0004
#define INDENT_IFDEF 0x0008
#define INDENT_IFNDEF 0x0010
// macro definitions
typedef struct define_s {
char * name; // define name
int flags; // define flags
int builtin; // > 0 if builtin define
int numparms; // number of define parameters
idToken * parms; // define parameters
idToken * tokens; // macro tokens (possibly containing parm tokens)
struct define_s *next; // next defined macro in a list
struct define_s *hashnext; // next define in the hash chain
} define_t;
// indents used for conditional compilation directives:
// #if, #else, #elif, #ifdef, #ifndef
typedef struct indent_s {
int type; // indent type
int skip; // true if skipping current indent
idLexer * script; // script the indent was in
struct indent_s *next; // next indent on the indent stack
} indent_t;
class idParser {
public:
// constructor
idParser();
idParser( int flags );
idParser( const char *filename, int flags = 0, bool OSPath = false );
idParser( const char *ptr, int length, const char *name, int flags = 0 );
// destructor
~idParser();
// load a source file
int LoadFile( const char *filename, bool OSPath = false );
// load a source from the given memory with the given length
// NOTE: the ptr is expected to point at a valid C string: ptr[length] == '\0'
int LoadMemory( const char *ptr, int length, const char *name );
// free the current source
void FreeSource( bool keepDefines = false );
// returns true if a source is loaded
int IsLoaded() const { return idParser::loaded; }
// read a token from the source
int ReadToken( idToken *token );
// expect a certain token, reads the token when available
int ExpectTokenString( const char *string );
// expect a certain token type
int ExpectTokenType( int type, int subtype, idToken *token );
// expect a token
int ExpectAnyToken( idToken *token );
// returns true if the next token equals the given string and removes the token from the source
int CheckTokenString( const char *string );
// returns true if the next token equals the given type and removes the token from the source
int CheckTokenType( int type, int subtype, idToken *token );
// returns true if the next token equals the given string but does not remove the token from the source
int PeekTokenString( const char *string );
// returns true if the next token equals the given type but does not remove the token from the source
int PeekTokenType( int type, int subtype, idToken *token );
// skip tokens until the given token string is read
int SkipUntilString( const char *string );
// skip the rest of the current line
int SkipRestOfLine();
// skip the braced section
int SkipBracedSection( bool parseFirstBrace = true );
// parse a braced section into a string
const char* ParseBracedSection( idStr& out, int tabs, bool parseFirstBrace, char intro, char outro );
// parse a braced section into a string, maintaining indents and newlines
const char * ParseBracedSectionExact( idStr &out, int tabs = -1 );
// parse the rest of the line
const char * ParseRestOfLine( idStr &out );
// unread the given token
void UnreadToken( idToken *token );
// read a token only if on the current line
int ReadTokenOnLine( idToken *token );
// read a signed integer
int ParseInt();
// read a boolean
bool ParseBool();
// read a floating point number
float ParseFloat();
// parse matrices with floats
int Parse1DMatrix( int x, float *m );
int Parse2DMatrix( int y, int x, float *m );
int Parse3DMatrix( int z, int y, int x, float *m );
// get the white space before the last read token
int GetLastWhiteSpace( idStr &whiteSpace ) const;
// Set a marker in the source file (there is only one marker)
void SetMarker();
// Get the string from the marker to the current position
void GetStringFromMarker( idStr& out, bool clean = false );
// add a define to the source
int AddDefine( const char *string );
// add builtin defines
void AddBuiltinDefines();
// set the source include path
void SetIncludePath( const char *path );
// set the punctuation set
void SetPunctuations( const punctuation_t *p );
// returns a pointer to the punctuation with the given id
const char * GetPunctuationFromId( int id );
// get the id for the given punctuation
int GetPunctuationId( const char *p );
// set lexer flags
void SetFlags( int flags );
// get lexer flags
int GetFlags() const;
// returns the current filename
const char * GetFileName() const;
// get current offset in current script
const int GetFileOffset() const;
// get file time for current script
const ID_TIME_T GetFileTime() const;
// returns the current line number
const int GetLineNum() const;
// print an error message
void Error( VERIFY_FORMAT_STRING const char *str, ... ) const;
// print a warning message
void Warning( VERIFY_FORMAT_STRING const char *str, ... ) const;
// returns true if at the end of the file
bool EndOfFile();
// add a global define that will be added to all opened sources
static int AddGlobalDefine( const char *string );
// remove the given global define
static int RemoveGlobalDefine( const char *name );
// remove all global defines
static void RemoveAllGlobalDefines();
// set the base folder to load files from
static void SetBaseFolder( const char *path );
private:
int loaded; // set when a source file is loaded from file or memory
idStr filename; // file name of the script
idStr includepath; // path to include files
bool OSPath; // true if the file was loaded from an OS path
const punctuation_t *punctuations; // punctuations to use
int flags; // flags used for script parsing
idLexer * scriptstack; // stack with scripts of the source
idToken * tokens; // tokens to read first
define_t * defines; // list with macro definitions
define_t ** definehash; // hash chain with defines
indent_t * indentstack; // stack with indents
int skip; // > 0 if skipping conditional code
const char* marker_p;
static define_t *globaldefines; // list with global defines added to every source loaded
private:
void PushIndent( int type, int skip );
void PopIndent( int *type, int *skip );
void PushScript( idLexer *script );
int ReadSourceToken( idToken *token );
int ReadLine( idToken *token );
int UnreadSourceToken( idToken *token );
int ReadDefineParms( define_t *define, idToken **parms, int maxparms );
int StringizeTokens( idToken *tokens, idToken *token );
int MergeTokens( idToken *t1, idToken *t2 );
int ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken );
int ExpandDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken );
int ExpandDefineIntoSource( idToken *deftoken, define_t *define );
void AddGlobalDefinesToSource();
define_t * CopyDefine( define_t *define );
define_t * FindHashedDefine(define_t **definehash, const char *name);
int FindDefineParm( define_t *define, const char *name );
void AddDefineToHash(define_t *define, define_t **definehash);
static void PrintDefine( define_t *define );
static void FreeDefine( define_t *define );
static define_t *FindDefine( define_t *defines, const char *name );
static define_t *DefineFromString( const char *string);
define_t * CopyFirstDefine();
int Directive_include();
int Directive_undef();
int Directive_if_def( int type );
int Directive_ifdef();
int Directive_ifndef();
int Directive_else();
int Directive_endif();
int EvaluateTokens( idToken *tokens, signed long int *intvalue, double *floatvalue, int integer );
int Evaluate( signed long int *intvalue, double *floatvalue, int integer );
int DollarEvaluate( signed long int *intvalue, double *floatvalue, int integer);
int Directive_define();
int Directive_elif();
int Directive_if();
int Directive_line();
int Directive_error();
int Directive_warning();
int Directive_pragma();
void UnreadSignToken();
int Directive_eval();
int Directive_evalfloat();
int ReadDirective();
int DollarDirective_evalint();
int DollarDirective_evalfloat();
int ReadDollarDirective();
};
ID_INLINE const char *idParser::GetFileName() const {
if ( idParser::scriptstack ) {
return idParser::scriptstack->GetFileName();
}
else {
return "";
}
}
ID_INLINE const int idParser::GetFileOffset() const {
if ( idParser::scriptstack ) {
return idParser::scriptstack->GetFileOffset();
}
else {
return 0;
}
}
ID_INLINE const ID_TIME_T idParser::GetFileTime() const {
if ( idParser::scriptstack ) {
return idParser::scriptstack->GetFileTime();
}
else {
return 0;
}
}
ID_INLINE const int idParser::GetLineNum() const {
if ( idParser::scriptstack ) {
return idParser::scriptstack->GetLineNum();
}
else {
return 0;
}
}
#endif /* !__PARSER_H__ */

171
neo/idlib/RectAllocator.cpp Normal file
View File

@@ -0,0 +1,171 @@
/*
===========================================================================
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"
/*
This routine performs a tight packing of a list of rectangles, attempting to minimize the area
of the rectangle that encloses all of them. Algorithm order is N^2, so it is not apropriate
for lists with many thousands of elements.
Contrast with idBitBlockAllocator, which is used incrementally with either fixed size or
size-doubling target areas.
Typical uses:
packing glyphs into a font image
packing model surfaces into a skin atlas
packing images into swf atlases
If you want a minimum alignment, ensure that all the sizes are multiples of that alignment,
or scale the input sizes down by that alignment and scale the outputPositions back up.
*/
float RectPackingFraction( const idList<idVec2i> &inputSizes, const idVec2i totalSize ) {
int totalArea = totalSize.Area();
if ( totalArea == 0 ) {
return 0;
}
int inputArea = 0;
for ( int i = 0 ; i < inputSizes.Num() ; i++ ) {
inputArea += inputSizes[i].Area();
}
return (float)inputArea / totalArea;
}
class idSortrects : public idSort_Quick< int, idSortrects > {
public:
int SizeMetric( idVec2i v ) const {
// skinny rects will sort earlier than square ones, because
// they are more likely to grow the entire region
return v.x * v.x + v.y * v.y;
}
int Compare( const int & a, const int & b ) const {
return SizeMetric( (*inputSizes)[b] ) - SizeMetric( (*inputSizes)[a] );
}
const idList<idVec2i> *inputSizes;
};
void RectAllocator( const idList<idVec2i> &inputSizes, idList<idVec2i> &outputPositions, idVec2i &totalSize ) {
outputPositions.SetNum( inputSizes.Num() );
if ( inputSizes.Num() == 0 ) {
totalSize.Set( 0, 0 );
return;
}
idList<int> sizeRemap;
sizeRemap.SetNum( inputSizes.Num() );
for ( int i = 0; i < inputSizes.Num(); i++ ) {
sizeRemap[i] = i;
}
// Sort the rects from largest to smallest (it makes allocating them in the image better)
idSortrects sortrectsBySize;
sortrectsBySize.inputSizes = &inputSizes;
sizeRemap.SortWithTemplate( sortrectsBySize );
// the largest rect goes to the top-left corner
outputPositions[sizeRemap[0]].Set( 0, 0 );
totalSize = inputSizes[sizeRemap[0]];
// For each image try to fit it at a corner of one of the already fitted images while
// minimizing the total area.
// Somewhat better allocation could be had by checking all the combinations of x and y edges
// in the allocated rectangles, rather than just the corners of each rectangle, but it
// still does a pretty good job.
static const int START_MAX = 1<<14;
for ( int i = 1; i < inputSizes.Num(); i++ ) {
idVec2i best( 0, 0 );
idVec2i bestMax( START_MAX, START_MAX );
idVec2i size = inputSizes[sizeRemap[i]];
for ( int j = 0; j < i; j++ ) {
for ( int k = 1; k < 4; k++ ) {
idVec2i test;
for ( int n = 0 ; n < 2 ; n++ ) {
test[n] = outputPositions[sizeRemap[j]][n] + ( ( k >> n ) & 1 ) * inputSizes[sizeRemap[j]][n];
}
idVec2i newMax;
for ( int n = 0 ; n < 2 ; n++ ) {
newMax[n] = Max( totalSize[n], test[n] + size[n] );
}
// widths must be multiples of 128 pixels / 32 DXT blocks to
// allow it to be used directly as a GPU texture without re-packing
// FIXME: make this a parameter
newMax[0] = (newMax[0]+31) & ~31;
// don't let an image get larger than 1024 DXT block, or PS3 crashes
// FIXME: pass maxSize in as a parameter
if ( newMax[0] > 1024 || newMax[1] > 1024 ) {
continue;
}
// if we have already found a spot that keeps the image smaller, don't bother checking here
// This calculation biases the rect towards more square shapes instead of
// allowing it to extend in one dimension for a long time.
int newSize = newMax.x * newMax.x + newMax.y * newMax.y;
int bestSize = bestMax.x * bestMax.x + bestMax.y * bestMax.y;
if ( newSize > bestSize ) {
continue;
}
// if the image isn't required to grow, favor the location closest to the origin
if ( newSize == bestSize && best.x + best.y < test.x + test.y ) {
continue;
}
// see if this spot overlaps any already allocated rect
int n = 0;
for ( ; n < i; n++ ) {
const idVec2i &check = outputPositions[sizeRemap[n]];
const idVec2i &checkSize = inputSizes[sizeRemap[n]];
if ( test.x + size.x > check.x &&
test.y + size.y > check.y &&
test.x < check.x + checkSize.x &&
test.y < check.y + checkSize.y ) {
break;
}
}
if ( n < i ) {
// overlapped, can't use
continue;
}
best = test;
bestMax = newMax;
}
}
if ( bestMax[0] == START_MAX ) { // FIXME: return an error code
idLib::FatalError( "RectAllocator: couldn't fit everything" );
}
outputPositions[sizeRemap[i]] = best;
totalSize = bestMax;
}
}

View File

@@ -0,0 +1,47 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "ParallelJobList_JobHeaders.h"
/*
================================================================================================
Software Cache
================================================================================================
*/
uint32 globalDmaTag;
bool SpursEmulationAssertFailed( const char *filename, int line, const char *expression ) {
static bool halt = true;
if ( halt ) {
__debugbreak();
}
return true;
}

513
neo/idlib/SoftwareCache.h Normal file
View File

@@ -0,0 +1,513 @@
/*
===========================================================================
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 __SOFTWARECACHE_H__
#define __SOFTWARECACHE_H__
#pragma warning( disable : 4324 ) // structure was padded due to __declspec(align())
/*
================================================================================================
On-Demand Streamed Objects and Arrays
idODSObject // DMA in a single object
idODSCachedObject // DMA in a single object through a software cache
idODSArray // DMA in an array with objects
idODSIndexedArray // DMA gather from an array with objects
idODSStreamedArray // overlapped DMA streaming of an array with objects
idODSStreamedIndexedArray // overlapped DMA gather from an array with objects
On the SPU the 'idODSObject' streams the data into temporary memory using the DMA controller
and the object constructor immediately waits for the DMA transfer to complete. In other words
there is no caching and every random memory access incurs full memory latency. This should be
used to stream in objects that are only used once at unpredictable times.
The 'idODSCachedObject' uses an object based software cache on the SPU which is useful for
streaming in objects that may be used repeatedly or which usage can be predicted allowing
the objects to be prefetched.
class idMyType {};
class idMyCache : public idSoftwareCache< idMyType, 8, 4 > {};
idMyCache myCache;
idMyType * myPtr;
idODSCachedObject< idMyType, idMyCache > myODS( myPtr, myCache );
The 'idSoftwareCache' implements a Prefetch() function that can be used to prefetch whole
objects into the cache well before they are needed. However, any idODSObject, idODSArray,
idODSIndexedArray etc. after calling the Prefetch() function will have to wait for the
prefetch to complete. In other words, make sure there is enough "work" done in between
a Prefetch() call and the first next idODS* object.
The 'idODSArray' streams in a block of objects that are tightly packed in memory.
The 'idODSIndexedArray' is used to gather a number of objects that are not necessarily
contiguous in memory. On the SPU a DMA-list is used in the 'idODSIndexedArray' constructor
to efficiently gather all the objects.
The 'idODSStreamedArray' is used for sequentially reading a large input array. Overlapped
streaming is used where one batch of array elements can be accessed while the next batch
is being streamed in.
The 'idODSStreamedIndexedArray' is used for gathering elements from an array using a
sequentially read index. Overlapped streaming is used for both the index and the array
elements where one batch of array elements can be accessed while the next batch of
indices/array elements is being streamed in.
Outside the SPU, data is never copied to temporary memory because this would cause
significant load-hit-store penalties. Instead, the object constructor issues prefetch
instructions where appropriate and only maintains pointers to the actual data. In the
case of 'idODSObject' or 'idODSCachedObject' the class is no more than a simple wrapper
of a pointer and the class should completely compile away with zero overhead.
COMMON MISTAKES:
1. When using ODS objects do not forget to set the "globalDmaTag" that is used to issue
and wait for DMAs.
void cellSpursJobMain2( CellSpursJobContext2 * stInfo, CellSpursJob256 * job ) {
globalDmaTag = stInfo->dmaTag; // for ODS objects
}
2. ODS objects can consume quite a bit of stack space. You may have to increase the SPU job
stack size. For instance:
job->header.sizeStack = SPURS_QUADWORDS( 16 * 1024 ); // the ODS objects get pretty large
Make sure you measure the size of each ODS object and if there are recursive functions
using ODS objects make sure the recursion is bounded. When the stack overflows the scratch
and output memory may get overwritten and the results will be undefined. Finding stack
overflows is painful.
3. While you can setup a regular DMA list entry to use a NULL pointer with zero size, do not use
a NULL pointer for a cache DMA list entry. This confuses SPURS and can cause your SPU binary
to get corrupted.
================================================================================================
*/
extern uint32 globalDmaTag;
#define MAX_DMA_SIZE ( 1 << 14 )
#define ODS_ROUND16( x ) ( ( x + 15 ) & ~15 )
enum streamBufferType_t {
SBT_DOUBLE = 2,
SBT_QUAD = 4
};
/*
================================================================================================
non-SPU code
================================================================================================
*/
/*
================================================
idSoftwareCache
================================================
*/
template< typename _type_, int _entries_ = 8, int _associativity_ = 4, bool aligned = false >
class ALIGNTYPE128 idSoftwareCache {
public:
void Prefetch( const _type_ * obj ) {
::Prefetch( obj, 0 );
}
};
/*
================================================
idODSObject
================================================
*/
template< typename _type_ >
class idODSObject {
public:
idODSObject( const _type_ * obj ) : objectPtr( obj ) {}
operator const _type_ & () const { return *objectPtr; }
const _type_ * operator->() const { return objectPtr; }
const _type_ & Get() const { return *objectPtr; }
const _type_ * Ptr() const { return objectPtr; }
const _type_ * OriginalPtr() const { return objectPtr; }
private:
const _type_ * objectPtr;
};
/*
================================================
idODSCachedObject
================================================
*/
template< typename _type_, typename _cache_ >
class idODSCachedObject {
public:
idODSCachedObject( const _type_ * obj, _cache_ & cache ) : objectPtr( obj ) {}
operator const _type_ & () const { return *objectPtr; }
const _type_ * operator->() const { return objectPtr; }
const _type_ & Get() const { return *objectPtr; }
const _type_ * Ptr() const { return objectPtr; }
const _type_ * OriginalPtr() const { return objectPtr; }
private:
const _type_ * objectPtr;
};
/*
================================================
idODSArray
================================================
*/
template< typename _type_, int max >
class idODSArray {
public:
idODSArray( const _type_ * array, int num ) : arrayPtr( array ), arrayNum( num ) {
assert( num <= max );
Prefetch( array, 0 );
}
const _type_ & operator[]( int index ) const {
assert( index >= 0 && index < arrayNum );
return arrayPtr[index];
}
const _type_ * Ptr() const { return arrayPtr; }
const int Num() const { return arrayNum; }
private:
const _type_ * arrayPtr;
int arrayNum;
};
/*
================================================
idODSIndexedArray
================================================
*/
template< typename _elemType_, typename _indexType_, int max >
class idODSIndexedArray {
public:
idODSIndexedArray( const _elemType_ * array, const _indexType_ * index, int num ) : arrayNum( num ) {
assert( num <= max );
for ( int i = 0; i < num; i++ ) {
Prefetch( arrayPtr, abs( index[i] ) * sizeof( _elemType_ ) );
arrayPtr[i] = array + abs( index[i] );
}
}
const _elemType_ & operator[]( int index ) const {
assert( index >= 0 && index < arrayNum );
return * arrayPtr[index];
}
void ReplicateUpToMultipleOfFour() {
assert( ( max & 3 ) == 0 );
while( ( arrayNum & 3 ) != 0 ) {
arrayPtr[arrayNum++] = arrayPtr[0];
}
}
private:
const _elemType_ * arrayPtr[max];
int arrayNum;
};
/*
================================================
idODSStreamedOutputArray
================================================
*/
template< typename _type_, int _bufferSize_ >
class ALIGNTYPE16 idODSStreamedOutputArray {
public:
idODSStreamedOutputArray( _type_ * array, int * numElements, int maxElements ) :
localNum( 0 ),
outArray( array ),
outNum( numElements ),
outMax( maxElements ) {
compile_time_assert( CONST_ISPOWEROFTWO( _bufferSize_ ) );
compile_time_assert( ( ( _bufferSize_ * sizeof( _type_ ) ) & 15 ) == 0 );
compile_time_assert( _bufferSize_ * sizeof( _type_ ) < MAX_DMA_SIZE );
assert_16_byte_aligned( array );
}
~idODSStreamedOutputArray() {
*outNum = localNum;
}
int Num() const { return localNum; }
void Append( _type_ element ) { assert( localNum < outMax ); outArray[localNum++] = element; }
_type_ & Alloc() { assert( localNum < outMax ); return outArray[localNum++]; }
private:
int localNum;
_type_ * outArray;
int * outNum;
int outMax;
};
/*
================================================
idODSStreamedArray
================================================
*/
template< typename _type_, int _bufferSize_, streamBufferType_t _sbt_ = SBT_DOUBLE, int _roundUpToMultiple_ = 1 >
class ALIGNTYPE16 idODSStreamedArray {
public:
idODSStreamedArray( const _type_ * array, const int numElements ) :
cachedArrayStart( 0 ),
cachedArrayEnd( 0 ),
streamArrayEnd( 0 ),
inArray( array ),
inArrayNum( numElements ),
inArrayNumRoundedUp( numElements ) {
compile_time_assert( CONST_ISPOWEROFTWO( _bufferSize_ ) );
compile_time_assert( ( ( _bufferSize_ * sizeof( _type_ ) ) & 15 ) == 0 );
compile_time_assert( _bufferSize_ * sizeof( _type_ ) < MAX_DMA_SIZE );
compile_time_assert( _roundUpToMultiple_ >= 1 );
assert_16_byte_aligned( array );
assert( (uintptr_t)array > _bufferSize_ * sizeof( _type_ ) );
// Fetch the first batch of elements.
FetchNextBatch();
// Calculate the rounded up size here making the mod effectively for free because we have to wait
// for memory access anyway while the above FetchNextBatch() does not need the rounded up size yet.
inArrayNumRoundedUp += _roundUpToMultiple_ - 1;
inArrayNumRoundedUp -= inArrayNumRoundedUp % ( ( _roundUpToMultiple_ > 1 ) ? _roundUpToMultiple_ : 1 );
}
~idODSStreamedArray() {
// Flush the accessible part of the array.
FlushArray( inArray, cachedArrayStart * sizeof( _type_ ), cachedArrayEnd * sizeof( _type_ ) );
}
// Fetches a new batch of array elements and returns the first index after this new batch.
// After calling this, the elements starting at the index returned by the previous call to
// FetchNextBach() (or zero if not yet called) up to (excluding) the index returned by
// this call to FetchNextBatch() can be accessed through the [] operator. When quad-buffering,
// the elements starting at the index returned by the second-from-last call to FetchNextBatch()
// can still be accessed. This is useful when the algorithm needs to successively access
// an odd number of elements at the same time that may cross a single buffer boundary.
int FetchNextBatch() {
// If not everything has been streamed already.
if ( cachedArrayEnd < inArrayNum ) {
cachedArrayEnd = streamArrayEnd;
cachedArrayStart = Max( cachedArrayEnd - _bufferSize_ * ( _sbt_ - 1 ), 0 );
// Flush the last batch of elements that is no longer accessible.
FlushArray( inArray, ( cachedArrayStart - _bufferSize_ ) * sizeof( _type_ ), cachedArrayStart * sizeof( _type_ ) );
// Prefetch the next batch of elements.
if ( streamArrayEnd < inArrayNum ) {
streamArrayEnd = Min( streamArrayEnd + _bufferSize_, inArrayNum );
for ( unsigned int offset = cachedArrayEnd * sizeof( _type_ ); offset < streamArrayEnd * sizeof( _type_ ); offset += CACHE_LINE_SIZE ) {
Prefetch( inArray, offset );
}
}
}
return ( cachedArrayEnd == inArrayNum ) ? inArrayNumRoundedUp : cachedArrayEnd;
}
// Provides access to the elements starting at the index returned by the next-to-last call
// to FetchNextBach() (or zero if only called once so far) up to (excluding) the index
// returned by the last call to FetchNextBatch(). When quad-buffering, the elements starting
// at the index returned by the second-from-last call to FetchNextBatch() can still be accessed.
// This is useful when the algorithm needs to successively access an odd number of elements
// at the same time that may cross a single buffer boundary.
const _type_ & operator[]( int index ) const {
assert( ( index >= cachedArrayStart && index < cachedArrayEnd ) || ( cachedArrayEnd == inArrayNum && index >= inArrayNum && index < inArrayNumRoundedUp ) );
if ( _roundUpToMultiple_ > 1 ) {
index &= ( index - inArrayNum ) >> 31;
}
return inArray[index];
}
private:
int cachedArrayStart;
int cachedArrayEnd;
int streamArrayEnd;
const _type_ * inArray;
int inArrayNum;
int inArrayNumRoundedUp;
static void FlushArray( const void * flushArray, int flushStart, int flushEnd ) {
#if 0
// arrayFlushBase is rounded up so we do not flush anything before the array.
// arrayFlushStart is rounded down so we start right after the last cache line that was previously flushed.
// arrayFlushEnd is rounded down so we do not flush a cache line that holds data that may still be partially
// accessible or a cache line that stretches beyond the end of the array.
const uintptr_t arrayAddress = (uintptr_t)flushArray;
const uintptr_t arrayFlushBase = ( arrayAddress + CACHE_LINE_SIZE - 1 ) & ~( CACHE_LINE_SIZE - 1 );
const uintptr_t arrayFlushStart = ( arrayAddress + flushStart ) & ~( CACHE_LINE_SIZE - 1 );
const uintptr_t arrayFlushEnd = ( arrayAddress + flushEnd ) & ~( CACHE_LINE_SIZE - 1 );
for ( uintptr_t offset = Max( arrayFlushBase, arrayFlushStart ); offset < arrayFlushEnd; offset += CACHE_LINE_SIZE ) {
FlushCacheLine( flushArray, offset - arrayAddress );
}
#endif
}
};
/*
================================================
idODSStreamedIndexedArray
For gathering elements from an array using a sequentially read index.
This uses overlapped streaming for both the index and the array elements
where one batch of indices and/or array elements can be accessed while
the next batch is being streamed in.
NOTE: currently the size of array elements must be a multiple of 16 bytes.
An index with offsets and more complex logic is needed to support other sizes.
================================================
*/
template< typename _elemType_, typename _indexType_, int _bufferSize_, streamBufferType_t _sbt_ = SBT_DOUBLE, int _roundUpToMultiple_ = 1 >
class ALIGNTYPE16 idODSStreamedIndexedArray {
public:
idODSStreamedIndexedArray( const _elemType_ * array, const int numElements, const _indexType_ * index, const int numIndices ) :
cachedArrayStart( 0 ),
cachedArrayEnd( 0 ),
streamArrayEnd( 0 ),
cachedIndexStart( 0 ),
cachedIndexEnd( 0 ),
streamIndexEnd( 0 ),
inArray( array ),
inArrayNum( numElements ),
inIndex( index ),
inIndexNum( numIndices ),
inIndexNumRoundedUp( numIndices ) {
compile_time_assert( CONST_ISPOWEROFTWO( _bufferSize_ ) );
compile_time_assert( ( ( _bufferSize_ * sizeof( _indexType_ ) ) & 15 ) == 0 );
compile_time_assert( _bufferSize_ * sizeof( _indexType_ ) < MAX_DMA_SIZE );
compile_time_assert( _bufferSize_ * sizeof( _elemType_ ) < MAX_DMA_SIZE );
compile_time_assert( ( sizeof( _elemType_ ) & 15 ) == 0 ); // to avoid complexity due to cellDmaListGet
compile_time_assert( _roundUpToMultiple_ >= 1 );
assert_16_byte_aligned( index );
assert_16_byte_aligned( array );
assert( (uintptr_t)index > _bufferSize_ * sizeof( _indexType_ ) );
assert( (uintptr_t)array > _bufferSize_ * sizeof( _elemType_ ) );
// Fetch the first batch of indices.
FetchNextBatch();
// Fetch the first batch of elements and the next batch of indices.
FetchNextBatch();
// Calculate the rounded up size here making the mod effectively for free because we have to wait
// for memory access anyway while the above FetchNextBatch() do not need the rounded up size yet.
inIndexNumRoundedUp += _roundUpToMultiple_ - 1;
inIndexNumRoundedUp -= inIndexNumRoundedUp % ( ( _roundUpToMultiple_ > 1 ) ? _roundUpToMultiple_ : 1 );
}
~idODSStreamedIndexedArray() {
// Flush the accessible part of the index.
FlushArray( inIndex, cachedIndexStart * sizeof( _indexType_ ), cachedIndexEnd * sizeof( _indexType_ ) );
// Flush the accessible part of the array.
FlushArray( inArray, cachedArrayStart * sizeof( _elemType_ ), cachedArrayEnd * sizeof( _elemType_ ) );
}
// Fetches a new batch of array elements and returns the first index after this new batch.
// After calling this, the elements starting at the index returned by the previous call to
// FetchNextBach() (or zero if not yet called) up to (excluding) the index returned by
// this call to FetchNextBatch() can be accessed through the [] operator. When quad-buffering,
// the elements starting at the index returned by the second-from-last call to FetchNextBatch()
// can still be accessed. This is useful when the algorithm needs to successively access
// an odd number of elements at the same time that may cross a single buffer boundary.
int FetchNextBatch() {
// If not everything has been streamed already.
if ( cachedArrayEnd < inIndexNum ) {
if ( streamIndexEnd > 0 ) {
cachedArrayEnd = streamArrayEnd;
cachedArrayStart = Max( cachedArrayEnd - _bufferSize_ * ( _sbt_ - 1 ), 0 );
cachedIndexEnd = streamIndexEnd;
cachedIndexStart = Max( cachedIndexEnd - _bufferSize_ * ( _sbt_ - 1 ), 0 );
// Flush the last batch of indices that are no longer accessible.
FlushArray( inIndex, ( cachedIndexStart - _bufferSize_ ) * sizeof( _indexType_ ), cachedIndexStart * sizeof( _indexType_ ) );
// Flush the last batch of elements that is no longer accessible.
FlushArray( inArray, ( cachedArrayStart - _bufferSize_ ) * sizeof( _elemType_ ), cachedArrayStart * sizeof( _elemType_ ) );
// Prefetch the next batch of elements.
if ( streamArrayEnd < inIndexNum ) {
streamArrayEnd = cachedIndexEnd;
for ( int i = cachedArrayEnd; i < streamArrayEnd; i++ ) {
assert( i >= cachedIndexStart && i < cachedIndexEnd );
assert( inIndex[i] >= 0 && inIndex[i] < inArrayNum );
Prefetch( inArray, inIndex[i] * sizeof( _elemType_ ) );
}
}
}
// Prefetch the next batch of indices.
if ( streamIndexEnd < inIndexNum ) {
streamIndexEnd = Min( streamIndexEnd + _bufferSize_, inIndexNum );
for ( unsigned int offset = cachedIndexEnd * sizeof( _indexType_ ); offset < streamIndexEnd * sizeof( _indexType_ ); offset += CACHE_LINE_SIZE ) {
Prefetch( inIndex, offset );
}
}
}
return ( cachedArrayEnd == inIndexNum ) ? inIndexNumRoundedUp : cachedArrayEnd;
}
// Provides access to the elements starting at the index returned by the next-to-last call
// to FetchNextBach() (or zero if only called once so far) up to (excluding) the index
// returned by the last call to FetchNextBatch(). When quad-buffering, the elements starting
// at the index returned by the second-from-last call to FetchNextBatch() can still be accessed.
// This is useful when the algorithm needs to successively access an odd number of elements
// at the same time that may cross a single buffer boundary.
const _elemType_ & operator[]( int index ) const {
assert( ( index >= cachedArrayStart && index < cachedArrayEnd ) || ( cachedArrayEnd == inIndexNum && index >= inIndexNum && index < inIndexNumRoundedUp ) );
if ( _roundUpToMultiple_ > 1 ) {
index &= ( index - inIndexNum ) >> 31;
}
return inArray[inIndex[index]];
}
private:
int cachedArrayStart;
int cachedArrayEnd;
int streamArrayEnd;
int cachedIndexStart;
int cachedIndexEnd;
int streamIndexEnd;
const _elemType_ * inArray;
int inArrayNum;
const _indexType_ * inIndex;
int inIndexNum;
int inIndexNumRoundedUp;
static void FlushArray( const void * flushArray, int flushStart, int flushEnd ) {
#if 0
// arrayFlushBase is rounded up so we do not flush anything before the array.
// arrayFlushStart is rounded down so we start right after the last cache line that was previously flushed.
// arrayFlushEnd is rounded down so we do not flush a cache line that holds data that may still be partially
// accessible or a cache line that stretches beyond the end of the array.
const uintptr_t arrayAddress = (uintptr_t)flushArray;
const uintptr_t arrayFlushBase = ( arrayAddress + CACHE_LINE_SIZE - 1 ) & ~( CACHE_LINE_SIZE - 1 );
const uintptr_t arrayFlushStart = ( arrayAddress + flushStart ) & ~( CACHE_LINE_SIZE - 1 );
const uintptr_t arrayFlushEnd = ( arrayAddress + flushEnd ) & ~( CACHE_LINE_SIZE - 1 );
for ( uintptr_t offset = Max( arrayFlushBase, arrayFlushStart ); offset < arrayFlushEnd; offset += CACHE_LINE_SIZE ) {
FlushCacheLine( flushArray, offset - arrayAddress );
}
#endif
}
};
#endif // !__SOFTWARECACHE_H__

2090
neo/idlib/Str.cpp Normal file

File diff suppressed because it is too large Load Diff

1215
neo/idlib/Str.h Normal file

File diff suppressed because it is too large Load Diff

125
neo/idlib/StrStatic.h Normal file
View File

@@ -0,0 +1,125 @@
/*
===========================================================================
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 __STRSTATIC_H__
#define __STRSTATIC_H__
/*
================================================
idStrStatic
================================================
*/
template< int _size_ >
class idStrStatic : public idStr {
public:
ID_INLINE void operator=( const idStrStatic &text ) {
// we should only get here when the types, including the size, are identical
len = text.Length();
memcpy( data, text.data, len+1 );
}
// all idStr operators are overloaded and the idStr default constructor is called so that the
// static buffer can be initialized in the body of the constructor before the data is ever
// copied.
ID_INLINE idStrStatic() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
}
ID_INLINE idStrStatic( const idStrStatic & text ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( text );
}
ID_INLINE idStrStatic( const idStr & text ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( text );
}
ID_INLINE idStrStatic( const idStrStatic & text, int start, int end ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
CopyRange( text.c_str(), start, end );
}
ID_INLINE idStrStatic( const char * text ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( text );
}
ID_INLINE idStrStatic( const char * text, int start, int end ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
CopyRange( text, start, end );
}
ID_INLINE explicit idStrStatic( const bool b ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( b );
}
ID_INLINE explicit idStrStatic( const char c ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( c );
}
ID_INLINE explicit idStrStatic( const int i ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( i );
}
ID_INLINE explicit idStrStatic( const unsigned u ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( u );
}
ID_INLINE explicit idStrStatic( const float f ) :
idStr() {
buffer[ 0 ] = '\0';
SetStaticBuffer( buffer, _size_ );
idStr::operator=( f );
}
private:
char buffer[ _size_ ];
};
#endif // __STRSTATIC_H__

223
neo/idlib/Swap.h Normal file
View 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.
===========================================================================
*/
#ifndef __SWAP_H__
#define __SWAP_H__
/*
================================================================================================
Contains the Swap class, for CrossPlatform endian conversion.
works
================================================================================================
*/
/*
========================
IsPointer
========================
*/
template< typename type >
bool IsPointer( type ) {
return false;
}
/*
========================
IsPointer
========================
*/
template< typename type >
bool IsPointer( type * ) {
return true;
}
/*
================================================
The *Swap* static template class, idSwap, is used by the SwapClass template class for
performing EndianSwapping.
================================================
*/
class idSwap {
public:
//#define SwapBytes( x, y ) (x) ^= (y) ^= (x) ^= (y)
#define SwapBytes( x, y ) { byte t = (x); (x) = (y); (y) = t; }
template<class type> static void Little( type &c ) {
// byte swapping pointers is pointless because we should never store pointers on disk
assert( !IsPointer( c ) );
}
template<class type> static void Big( type &c ) {
// byte swapping pointers is pointless because we should never store pointers on disk
assert( !IsPointer( c ) );
if ( sizeof( type ) == 1 ) {
} else if ( sizeof( type ) == 2 ) {
byte *b = (byte *)&c;
SwapBytes( b[0], b[1] );
} else if ( sizeof( type ) == 4 ) {
byte *b = (byte *)&c;
SwapBytes( b[0], b[3] );
SwapBytes( b[1], b[2] );
} else if ( sizeof( type ) == 8 ) {
byte * b = (byte *)&c;
SwapBytes( b[0], b[7] );
SwapBytes( b[1], b[6]);
SwapBytes( b[2], b[5] );
SwapBytes( b[3], b[4] );
} else {
assert( false );
}
}
template<class type> static void LittleArray( type *c, int count ) {
}
template<class type> static void BigArray( type *c, int count ) {
for ( int i = 0; i < count; i++ ) {
Big( c[i] );
}
}
static void SixtetsForInt( byte *out, int src ) {
byte *b = (byte *)&src;
out[0] = ( b[0] & 0xfc ) >> 2;
out[1] = ( ( b[0] & 0x3 ) << 4 ) + ( ( b[1] & 0xf0 ) >> 4 );
out[2] = ( ( b[1] & 0xf ) << 2 ) + ( ( b[2] & 0xc0 ) >> 6 );
out[3] = b[2] & 0x3f;
}
static int IntForSixtets( byte *in ) {
int ret = 0;
byte *b = (byte *)&ret;
b[0] |= in[0] << 2;
b[0] |= ( in[1] & 0x30 ) >> 4;
b[1] |= ( in[1] & 0xf ) << 4;
b[1] |= ( in[2] & 0x3c ) >> 2;
b[2] |= ( in[2] & 0x3 ) << 6;
b[2] |= in[3];
return ret;
}
public: // specializations
#ifndef ID_SWAP_LITE // avoid dependency avalanche for SPU code
#define SWAP_VECTOR( x ) \
static void Little( x &c ) { LittleArray( c.ToFloatPtr(), c.GetDimension() ); } \
static void Big( x &c ) { BigArray( c.ToFloatPtr(), c.GetDimension() ); }
SWAP_VECTOR( idVec2 );
SWAP_VECTOR( idVec3 );
SWAP_VECTOR( idVec4 );
SWAP_VECTOR( idVec5 );
SWAP_VECTOR( idVec6 );
SWAP_VECTOR( idMat2 );
SWAP_VECTOR( idMat3 );
SWAP_VECTOR( idMat4 );
SWAP_VECTOR( idMat5 );
SWAP_VECTOR( idMat6 );
SWAP_VECTOR( idPlane );
SWAP_VECTOR( idQuat );
SWAP_VECTOR( idCQuat );
SWAP_VECTOR( idAngles );
SWAP_VECTOR( idBounds );
static void Little( idDrawVert &v ) {
Little( v.xyz );
LittleArray( v.st, 2 );
LittleArray( v.normal, 4 );
LittleArray( v.tangent, 4 );
LittleArray( v.color, 4 );
}
static void Big( idDrawVert &v ) {
Big( v.xyz );
BigArray( v.st, 2 );
BigArray( v.normal, 4 );
BigArray( v.tangent, 4 );
BigArray( v.color, 4 );
}
#endif
};
/*
================================================
idSwapClass is a template class for performing EndianSwapping.
================================================
*/
template<class classType>
class idSwapClass {
public:
idSwapClass() {
#ifdef _DEBUG
size = 0;
#endif
}
~idSwapClass() {
#ifdef _DEBUG
assert( size == sizeof( classType ) );
#endif
}
template<class type> void Little( type &c ) {
idSwap::Little( c );
#ifdef _DEBUG
size += sizeof( type );
#endif
}
template<class type> void Big( type &c ) {
idSwap::Big( c );
#ifdef _DEBUG
size += sizeof( type );
#endif
}
template<class type> void LittleArray( type *c, int count ) {
idSwap::LittleArray( c, count );
#ifdef _DEBUG
size += count * sizeof( type );
#endif
}
template<class type> void BigArray( type *c, int count ) {
idSwap::BigArray( c, count );
#ifdef _DEBUG
size += count * sizeof( type );
#endif
}
#ifdef _DEBUG
private:
int size;
#endif
};
#define BIG32(v) ((((uint32)(v)) >> 24) | (((uint32)(v) & 0x00FF0000) >> 8) | (((uint32)(v) & 0x0000FF00) << 8) | ((uint32)(v) << 24))
#define BIG16(v) ((((uint16)(v)) >> 8) | ((uint16)(v) << 8))
#endif // !__SWAP_H__

283
neo/idlib/Thread.cpp Normal file
View File

@@ -0,0 +1,283 @@
/*
===========================================================================
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"
/*
================================================================================================
Contains the vartious ThreadingClass implementations.
================================================================================================
*/
/*
================================================================================================
idSysThread
================================================================================================
*/
/*
========================
idSysThread::idSysThread
========================
*/
idSysThread::idSysThread() :
threadHandle( 0 ),
isWorker( false ),
isRunning( false ),
isTerminating( false ),
moreWorkToDo( false ),
signalWorkerDone( true ) {
}
/*
========================
idSysThread::~idSysThread
========================
*/
idSysThread::~idSysThread() {
StopThread( true );
if ( threadHandle ) {
Sys_DestroyThread( threadHandle );
}
}
/*
========================
idSysThread::StartThread
========================
*/
bool idSysThread::StartThread( const char * name_, core_t core, xthreadPriority priority, int stackSize ) {
if ( isRunning ) {
return false;
}
name = name_;
isTerminating = false;
if ( threadHandle ) {
Sys_DestroyThread( threadHandle );
}
threadHandle = Sys_CreateThread( (xthread_t)ThreadProc, this, priority, name, core, stackSize, false );
isRunning = true;
return true;
}
/*
========================
idSysThread::StartWorkerThread
========================
*/
bool idSysThread::StartWorkerThread( const char * name_, core_t core, xthreadPriority priority, int stackSize ) {
if ( isRunning ) {
return false;
}
isWorker = true;
bool result = StartThread( name_, core, priority, stackSize );
signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE );
return result;
}
/*
========================
idSysThread::StopThread
========================
*/
void idSysThread::StopThread( bool wait ) {
if ( !isRunning ) {
return;
}
if ( isWorker ) {
signalMutex.Lock();
moreWorkToDo = true;
signalWorkerDone.Clear();
isTerminating = true;
signalMoreWorkToDo.Raise();
signalMutex.Unlock();
} else {
isTerminating = true;
}
if ( wait ) {
WaitForThread();
}
}
/*
========================
idSysThread::WaitForThread
========================
*/
void idSysThread::WaitForThread() {
if ( isWorker ) {
signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE );
} else if ( isRunning ) {
Sys_DestroyThread( threadHandle );
threadHandle = 0;
}
}
/*
========================
idSysThread::SignalWork
========================
*/
void idSysThread::SignalWork() {
if ( isWorker ) {
signalMutex.Lock();
moreWorkToDo = true;
signalWorkerDone.Clear();
signalMoreWorkToDo.Raise();
signalMutex.Unlock();
}
}
/*
========================
idSysThread::IsWorkDone
========================
*/
bool idSysThread::IsWorkDone() {
if ( isWorker ) {
// a timeout of 0 will return immediately with true if signaled
if ( signalWorkerDone.Wait( 0 ) ) {
return true;
}
}
return false;
}
/*
========================
idSysThread::ThreadProc
========================
*/
int idSysThread::ThreadProc( idSysThread * thread ) {
int retVal = 0;
try {
if ( thread->isWorker ) {
for( ; ; ) {
thread->signalMutex.Lock();
if ( thread->moreWorkToDo ) {
thread->moreWorkToDo = false;
thread->signalMoreWorkToDo.Clear();
thread->signalMutex.Unlock();
} else {
thread->signalWorkerDone.Raise();
thread->signalMutex.Unlock();
thread->signalMoreWorkToDo.Wait( idSysSignal::WAIT_INFINITE );
continue;
}
if ( thread->isTerminating ) {
break;
}
retVal = thread->Run();
}
thread->signalWorkerDone.Raise();
} else {
retVal = thread->Run();
}
} catch ( idException & ex ) {
idLib::Warning( "Fatal error in thread %s: %s", thread->GetName(), ex.GetError() );
// We don't handle threads terminating unexpectedly very well, so just terminate the whole process
_exit( 0 );
}
thread->isRunning = false;
return retVal;
}
/*
========================
idSysThread::Run
========================
*/
int idSysThread::Run() {
// The Run() is not pure virtual because on destruction of a derived class
// the virtual function pointer will be set to NULL before the idSysThread
// destructor actually stops the thread.
return 0;
}
/*
================================================================================================
test
================================================================================================
*/
/*
================================================
idMyThread test class.
================================================
*/
class idMyThread : public idSysThread {
public:
virtual int Run() {
// run threaded code here
return 0;
}
// specify thread data here
};
/*
========================
TestThread
========================
*/
void TestThread() {
idMyThread thread;
thread.StartThread( "myThread", CORE_ANY );
}
/*
========================
TestWorkers
========================
*/
void TestWorkers() {
idSysWorkerThreadGroup<idMyThread> workers( "myWorkers", 4 );
for ( ; ; ) {
for ( int i = 0; i < workers.GetNumThreads(); i++ ) {
// workers.GetThread( i )-> // setup work for this thread
}
workers.SignalWorkAndWait();
}
}

465
neo/idlib/Thread.h Normal file
View File

@@ -0,0 +1,465 @@
/*
===========================================================================
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 __THREAD_H__
#define __THREAD_H__
/*
================================================
idSysMutex provides a C++ wrapper to the low level system mutex functions. A mutex is an
object that can only be locked by one thread at a time. It's used to prevent two threads
from accessing the same piece of data simultaneously.
================================================
*/
class idSysMutex {
public:
idSysMutex() { Sys_MutexCreate( handle ); }
~idSysMutex() { Sys_MutexDestroy( handle ); }
bool Lock( bool blocking = true ) { return Sys_MutexLock( handle, blocking ); }
void Unlock() { Sys_MutexUnlock( handle ); }
private:
mutexHandle_t handle;
idSysMutex( const idSysMutex & s ) {}
void operator=( const idSysMutex & s ) {}
};
/*
================================================
idScopedCriticalSection is a helper class that automagically locks a mutex when it's created
and unlocks it when it goes out of scope.
================================================
*/
class idScopedCriticalSection {
public:
idScopedCriticalSection( idSysMutex & m ) : mutex(&m) { mutex->Lock(); }
~idScopedCriticalSection() { mutex->Unlock(); }
private:
idSysMutex * mutex; // NOTE: making this a reference causes a TypeInfo crash
};
/*
================================================
idSysSignal is a C++ wrapper for the low level system signal functions. A signal is an object
that a thread can wait on for it to be raised. It's used to indicate data is available or that
a thread has reached a specific point.
================================================
*/
class idSysSignal {
public:
static const int WAIT_INFINITE = -1;
idSysSignal( bool manualReset = false ) { Sys_SignalCreate( handle, manualReset ); }
~idSysSignal() { Sys_SignalDestroy( handle ); }
void Raise() { Sys_SignalRaise( handle ); }
void Clear() { Sys_SignalClear( handle ); }
// Wait returns true if the object is in a signalled state and
// returns false if the wait timed out. Wait also clears the signalled
// state when the signalled state is reached within the time out period.
bool Wait( int timeout = WAIT_INFINITE ) { return Sys_SignalWait( handle, timeout ); }
private:
signalHandle_t handle;
idSysSignal( const idSysSignal & s ) {}
void operator=( const idSysSignal & s ) {}
};
/*
================================================
idSysInterlockedInteger is a C++ wrapper for the low level system interlocked integer
routines to atomically increment or decrement an integer.
================================================
*/
class idSysInterlockedInteger {
public:
idSysInterlockedInteger() : value( 0 ) {}
// atomically increments the integer and returns the new value
int Increment() { return Sys_InterlockedIncrement( value ); }
// atomically decrements the integer and returns the new value
int Decrement() { return Sys_InterlockedDecrement( value ); }
// atomically adds a value to the integer and returns the new value
int Add( int v ) { return Sys_InterlockedAdd( value, (interlockedInt_t) v ); }
// atomically subtracts a value from the integer and returns the new value
int Sub( int v ) { return Sys_InterlockedSub( value, (interlockedInt_t) v ); }
// returns the current value of the integer
int GetValue() const { return value; }
// sets a new value, Note: this operation is not atomic
void SetValue( int v ) { value = (interlockedInt_t)v; }
private:
interlockedInt_t value;
};
/*
================================================
idSysInterlockedPointer is a C++ wrapper around the low level system interlocked pointer
routine to atomically set a pointer while retrieving the previous value of the pointer.
================================================
*/
template< typename T >
class idSysInterlockedPointer {
public:
idSysInterlockedPointer() : ptr( NULL ) {}
// atomically sets the pointer and returns the previous pointer value
T * Set( T * newPtr ) {
return (T *) Sys_InterlockedExchangePointer( (void * &) ptr, newPtr );
}
// atomically sets the pointer to 'newPtr' only if the previous pointer is equal to 'comparePtr'
// ptr = ( ptr == comparePtr ) ? newPtr : ptr
T * CompareExchange( T * comparePtr, T * newPtr ) {
return (T *) Sys_InterlockedCompareExchangePointer( (void * &) ptr, comparePtr, newPtr );
}
// returns the current value of the pointer
T * Get() const { return ptr; }
private:
T * ptr;
};
/*
================================================
idSysThread is an abstract base class, to be extended by classes implementing the
idSysThread::Run() method.
class idMyThread : public idSysThread {
public:
virtual int Run() {
// run thread code here
return 0;
}
// specify thread data here
};
idMyThread thread;
thread.Start( "myThread" );
A worker thread is a thread that waits in place (without consuming CPU)
until work is available. A worker thread is implemented as normal, except that, instead of
calling the Start() method, the StartWorker() method is called to start the thread.
Note that the Sys_CreateThread function does not support the concept of worker threads.
class idMyWorkerThread : public idSysThread {
public:
virtual int Run() {
// run thread code here
return 0;
}
// specify thread data here
};
idMyWorkerThread thread;
thread.StartThread( "myWorkerThread" );
// main thread loop
for ( ; ; ) {
// setup work for the thread here (by modifying class data on the thread)
thread.SignalWork(); // kick in the worker thread
// run other code in the main thread here (in parallel with the worker thread)
thread.WaitForThread(); // wait for the worker thread to finish
// use results from worker thread here
}
In the above example, the thread does not continuously run in parallel with the main Thread,
but only for a certain period of time in a very controlled manner. Work is set up for the
Thread and then the thread is signalled to process that work while the main thread continues.
After doing other work, the main thread can wait for the worker thread to finish, if it has not
finished already. When the worker thread is done, the main thread can safely use the results
from the worker thread.
Note that worker threads are useful on all platforms but they do not map to the SPUs on the PS3.
================================================
*/
class idSysThread {
public:
idSysThread();
virtual ~idSysThread();
const char * GetName() const { return name.c_str(); }
uintptr_t GetThreadHandle() const { return threadHandle; }
bool IsRunning() const { return isRunning; }
bool IsTerminating() const { return isTerminating; }
//------------------------
// Thread Start/Stop/Wait
//------------------------
bool StartThread( const char * name, core_t core,
xthreadPriority priority = THREAD_NORMAL,
int stackSize = DEFAULT_THREAD_STACK_SIZE );
bool StartWorkerThread( const char * name, core_t core,
xthreadPriority priority = THREAD_NORMAL,
int stackSize = DEFAULT_THREAD_STACK_SIZE );
void StopThread( bool wait = true );
// This can be called from multiple other threads. However, in the case
// of a worker thread, the work being "done" has little meaning if other
// threads are continuously signalling more work.
void WaitForThread();
//------------------------
// Worker Thread
//------------------------
// Signals the thread to notify work is available.
// This can be called from multiple other threads.
void SignalWork();
// Returns true if the work is done without waiting.
// This can be called from multiple other threads. However, the work
// being "done" has little meaning if other threads are continuously
// signalling more work.
bool IsWorkDone();
protected:
// The routine that performs the work.
virtual int Run();
private:
idStr name;
uintptr_t threadHandle;
bool isWorker;
bool isRunning;
volatile bool isTerminating;
volatile bool moreWorkToDo;
idSysSignal signalWorkerDone;
idSysSignal signalMoreWorkToDo;
idSysMutex signalMutex;
static int ThreadProc( idSysThread * thread );
idSysThread( const idSysThread & s ) {}
void operator=( const idSysThread & s ) {}
};
/*
================================================
idSysWorkerThreadGroup implements a group of worker threads that
typically crunch through a collection of similar tasks.
class idMyWorkerThread : public idSysThread {
public:
virtual int Run() {
// run thread code here
return 0;
}
// specify thread data here
};
idSysWorkerThreadGroup<idMyWorkerThread> workers( "myWorkers", 4 );
for ( ; ; ) {
for ( int i = 0; i < workers.GetNumThreads(); i++ ) {
// workers.GetThread( i )-> // setup work for this thread
}
workers.SignalWorkAndWait();
// use results from the worker threads here
}
The concept of worker thread Groups is probably most useful for tools and compilers.
For instance, the AAS Compiler is using a worker thread group. Although worker threads
will work well on the PC, Mac and the 360, they do not directly map to the PS3,
in that the worker threads won't automatically run on the SPUs.
================================================
*/
template<class threadType>
class idSysWorkerThreadGroup {
public:
idSysWorkerThreadGroup( const char * name, int numThreads,
xthreadPriority priority = THREAD_NORMAL,
int stackSize = DEFAULT_THREAD_STACK_SIZE );
virtual ~idSysWorkerThreadGroup();
int GetNumThreads() const { return threadList.Num(); }
threadType & GetThread( int i ) { return *threadList[i]; }
void SignalWorkAndWait();
private:
idList<threadType *, TAG_THREAD> threadList;
bool runOneThreadInline; // use the signalling thread as one of the threads
bool singleThreaded; // set to true for debugging
};
/*
========================
idSysWorkerThreadGroup<threadType>::idSysWorkerThreadGroup
========================
*/
template<class threadType>
ID_INLINE idSysWorkerThreadGroup<threadType>::idSysWorkerThreadGroup( const char * name,
int numThreads, xthreadPriority priority, int stackSize ) {
runOneThreadInline = ( numThreads < 0 );
singleThreaded = false;
numThreads = abs( numThreads );
for( int i = 0; i < numThreads; i++ ) {
threadType *thread = new (TAG_THREAD) threadType;
thread->StartWorkerThread( va( "%s_worker%i", name, i ), (core_t) i, priority, stackSize );
threadList.Append( thread );
}
}
/*
========================
idSysWorkerThreadGroup<threadType>::~idSysWorkerThreadGroup
========================
*/
template<class threadType>
ID_INLINE idSysWorkerThreadGroup<threadType>::~idSysWorkerThreadGroup() {
threadList.DeleteContents();
}
/*
========================
idSysWorkerThreadGroup<threadType>::SignalWorkAndWait
========================
*/
template<class threadType>
ID_INLINE void idSysWorkerThreadGroup<threadType>::SignalWorkAndWait() {
if ( singleThreaded ) {
for( int i = 0; i < threadList.Num(); i++ ) {
threadList[ i ]->Run();
}
return;
}
for( int i = 0; i < threadList.Num() - runOneThreadInline; i++ ) {
threadList[ i ]->SignalWork();
}
if ( runOneThreadInline ) {
threadList[ threadList.Num() - 1 ]->Run();
}
for ( int i = 0; i < threadList.Num() - runOneThreadInline; i++ ) {
threadList[ i ]->WaitForThread();
}
}
/*
================================================
idSysThreadSynchronizer, allows a group of threads to
synchronize with each other half-way through execution.
idSysThreadSynchronizer sync;
class idMyWorkerThread : public idSysThread {
public:
virtual int Run() {
// perform first part of the work here
sync.Synchronize( threadNum ); // synchronize all threads
// perform second part of the work here
return 0;
}
// specify thread data here
unsigned int threadNum;
};
idSysWorkerThreadGroup<idMyWorkerThread> workers( "myWorkers", 4 );
for ( int i = 0; i < workers.GetNumThreads(); i++ ) {
workers.GetThread( i )->threadNum = i;
}
for ( ; ; ) {
for ( int i = 0; i < workers.GetNumThreads(); i++ ) {
// workers.GetThread( i )-> // setup work for this thread
}
workers.SignalWorkAndWait();
// use results from the worker threads here
}
================================================
*/
class idSysThreadSynchronizer {
public:
static const int WAIT_INFINITE = -1;
ID_INLINE void SetNumThreads( unsigned int num );
ID_INLINE void Signal( unsigned int threadNum );
ID_INLINE bool Synchronize( unsigned int threadNum, int timeout = WAIT_INFINITE );
private:
idList< idSysSignal *, TAG_THREAD > signals;
idSysInterlockedInteger busyCount;
};
/*
========================
idSysThreadSynchronizer::SetNumThreads
========================
*/
ID_INLINE void idSysThreadSynchronizer::SetNumThreads( unsigned int num ) {
assert( busyCount.GetValue() == signals.Num() );
if ( (int)num != signals.Num() ) {
signals.DeleteContents();
signals.SetNum( (int)num );
for ( unsigned int i = 0; i < num; i++ ) {
signals[i] = new (TAG_THREAD) idSysSignal();
}
busyCount.SetValue( num );
SYS_MEMORYBARRIER;
}
}
/*
========================
idSysThreadSynchronizer::Signal
========================
*/
ID_INLINE void idSysThreadSynchronizer::Signal( unsigned int threadNum ) {
if ( busyCount.Decrement() == 0 ) {
busyCount.SetValue( (unsigned int) signals.Num() );
SYS_MEMORYBARRIER;
for ( int i = 0; i < signals.Num(); i++ ) {
signals[i]->Raise();
}
}
}
/*
========================
idSysThreadSynchronizer::Synchronize
========================
*/
ID_INLINE bool idSysThreadSynchronizer::Synchronize( unsigned int threadNum, int timeout ) {
return signals[threadNum]->Wait( timeout );
}
#endif // !__THREAD_H__

160
neo/idlib/Timer.cpp Normal file
View File

@@ -0,0 +1,160 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
double idTimer::base = -1.0;
/*
=================
idTimer::InitBaseClockTicks
=================
*/
void idTimer::InitBaseClockTicks() const {
idTimer timer;
double ct, b;
int i;
base = 0.0;
b = -1.0;
for ( i = 0; i < 1000; i++ ) {
timer.Clear();
timer.Start();
timer.Stop();
ct = timer.ClockTicks();
if ( b < 0.0 || ct < b ) {
b = ct;
}
}
base = b;
}
/*
=================
idTimerReport::idTimerReport
=================
*/
idTimerReport::idTimerReport() {
}
/*
=================
idTimerReport::SetReportName
=================
*/
void idTimerReport::SetReportName( const char *name ) {
reportName = ( name ) ? name : "Timer Report";
}
/*
=================
idTimerReport::~idTimerReport
=================
*/
idTimerReport::~idTimerReport() {
Clear();
}
/*
=================
idTimerReport::AddReport
=================
*/
int idTimerReport::AddReport( const char *name ) {
if ( name && *name ) {
names.Append( name );
return timers.Append( new (TAG_IDLIB) idTimer() );
}
return -1;
}
/*
=================
idTimerReport::Clear
=================
*/
void idTimerReport::Clear() {
timers.DeleteContents( true );
names.Clear();
reportName.Clear();
}
/*
=================
idTimerReport::Reset
=================
*/
void idTimerReport::Reset() {
assert ( timers.Num() == names.Num() );
for ( int i = 0; i < timers.Num(); i++ ) {
timers[i]->Clear();
}
}
/*
=================
idTimerReport::AddTime
=================
*/
void idTimerReport::AddTime( const char *name, idTimer *time ) {
assert ( timers.Num() == names.Num() );
int i;
for ( i = 0; i < names.Num(); i++ ) {
if ( names[i].Icmp( name ) == 0 ) {
*timers[i] += *time;
break;
}
}
if ( i == names.Num() ) {
int index = AddReport( name );
if ( index >= 0 ) {
timers[index]->Clear();
*timers[index] += *time;
}
}
}
/*
=================
idTimerReport::PrintReport
=================
*/
void idTimerReport::PrintReport() {
assert( timers.Num() == names.Num() );
idLib::common->Printf( "Timing Report for %s\n", reportName.c_str() );
idLib::common->Printf( "-------------------------------\n" );
float total = 0.0f;
for ( int i = 0; i < names.Num(); i++ ) {
idLib::common->Printf( "%s consumed %5.2f seconds\n", names[i].c_str(), timers[i]->Milliseconds() * 0.001f );
total += timers[i]->Milliseconds();
}
idLib::common->Printf( "Total time for report %s was %5.2f\n\n", reportName.c_str(), total * 0.001f );
}

223
neo/idlib/Timer.h Normal file
View 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.
===========================================================================
*/
#ifndef __TIMER_H__
#define __TIMER_H__
/*
===============================================================================
Clock tick counter. Should only be used for profiling.
===============================================================================
*/
class idTimer {
public:
idTimer();
idTimer( double clockTicks );
~idTimer();
idTimer operator+( const idTimer &t ) const;
idTimer operator-( const idTimer &t ) const;
idTimer & operator+=( const idTimer &t );
idTimer & operator-=( const idTimer &t );
void Start();
void Stop();
void Clear();
double ClockTicks() const;
double Milliseconds() const;
private:
static double base;
enum {
TS_STARTED,
TS_STOPPED
} state;
double start;
double clockTicks;
void InitBaseClockTicks() const;
};
/*
=================
idTimer::idTimer
=================
*/
ID_INLINE idTimer::idTimer() {
state = TS_STOPPED;
clockTicks = 0.0;
}
/*
=================
idTimer::idTimer
=================
*/
ID_INLINE idTimer::idTimer( double _clockTicks ) {
state = TS_STOPPED;
clockTicks = _clockTicks;
}
/*
=================
idTimer::~idTimer
=================
*/
ID_INLINE idTimer::~idTimer() {
}
/*
=================
idTimer::operator+
=================
*/
ID_INLINE idTimer idTimer::operator+( const idTimer &t ) const {
assert( state == TS_STOPPED && t.state == TS_STOPPED );
return idTimer( clockTicks + t.clockTicks );
}
/*
=================
idTimer::operator-
=================
*/
ID_INLINE idTimer idTimer::operator-( const idTimer &t ) const {
assert( state == TS_STOPPED && t.state == TS_STOPPED );
return idTimer( clockTicks - t.clockTicks );
}
/*
=================
idTimer::operator+=
=================
*/
ID_INLINE idTimer &idTimer::operator+=( const idTimer &t ) {
assert( state == TS_STOPPED && t.state == TS_STOPPED );
clockTicks += t.clockTicks;
return *this;
}
/*
=================
idTimer::operator-=
=================
*/
ID_INLINE idTimer &idTimer::operator-=( const idTimer &t ) {
assert( state == TS_STOPPED && t.state == TS_STOPPED );
clockTicks -= t.clockTicks;
return *this;
}
/*
=================
idTimer::Start
=================
*/
ID_INLINE void idTimer::Start() {
assert( state == TS_STOPPED );
state = TS_STARTED;
start = idLib::sys->GetClockTicks();
}
/*
=================
idTimer::Stop
=================
*/
ID_INLINE void idTimer::Stop() {
assert( state == TS_STARTED );
clockTicks += idLib::sys->GetClockTicks() - start;
if ( base < 0.0 ) {
InitBaseClockTicks();
}
if ( clockTicks > base ) {
clockTicks -= base;
}
state = TS_STOPPED;
}
/*
=================
idTimer::Clear
=================
*/
ID_INLINE void idTimer::Clear() {
clockTicks = 0.0;
}
/*
=================
idTimer::ClockTicks
=================
*/
ID_INLINE double idTimer::ClockTicks() const {
assert( state == TS_STOPPED );
return clockTicks;
}
/*
=================
idTimer::Milliseconds
=================
*/
ID_INLINE double idTimer::Milliseconds() const {
assert( state == TS_STOPPED );
return clockTicks / ( idLib::sys->ClockTicksPerSecond() * 0.001 );
}
/*
===============================================================================
Report of multiple named timers.
===============================================================================
*/
class idTimerReport {
public:
idTimerReport();
~idTimerReport();
void SetReportName( const char *name );
int AddReport( const char *name );
void Clear();
void Reset();
void PrintReport();
void AddTime( const char *name, idTimer *time );
private:
idList<idTimer*>timers;
idStrList names;
idStr reportName;
};
#endif /* !__TIMER_H__ */

179
neo/idlib/Token.cpp Normal file
View File

@@ -0,0 +1,179 @@
/*
===========================================================================
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.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
/*
================
idToken::NumberValue
================
*/
void idToken::NumberValue() {
int i, pow, div, c;
const char *p;
double m;
assert( type == TT_NUMBER );
p = c_str();
floatvalue = 0;
intvalue = 0;
// floating point number
if ( subtype & TT_FLOAT ) {
if ( subtype & ( TT_INFINITE | TT_INDEFINITE | TT_NAN ) ) {
if ( subtype & TT_INFINITE ) { // 1.#INF
unsigned int inf = 0x7f800000;
floatvalue = (double) *(float*)&inf;
}
else if ( subtype & TT_INDEFINITE ) { // 1.#IND
unsigned int ind = 0xffc00000;
floatvalue = (double) *(float*)&ind;
}
else if ( subtype & TT_NAN ) { // 1.#QNAN
unsigned int nan = 0x7fc00000;
floatvalue = (double) *(float*)&nan;
}
}
else {
while( *p && *p != '.' && *p != 'e' ) {
floatvalue = floatvalue * 10.0 + (double) (*p - '0');
p++;
}
if ( *p == '.' ) {
p++;
for( m = 0.1; *p && *p != 'e'; p++ ) {
floatvalue = floatvalue + (double) (*p - '0') * m;
m *= 0.1;
}
}
if ( *p == 'e' ) {
p++;
if ( *p == '-' ) {
div = true;
p++;
}
else if ( *p == '+' ) {
div = false;
p++;
}
else {
div = false;
}
pow = 0;
for ( pow = 0; *p; p++ ) {
pow = pow * 10 + (int) (*p - '0');
}
for ( m = 1.0, i = 0; i < pow; i++ ) {
m *= 10.0;
}
if ( div ) {
floatvalue /= m;
}
else {
floatvalue *= m;
}
}
}
intvalue = idMath::Ftoi( floatvalue );
}
else if ( subtype & TT_DECIMAL ) {
while( *p ) {
intvalue = intvalue * 10 + (*p - '0');
p++;
}
floatvalue = intvalue;
}
else if ( subtype & TT_IPADDRESS ) {
c = 0;
while( *p && *p != ':' ) {
if ( *p == '.' ) {
while( c != 3 ) {
intvalue = intvalue * 10;
c++;
}
c = 0;
}
else {
intvalue = intvalue * 10 + (*p - '0');
c++;
}
p++;
}
while( c != 3 ) {
intvalue = intvalue * 10;
c++;
}
floatvalue = intvalue;
}
else if ( subtype & TT_OCTAL ) {
// step over the first zero
p += 1;
while( *p ) {
intvalue = (intvalue << 3) + (*p - '0');
p++;
}
floatvalue = intvalue;
}
else if ( subtype & TT_HEX ) {
// step over the leading 0x or 0X
p += 2;
while( *p ) {
intvalue <<= 4;
if (*p >= 'a' && *p <= 'f')
intvalue += *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
intvalue += *p - 'A' + 10;
else
intvalue += *p - '0';
p++;
}
floatvalue = intvalue;
}
else if ( subtype & TT_BINARY ) {
// step over the leading 0b or 0B
p += 2;
while( *p ) {
intvalue = (intvalue << 1) + (*p - '0');
p++;
}
floatvalue = intvalue;
}
subtype |= TT_VALUESVALID;
}
/*
================
idToken::ClearTokenWhiteSpace
================
*/
void idToken::ClearTokenWhiteSpace() {
whiteSpaceStart_p = NULL;
whiteSpaceEnd_p = NULL;
linesCrossed = 0;
}

165
neo/idlib/Token.h Normal file
View File

@@ -0,0 +1,165 @@
/*
===========================================================================
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 __TOKEN_H__
#define __TOKEN_H__
/*
===============================================================================
idToken is a token read from a file or memory with idLexer or idParser
===============================================================================
*/
// token types
#define TT_STRING 1 // string
#define TT_LITERAL 2 // literal
#define TT_NUMBER 3 // number
#define TT_NAME 4 // name
#define TT_PUNCTUATION 5 // punctuation
// number sub types
#define TT_INTEGER 0x00001 // integer
#define TT_DECIMAL 0x00002 // decimal number
#define TT_HEX 0x00004 // hexadecimal number
#define TT_OCTAL 0x00008 // octal number
#define TT_BINARY 0x00010 // binary number
#define TT_LONG 0x00020 // long int
#define TT_UNSIGNED 0x00040 // unsigned int
#define TT_FLOAT 0x00080 // floating point number
#define TT_SINGLE_PRECISION 0x00100 // float
#define TT_DOUBLE_PRECISION 0x00200 // double
#define TT_EXTENDED_PRECISION 0x00400 // long double
#define TT_INFINITE 0x00800 // infinite 1.#INF
#define TT_INDEFINITE 0x01000 // indefinite 1.#IND
#define TT_NAN 0x02000 // NaN
#define TT_IPADDRESS 0x04000 // ip address
#define TT_IPPORT 0x08000 // ip port
#define TT_VALUESVALID 0x10000 // set if intvalue and floatvalue are valid
// string sub type is the length of the string
// literal sub type is the ASCII code
// punctuation sub type is the punctuation id
// name sub type is the length of the name
class idToken : public idStr {
friend class idParser;
friend class idLexer;
public:
int type; // token type
int subtype; // token sub type
int line; // line in script the token was on
int linesCrossed; // number of lines crossed in white space before token
int flags; // token flags, used for recursive defines
public:
idToken();
idToken( const idToken *token );
~idToken();
void operator=( const idStr& text );
void operator=( const char *text );
double GetDoubleValue(); // double value of TT_NUMBER
float GetFloatValue(); // float value of TT_NUMBER
unsigned long GetUnsignedLongValue(); // unsigned long value of TT_NUMBER
int GetIntValue(); // int value of TT_NUMBER
int WhiteSpaceBeforeToken() const;// returns length of whitespace before token
void ClearTokenWhiteSpace(); // forget whitespace before token
void NumberValue(); // calculate values for a TT_NUMBER
private:
unsigned long intvalue; // integer value
double floatvalue; // floating point value
const char * whiteSpaceStart_p; // start of white space before token, only used by idLexer
const char * whiteSpaceEnd_p; // end of white space before token, only used by idLexer
idToken * next; // next token in chain, only used by idParser
void AppendDirty( const char a ); // append character without adding trailing zero
};
ID_INLINE idToken::idToken() : type(), subtype(), line(), linesCrossed(), flags() {
}
ID_INLINE idToken::idToken( const idToken *token ) {
*this = *token;
}
ID_INLINE idToken::~idToken() {
}
ID_INLINE void idToken::operator=( const char *text) {
*static_cast<idStr *>(this) = text;
}
ID_INLINE void idToken::operator=( const idStr& text ) {
*static_cast<idStr *>(this) = text;
}
ID_INLINE double idToken::GetDoubleValue() {
if ( type != TT_NUMBER ) {
return 0.0;
}
if ( !(subtype & TT_VALUESVALID) ) {
NumberValue();
}
return floatvalue;
}
ID_INLINE float idToken::GetFloatValue() {
return (float) GetDoubleValue();
}
ID_INLINE unsigned long idToken::GetUnsignedLongValue() {
if ( type != TT_NUMBER ) {
return 0;
}
if ( !(subtype & TT_VALUESVALID) ) {
NumberValue();
}
return intvalue;
}
ID_INLINE int idToken::GetIntValue() {
return (int) GetUnsignedLongValue();
}
ID_INLINE int idToken::WhiteSpaceBeforeToken() const {
return ( whiteSpaceEnd_p > whiteSpaceStart_p );
}
ID_INLINE void idToken::AppendDirty( const char a ) {
EnsureAlloced( len + 2, true );
data[len++] = a;
}
#endif /* !__TOKEN_H__ */

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

@@ -0,0 +1,425 @@
/*
===========================================================================
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"
idBounds bounds_zero( vec3_zero, vec3_zero );
idBounds bounds_zeroOneCube( idVec3( 0.0f ), idVec3( 1.0f ) );
idBounds bounds_unitCube( idVec3( -1.0f ), idVec3( 1.0f ) );
/*
============
idBounds::GetRadius
============
*/
float idBounds::GetRadius() const {
int i;
float total, b0, b1;
total = 0.0f;
for ( i = 0; i < 3; i++ ) {
b0 = (float)idMath::Fabs( b[0][i] );
b1 = (float)idMath::Fabs( b[1][i] );
if ( b0 > b1 ) {
total += b0 * b0;
} else {
total += b1 * b1;
}
}
return idMath::Sqrt( total );
}
/*
============
idBounds::GetRadius
============
*/
float idBounds::GetRadius( const idVec3 &center ) const {
int i;
float total, b0, b1;
total = 0.0f;
for ( i = 0; i < 3; i++ ) {
b0 = (float)idMath::Fabs( center[i] - b[0][i] );
b1 = (float)idMath::Fabs( b[1][i] - center[i] );
if ( b0 > b1 ) {
total += b0 * b0;
} else {
total += b1 * b1;
}
}
return idMath::Sqrt( total );
}
/*
================
idBounds::PlaneDistance
================
*/
float idBounds::PlaneDistance( const idPlane &plane ) const {
idVec3 center;
float d1, d2;
center = ( b[0] + b[1] ) * 0.5f;
d1 = plane.Distance( center );
d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) +
idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) +
idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] );
if ( d1 - d2 > 0.0f ) {
return d1 - d2;
}
if ( d1 + d2 < 0.0f ) {
return d1 + d2;
}
return 0.0f;
}
/*
================
idBounds::PlaneSide
================
*/
int idBounds::PlaneSide( const idPlane &plane, const float epsilon ) const {
idVec3 center;
float d1, d2;
center = ( b[0] + b[1] ) * 0.5f;
d1 = plane.Distance( center );
d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) +
idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) +
idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] );
if ( d1 - d2 > epsilon ) {
return PLANESIDE_FRONT;
}
if ( d1 + d2 < -epsilon ) {
return PLANESIDE_BACK;
}
return PLANESIDE_CROSS;
}
/*
============
idBounds::LineIntersection
Returns true if the line intersects the bounds between the start and end point.
============
*/
bool idBounds::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
const idVec3 center = ( b[0] + b[1] ) * 0.5f;
const idVec3 extents = b[1] - center;
const idVec3 lineDir = 0.5f * ( end - start );
const idVec3 lineCenter = start + lineDir;
const idVec3 dir = lineCenter - center;
const float ld0 = idMath::Fabs( lineDir[0] );
if ( idMath::Fabs( dir[0] ) > extents[0] + ld0 ) {
return false;
}
const float ld1 = idMath::Fabs( lineDir[1] );
if ( idMath::Fabs( dir[1] ) > extents[1] + ld1 ) {
return false;
}
const float ld2 = idMath::Fabs( lineDir[2] );
if ( idMath::Fabs( dir[2] ) > extents[2] + ld2 ) {
return false;
}
const idVec3 cross = lineDir.Cross( dir );
if ( idMath::Fabs( cross[0] ) > extents[1] * ld2 + extents[2] * ld1 ) {
return false;
}
if ( idMath::Fabs( cross[1] ) > extents[0] * ld2 + extents[2] * ld0 ) {
return false;
}
if ( idMath::Fabs( cross[2] ) > extents[0] * ld1 + extents[1] * ld0 ) {
return false;
}
return true;
}
/*
============
idBounds::RayIntersection
Returns true if the ray intersects the bounds.
The ray can intersect the bounds in both directions from the start point.
If start is inside the bounds it is considered an intersection with scale = 0
============
*/
bool idBounds::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const {
int i, ax0, ax1, ax2, side, inside;
float f;
idVec3 hit;
ax0 = -1;
inside = 0;
for ( i = 0; i < 3; i++ ) {
if ( start[i] < b[0][i] ) {
side = 0;
}
else if ( start[i] > b[1][i] ) {
side = 1;
}
else {
inside++;
continue;
}
if ( dir[i] == 0.0f ) {
continue;
}
f = ( start[i] - b[side][i] );
if ( ax0 < 0 || idMath::Fabs( f ) > idMath::Fabs( scale * dir[i] ) ) {
scale = - ( f / dir[i] );
ax0 = i;
}
}
if ( ax0 < 0 ) {
scale = 0.0f;
// return true if the start point is inside the bounds
return ( inside == 3 );
}
ax1 = (ax0+1)%3;
ax2 = (ax0+2)%3;
hit[ax1] = start[ax1] + scale * dir[ax1];
hit[ax2] = start[ax2] + scale * dir[ax2];
return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&
hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );
}
/*
============
idBounds::FromTransformedBounds
============
*/
void idBounds::FromTransformedBounds( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis ) {
int i;
idVec3 center, extents, rotatedExtents;
center = (bounds[0] + bounds[1]) * 0.5f;
extents = bounds[1] - center;
for ( i = 0; i < 3; i++ ) {
rotatedExtents[i] = idMath::Fabs( extents[0] * axis[0][i] ) +
idMath::Fabs( extents[1] * axis[1][i] ) +
idMath::Fabs( extents[2] * axis[2][i] );
}
center = origin + center * axis;
b[0] = center - rotatedExtents;
b[1] = center + rotatedExtents;
}
/*
============
idBounds::FromPoints
Most tight bounds for a point set.
============
*/
void idBounds::FromPoints( const idVec3 *points, const int numPoints ) {
SIMDProcessor->MinMax( b[0], b[1], points, numPoints );
}
/*
============
idBounds::FromPointTranslation
Most tight bounds for the translational movement of the given point.
============
*/
void idBounds::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
int i;
for ( i = 0; i < 3; i++ ) {
if ( translation[i] < 0.0f ) {
b[0][i] = point[i] + translation[i];
b[1][i] = point[i];
}
else {
b[0][i] = point[i];
b[1][i] = point[i] + translation[i];
}
}
}
/*
============
idBounds::FromBoundsTranslation
Most tight bounds for the translational movement of the given bounds.
============
*/
void idBounds::FromBoundsTranslation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation ) {
int i;
if ( axis.IsRotated() ) {
FromTransformedBounds( bounds, origin, axis );
}
else {
b[0] = bounds[0] + origin;
b[1] = bounds[1] + origin;
}
for ( i = 0; i < 3; i++ ) {
if ( translation[i] < 0.0f ) {
b[0][i] += translation[i];
}
else {
b[1][i] += translation[i];
}
}
}
/*
================
BoundsForPointRotation
only for rotations < 180 degrees
================
*/
idBounds BoundsForPointRotation( const idVec3 &start, const idRotation &rotation ) {
int i;
float radiusSqr;
idVec3 v1, v2;
idVec3 origin, axis, end;
idBounds bounds;
end = start * rotation;
axis = rotation.GetVec();
origin = rotation.GetOrigin() + axis * ( axis * ( start - rotation.GetOrigin() ) );
radiusSqr = ( start - origin ).LengthSqr();
v1 = ( start - origin ).Cross( axis );
v2 = ( end - origin ).Cross( axis );
for ( i = 0; i < 3; i++ ) {
// if the derivative changes sign along this axis during the rotation from start to end
if ( ( v1[i] > 0.0f && v2[i] < 0.0f ) || ( v1[i] < 0.0f && v2[i] > 0.0f ) ) {
if ( ( 0.5f * (start[i] + end[i]) - origin[i] ) > 0.0f ) {
bounds[0][i] = Min( start[i], end[i] );
bounds[1][i] = origin[i] + idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
}
else {
bounds[0][i] = origin[i] - idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
bounds[1][i] = Max( start[i], end[i] );
}
}
else if ( start[i] > end[i] ) {
bounds[0][i] = end[i];
bounds[1][i] = start[i];
}
else {
bounds[0][i] = start[i];
bounds[1][i] = end[i];
}
}
return bounds;
}
/*
============
idBounds::FromPointRotation
Most tight bounds for the rotational movement of the given point.
============
*/
void idBounds::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
float radius;
if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
(*this) = BoundsForPointRotation( point, rotation );
}
else {
radius = ( point - rotation.GetOrigin() ).Length();
// FIXME: these bounds are usually way larger
b[0].Set( -radius, -radius, -radius );
b[1].Set( radius, radius, radius );
}
}
/*
============
idBounds::FromBoundsRotation
Most tight bounds for the rotational movement of the given bounds.
============
*/
void idBounds::FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation ) {
int i;
float radius;
idVec3 point;
idBounds rBounds;
if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
(*this) = BoundsForPointRotation( bounds[0] * axis + origin, rotation );
for ( i = 1; i < 8; i++ ) {
point[0] = bounds[(i^(i>>1))&1][0];
point[1] = bounds[(i>>1)&1][1];
point[2] = bounds[(i>>2)&1][2];
(*this) += BoundsForPointRotation( point * axis + origin, rotation );
}
}
else {
point = (bounds[1] - bounds[0]) * 0.5f;
radius = (bounds[1] - point).Length() + (point - rotation.GetOrigin()).Length();
// FIXME: these bounds are usually way larger
b[0].Set( -radius, -radius, -radius );
b[1].Set( radius, radius, radius );
}
}
/*
============
idBounds::ToPoints
============
*/
void idBounds::ToPoints( idVec3 points[8] ) const {
for ( int i = 0; i < 8; i++ ) {
points[i][0] = b[(i^(i>>1))&1][0];
points[i][1] = b[(i>>1)&1][1];
points[i][2] = b[(i>>2)&1][2];
}
}

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

@@ -0,0 +1,428 @@
/*
===========================================================================
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 __BV_BOUNDS_H__
#define __BV_BOUNDS_H__
/*
===============================================================================
Axis Aligned Bounding Box
===============================================================================
*/
class idBounds {
public:
idBounds();
explicit idBounds( const idVec3 &mins, const idVec3 &maxs );
explicit idBounds( const idVec3 &point );
const idVec3 & operator[]( const int index ) const;
idVec3 & operator[]( const int index );
idBounds operator+( const idVec3 &t ) const; // returns translated bounds
idBounds & operator+=( const idVec3 &t ); // translate the bounds
idBounds operator*( const idMat3 &r ) const; // returns rotated bounds
idBounds & operator*=( const idMat3 &r ); // rotate the bounds
idBounds operator+( const idBounds &a ) const;
idBounds & operator+=( const idBounds &a );
idBounds operator-( const idBounds &a ) const;
idBounds & operator-=( const idBounds &a );
bool Compare( const idBounds &a ) const; // exact compare, no epsilon
bool Compare( const idBounds &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idBounds &a ) const; // exact compare, no epsilon
bool operator!=( const idBounds &a ) const; // exact compare, no epsilon
void Clear(); // inside out bounds
void Zero(); // single point at origin
idVec3 GetCenter() const; // returns center of bounds
float GetRadius() const; // returns the radius relative to the bounds origin
float GetRadius( const idVec3 &center ) const; // returns the radius relative to the given center
float GetVolume() const; // returns the volume of the bounds
bool IsCleared() const; // returns true if bounds are inside out
bool AddPoint( const idVec3 &v ); // add the point, returns true if the bounds expanded
bool AddBounds( const idBounds &a ); // add the bounds, returns true if the bounds expanded
idBounds Intersect( const idBounds &a ) const; // return intersection of this bounds with the given bounds
idBounds & IntersectSelf( const idBounds &a ); // intersect this bounds with the given bounds
idBounds Expand( const float d ) const; // return bounds expanded in all directions with the given value
idBounds & ExpandSelf( const float d ); // expand bounds in all directions with the given value
idBounds Translate( const idVec3 &translation ) const; // return translated bounds
idBounds & TranslateSelf( const idVec3 &translation ); // translate this bounds
idBounds Rotate( const idMat3 &rotation ) const; // return rotated bounds
idBounds & RotateSelf( const idMat3 &rotation ); // rotate this bounds
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool ContainsPoint( const idVec3 &p ) const; // includes touching
bool IntersectsBounds( const idBounds &a ) const; // includes touching
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
// intersection point is start + dir * scale
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const;
// most tight bounds for the given transformed bounds
void FromTransformedBounds( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis );
// most tight bounds for a point set
void FromPoints( const idVec3 *points, const int numPoints );
// most tight bounds for a translation
void FromPointTranslation( const idVec3 &point, const idVec3 &translation );
void FromBoundsTranslation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation );
// most tight bounds for a rotation
void FromPointRotation( const idVec3 &point, const idRotation &rotation );
void FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation );
void ToPoints( idVec3 points[8] ) const;
idSphere ToSphere() const;
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
void AxisProjection( const idVec3 &origin, const idMat3 &axis, const idVec3 &dir, float &min, float &max ) const;
int GetDimension() const;
const float * ToFloatPtr() const;
float * ToFloatPtr();
private:
idVec3 b[2];
};
extern idBounds bounds_zero;
extern idBounds bounds_zeroOneCube;
extern idBounds bounds_unitCube;
ID_INLINE idBounds::idBounds() {
}
ID_INLINE idBounds::idBounds( const idVec3 &mins, const idVec3 &maxs ) {
b[0] = mins;
b[1] = maxs;
}
ID_INLINE idBounds::idBounds( const idVec3 &point ) {
b[0] = point;
b[1] = point;
}
ID_INLINE const idVec3 &idBounds::operator[]( const int index ) const {
return b[index];
}
ID_INLINE idVec3 &idBounds::operator[]( const int index ) {
return b[index];
}
ID_INLINE idBounds idBounds::operator+( const idVec3 &t ) const {
return idBounds( b[0] + t, b[1] + t );
}
ID_INLINE idBounds &idBounds::operator+=( const idVec3 &t ) {
b[0] += t;
b[1] += t;
return *this;
}
ID_INLINE idBounds idBounds::operator*( const idMat3 &r ) const {
idBounds bounds;
bounds.FromTransformedBounds( *this, vec3_origin, r );
return bounds;
}
ID_INLINE idBounds &idBounds::operator*=( const idMat3 &r ) {
this->FromTransformedBounds( *this, vec3_origin, r );
return *this;
}
ID_INLINE idBounds idBounds::operator+( const idBounds &a ) const {
idBounds newBounds;
newBounds = *this;
newBounds.AddBounds( a );
return newBounds;
}
ID_INLINE idBounds &idBounds::operator+=( const idBounds &a ) {
idBounds::AddBounds( a );
return *this;
}
ID_INLINE idBounds idBounds::operator-( const idBounds &a ) const {
assert( b[1][0] - b[0][0] > a.b[1][0] - a.b[0][0] &&
b[1][1] - b[0][1] > a.b[1][1] - a.b[0][1] &&
b[1][2] - b[0][2] > a.b[1][2] - a.b[0][2] );
return idBounds( idVec3( b[0][0] + a.b[1][0], b[0][1] + a.b[1][1], b[0][2] + a.b[1][2] ),
idVec3( b[1][0] + a.b[0][0], b[1][1] + a.b[0][1], b[1][2] + a.b[0][2] ) );
}
ID_INLINE idBounds &idBounds::operator-=( const idBounds &a ) {
assert( b[1][0] - b[0][0] > a.b[1][0] - a.b[0][0] &&
b[1][1] - b[0][1] > a.b[1][1] - a.b[0][1] &&
b[1][2] - b[0][2] > a.b[1][2] - a.b[0][2] );
b[0] += a.b[1];
b[1] += a.b[0];
return *this;
}
ID_INLINE bool idBounds::Compare( const idBounds &a ) const {
return ( b[0].Compare( a.b[0] ) && b[1].Compare( a.b[1] ) );
}
ID_INLINE bool idBounds::Compare( const idBounds &a, const float epsilon ) const {
return ( b[0].Compare( a.b[0], epsilon ) && b[1].Compare( a.b[1], epsilon ) );
}
ID_INLINE bool idBounds::operator==( const idBounds &a ) const {
return Compare( a );
}
ID_INLINE bool idBounds::operator!=( const idBounds &a ) const {
return !Compare( a );
}
ID_INLINE void idBounds::Clear() {
b[0][0] = b[0][1] = b[0][2] = idMath::INFINITY;
b[1][0] = b[1][1] = b[1][2] = -idMath::INFINITY;
}
ID_INLINE void idBounds::Zero() {
b[0][0] = b[0][1] = b[0][2] =
b[1][0] = b[1][1] = b[1][2] = 0;
}
ID_INLINE idVec3 idBounds::GetCenter() const {
return idVec3( ( b[1][0] + b[0][0] ) * 0.5f, ( b[1][1] + b[0][1] ) * 0.5f, ( b[1][2] + b[0][2] ) * 0.5f );
}
ID_INLINE float idBounds::GetVolume() const {
if ( b[0][0] >= b[1][0] || b[0][1] >= b[1][1] || b[0][2] >= b[1][2] ) {
return 0.0f;
}
return ( ( b[1][0] - b[0][0] ) * ( b[1][1] - b[0][1] ) * ( b[1][2] - b[0][2] ) );
}
ID_INLINE bool idBounds::IsCleared() const {
return b[0][0] > b[1][0];
}
ID_INLINE bool idBounds::AddPoint( const idVec3 &v ) {
bool expanded = false;
if ( v[0] < b[0][0]) {
b[0][0] = v[0];
expanded = true;
}
if ( v[0] > b[1][0]) {
b[1][0] = v[0];
expanded = true;
}
if ( v[1] < b[0][1] ) {
b[0][1] = v[1];
expanded = true;
}
if ( v[1] > b[1][1]) {
b[1][1] = v[1];
expanded = true;
}
if ( v[2] < b[0][2] ) {
b[0][2] = v[2];
expanded = true;
}
if ( v[2] > b[1][2]) {
b[1][2] = v[2];
expanded = true;
}
return expanded;
}
ID_INLINE bool idBounds::AddBounds( const idBounds &a ) {
bool expanded = false;
if ( a.b[0][0] < b[0][0] ) {
b[0][0] = a.b[0][0];
expanded = true;
}
if ( a.b[0][1] < b[0][1] ) {
b[0][1] = a.b[0][1];
expanded = true;
}
if ( a.b[0][2] < b[0][2] ) {
b[0][2] = a.b[0][2];
expanded = true;
}
if ( a.b[1][0] > b[1][0] ) {
b[1][0] = a.b[1][0];
expanded = true;
}
if ( a.b[1][1] > b[1][1] ) {
b[1][1] = a.b[1][1];
expanded = true;
}
if ( a.b[1][2] > b[1][2] ) {
b[1][2] = a.b[1][2];
expanded = true;
}
return expanded;
}
ID_INLINE idBounds idBounds::Intersect( const idBounds &a ) const {
idBounds n;
n.b[0][0] = ( a.b[0][0] > b[0][0] ) ? a.b[0][0] : b[0][0];
n.b[0][1] = ( a.b[0][1] > b[0][1] ) ? a.b[0][1] : b[0][1];
n.b[0][2] = ( a.b[0][2] > b[0][2] ) ? a.b[0][2] : b[0][2];
n.b[1][0] = ( a.b[1][0] < b[1][0] ) ? a.b[1][0] : b[1][0];
n.b[1][1] = ( a.b[1][1] < b[1][1] ) ? a.b[1][1] : b[1][1];
n.b[1][2] = ( a.b[1][2] < b[1][2] ) ? a.b[1][2] : b[1][2];
return n;
}
ID_INLINE idBounds &idBounds::IntersectSelf( const idBounds &a ) {
if ( a.b[0][0] > b[0][0] ) {
b[0][0] = a.b[0][0];
}
if ( a.b[0][1] > b[0][1] ) {
b[0][1] = a.b[0][1];
}
if ( a.b[0][2] > b[0][2] ) {
b[0][2] = a.b[0][2];
}
if ( a.b[1][0] < b[1][0] ) {
b[1][0] = a.b[1][0];
}
if ( a.b[1][1] < b[1][1] ) {
b[1][1] = a.b[1][1];
}
if ( a.b[1][2] < b[1][2] ) {
b[1][2] = a.b[1][2];
}
return *this;
}
ID_INLINE idBounds idBounds::Expand( const float d ) const {
return idBounds( idVec3( b[0][0] - d, b[0][1] - d, b[0][2] - d ),
idVec3( b[1][0] + d, b[1][1] + d, b[1][2] + d ) );
}
ID_INLINE idBounds &idBounds::ExpandSelf( const float d ) {
b[0][0] -= d;
b[0][1] -= d;
b[0][2] -= d;
b[1][0] += d;
b[1][1] += d;
b[1][2] += d;
return *this;
}
ID_INLINE idBounds idBounds::Translate( const idVec3 &translation ) const {
return idBounds( b[0] + translation, b[1] + translation );
}
ID_INLINE idBounds &idBounds::TranslateSelf( const idVec3 &translation ) {
b[0] += translation;
b[1] += translation;
return *this;
}
ID_INLINE idBounds idBounds::Rotate( const idMat3 &rotation ) const {
idBounds bounds;
bounds.FromTransformedBounds( *this, vec3_origin, rotation );
return bounds;
}
ID_INLINE idBounds &idBounds::RotateSelf( const idMat3 &rotation ) {
FromTransformedBounds( *this, vec3_origin, rotation );
return *this;
}
ID_INLINE bool idBounds::ContainsPoint( const idVec3 &p ) const {
if ( p[0] < b[0][0] || p[1] < b[0][1] || p[2] < b[0][2]
|| p[0] > b[1][0] || p[1] > b[1][1] || p[2] > b[1][2] ) {
return false;
}
return true;
}
ID_INLINE bool idBounds::IntersectsBounds( const idBounds &a ) const {
if ( a.b[1][0] < b[0][0] || a.b[1][1] < b[0][1] || a.b[1][2] < b[0][2]
|| a.b[0][0] > b[1][0] || a.b[0][1] > b[1][1] || a.b[0][2] > b[1][2] ) {
return false;
}
return true;
}
ID_INLINE idSphere idBounds::ToSphere() const {
idSphere sphere;
sphere.SetOrigin( ( b[0] + b[1] ) * 0.5f );
sphere.SetRadius( ( b[1] - sphere.GetOrigin() ).Length() );
return sphere;
}
ID_INLINE void idBounds::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
float d1, d2;
idVec3 center, extents;
center = ( b[0] + b[1] ) * 0.5f;
extents = b[1] - center;
d1 = dir * center;
d2 = idMath::Fabs( extents[0] * dir[0] ) +
idMath::Fabs( extents[1] * dir[1] ) +
idMath::Fabs( extents[2] * dir[2] );
min = d1 - d2;
max = d1 + d2;
}
ID_INLINE void idBounds::AxisProjection( const idVec3 &origin, const idMat3 &axis, const idVec3 &dir, float &min, float &max ) const {
float d1, d2;
idVec3 center, extents;
center = ( b[0] + b[1] ) * 0.5f;
extents = b[1] - center;
center = origin + center * axis;
d1 = dir * center;
d2 = idMath::Fabs( extents[0] * ( dir * axis[0] ) ) +
idMath::Fabs( extents[1] * ( dir * axis[1] ) ) +
idMath::Fabs( extents[2] * ( dir * axis[2] ) );
min = d1 - d2;
max = d1 + d2;
}
ID_INLINE int idBounds::GetDimension() const {
return 6;
}
ID_INLINE const float *idBounds::ToFloatPtr() const {
return &b[0].x;
}
ID_INLINE float *idBounds::ToFloatPtr() {
return &b[0].x;
}
#endif /* !__BV_BOUNDS_H__ */

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

@@ -0,0 +1,849 @@
/*
===========================================================================
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"
idBox box_zero( vec3_zero, vec3_zero, mat3_identity );
/*
4---{4}---5
+ /| /|
Z {7} {8} {5} |
- / | / {9}
7--{6}----6 |
| | | |
{11} 0---|-{0}-1
| / | / -
| {3} {10} {1} Y
|/ |/ +
3---{2}---2
- X +
plane bits:
0 = min x
1 = max x
2 = min y
3 = max y
4 = min z
5 = max z
*/
/*
static int boxVertPlanes[8] = {
( (1<<0) | (1<<2) | (1<<4) ),
( (1<<1) | (1<<2) | (1<<4) ),
( (1<<1) | (1<<3) | (1<<4) ),
( (1<<0) | (1<<3) | (1<<4) ),
( (1<<0) | (1<<2) | (1<<5) ),
( (1<<1) | (1<<2) | (1<<5) ),
( (1<<1) | (1<<3) | (1<<5) ),
( (1<<0) | (1<<3) | (1<<5) )
};
static int boxVertEdges[8][3] = {
// bottom
{ 3, 0, 8 },
{ 0, 1, 9 },
{ 1, 2, 10 },
{ 2, 3, 11 },
// top
{ 7, 4, 8 },
{ 4, 5, 9 },
{ 5, 6, 10 },
{ 6, 7, 11 }
};
static int boxEdgePlanes[12][2] = {
// bottom
{ 4, 2 },
{ 4, 1 },
{ 4, 3 },
{ 4, 0 },
// top
{ 5, 2 },
{ 5, 1 },
{ 5, 3 },
{ 5, 0 },
// sides
{ 0, 2 },
{ 2, 1 },
{ 1, 3 },
{ 3, 0 }
};
static int boxEdgeVerts[12][2] = {
// bottom
{ 0, 1 },
{ 1, 2 },
{ 2, 3 },
{ 3, 0 },
// top
{ 4, 5 },
{ 5, 6 },
{ 6, 7 },
{ 7, 4 },
// sides
{ 0, 4 },
{ 1, 5 },
{ 2, 6 },
{ 3, 7 }
};
*/
static int boxPlaneBitsSilVerts[64][7] = {
{ 0, 0, 0, 0, 0, 0, 0 }, // 000000 = 0
{ 4, 7, 4, 0, 3, 0, 0 }, // 000001 = 1
{ 4, 5, 6, 2, 1, 0, 0 }, // 000010 = 2
{ 0, 0, 0, 0, 0, 0, 0 }, // 000011 = 3
{ 4, 4, 5, 1, 0, 0, 0 }, // 000100 = 4
{ 6, 3, 7, 4, 5, 1, 0 }, // 000101 = 5
{ 6, 4, 5, 6, 2, 1, 0 }, // 000110 = 6
{ 0, 0, 0, 0, 0, 0, 0 }, // 000111 = 7
{ 4, 6, 7, 3, 2, 0, 0 }, // 001000 = 8
{ 6, 6, 7, 4, 0, 3, 2 }, // 001001 = 9
{ 6, 5, 6, 7, 3, 2, 1 }, // 001010 = 10
{ 0, 0, 0, 0, 0, 0, 0 }, // 001011 = 11
{ 0, 0, 0, 0, 0, 0, 0 }, // 001100 = 12
{ 0, 0, 0, 0, 0, 0, 0 }, // 001101 = 13
{ 0, 0, 0, 0, 0, 0, 0 }, // 001110 = 14
{ 0, 0, 0, 0, 0, 0, 0 }, // 001111 = 15
{ 4, 0, 1, 2, 3, 0, 0 }, // 010000 = 16
{ 6, 0, 1, 2, 3, 7, 4 }, // 010001 = 17
{ 6, 3, 2, 6, 5, 1, 0 }, // 010010 = 18
{ 0, 0, 0, 0, 0, 0, 0 }, // 010011 = 19
{ 6, 1, 2, 3, 0, 4, 5 }, // 010100 = 20
{ 6, 1, 2, 3, 7, 4, 5 }, // 010101 = 21
{ 6, 2, 3, 0, 4, 5, 6 }, // 010110 = 22
{ 0, 0, 0, 0, 0, 0, 0 }, // 010111 = 23
{ 6, 0, 1, 2, 6, 7, 3 }, // 011000 = 24
{ 6, 0, 1, 2, 6, 7, 4 }, // 011001 = 25
{ 6, 0, 1, 5, 6, 7, 3 }, // 011010 = 26
{ 0, 0, 0, 0, 0, 0, 0 }, // 011011 = 27
{ 0, 0, 0, 0, 0, 0, 0 }, // 011100 = 28
{ 0, 0, 0, 0, 0, 0, 0 }, // 011101 = 29
{ 0, 0, 0, 0, 0, 0, 0 }, // 011110 = 30
{ 0, 0, 0, 0, 0, 0, 0 }, // 011111 = 31
{ 4, 7, 6, 5, 4, 0, 0 }, // 100000 = 32
{ 6, 7, 6, 5, 4, 0, 3 }, // 100001 = 33
{ 6, 5, 4, 7, 6, 2, 1 }, // 100010 = 34
{ 0, 0, 0, 0, 0, 0, 0 }, // 100011 = 35
{ 6, 4, 7, 6, 5, 1, 0 }, // 100100 = 36
{ 6, 3, 7, 6, 5, 1, 0 }, // 100101 = 37
{ 6, 4, 7, 6, 2, 1, 0 }, // 100110 = 38
{ 0, 0, 0, 0, 0, 0, 0 }, // 100111 = 39
{ 6, 6, 5, 4, 7, 3, 2 }, // 101000 = 40
{ 6, 6, 5, 4, 0, 3, 2 }, // 101001 = 41
{ 6, 5, 4, 7, 3, 2, 1 }, // 101010 = 42
{ 0, 0, 0, 0, 0, 0, 0 }, // 101011 = 43
{ 0, 0, 0, 0, 0, 0, 0 }, // 101100 = 44
{ 0, 0, 0, 0, 0, 0, 0 }, // 101101 = 45
{ 0, 0, 0, 0, 0, 0, 0 }, // 101110 = 46
{ 0, 0, 0, 0, 0, 0, 0 }, // 101111 = 47
{ 0, 0, 0, 0, 0, 0, 0 }, // 110000 = 48
{ 0, 0, 0, 0, 0, 0, 0 }, // 110001 = 49
{ 0, 0, 0, 0, 0, 0, 0 }, // 110010 = 50
{ 0, 0, 0, 0, 0, 0, 0 }, // 110011 = 51
{ 0, 0, 0, 0, 0, 0, 0 }, // 110100 = 52
{ 0, 0, 0, 0, 0, 0, 0 }, // 110101 = 53
{ 0, 0, 0, 0, 0, 0, 0 }, // 110110 = 54
{ 0, 0, 0, 0, 0, 0, 0 }, // 110111 = 55
{ 0, 0, 0, 0, 0, 0, 0 }, // 111000 = 56
{ 0, 0, 0, 0, 0, 0, 0 }, // 111001 = 57
{ 0, 0, 0, 0, 0, 0, 0 }, // 111010 = 58
{ 0, 0, 0, 0, 0, 0, 0 }, // 111011 = 59
{ 0, 0, 0, 0, 0, 0, 0 }, // 111100 = 60
{ 0, 0, 0, 0, 0, 0, 0 }, // 111101 = 61
{ 0, 0, 0, 0, 0, 0, 0 }, // 111110 = 62
{ 0, 0, 0, 0, 0, 0, 0 }, // 111111 = 63
};
/*
============
idBox::AddPoint
============
*/
bool idBox::AddPoint( const idVec3 &v ) {
idMat3 axis2;
idBounds bounds1, bounds2;
if ( extents[0] < 0.0f ) {
extents.Zero();
center = v;
axis.Identity();
return true;
}
bounds1[0][0] = bounds1[1][0] = center * axis[0];
bounds1[0][1] = bounds1[1][1] = center * axis[1];
bounds1[0][2] = bounds1[1][2] = center * axis[2];
bounds1[0] -= extents;
bounds1[1] += extents;
if ( !bounds1.AddPoint( idVec3( v * axis[0], v * axis[1], v * axis[2] ) ) ) {
// point is contained in the box
return false;
}
axis2[0] = v - center;
axis2[0].Normalize();
axis2[1] = axis[ Min3Index( axis2[0] * axis[0], axis2[0] * axis[1], axis2[0] * axis[2] ) ];
axis2[1] = axis2[1] - ( axis2[1] * axis2[0] ) * axis2[0];
axis2[1].Normalize();
axis2[2].Cross( axis2[0], axis2[1] );
AxisProjection( axis2, bounds2 );
bounds2.AddPoint( idVec3( v * axis2[0], v * axis2[1], v * axis2[2] ) );
// create new box based on the smallest bounds
if ( bounds1.GetVolume() < bounds2.GetVolume() ) {
center = ( bounds1[0] + bounds1[1] ) * 0.5f;
extents = bounds1[1] - center;
center *= axis;
}
else {
center = ( bounds2[0] + bounds2[1] ) * 0.5f;
extents = bounds2[1] - center;
center *= axis2;
axis = axis2;
}
return true;
}
/*
============
idBox::AddBox
============
*/
bool idBox::AddBox( const idBox &a ) {
int i, besti;
float v, bestv;
idVec3 dir;
idMat3 ax[4];
idBounds bounds[4], b;
if ( a.extents[0] < 0.0f ) {
return false;
}
if ( extents[0] < 0.0f ) {
center = a.center;
extents = a.extents;
axis = a.axis;
return true;
}
// test axis of this box
ax[0] = axis;
bounds[0][0][0] = bounds[0][1][0] = center * ax[0][0];
bounds[0][0][1] = bounds[0][1][1] = center * ax[0][1];
bounds[0][0][2] = bounds[0][1][2] = center * ax[0][2];
bounds[0][0] -= extents;
bounds[0][1] += extents;
a.AxisProjection( ax[0], b );
if ( !bounds[0].AddBounds( b ) ) {
// the other box is contained in this box
return false;
}
// test axis of other box
ax[1] = a.axis;
bounds[1][0][0] = bounds[1][1][0] = a.center * ax[1][0];
bounds[1][0][1] = bounds[1][1][1] = a.center * ax[1][1];
bounds[1][0][2] = bounds[1][1][2] = a.center * ax[1][2];
bounds[1][0] -= a.extents;
bounds[1][1] += a.extents;
AxisProjection( ax[1], b );
if ( !bounds[1].AddBounds( b ) ) {
// this box is contained in the other box
center = a.center;
extents = a.extents;
axis = a.axis;
return true;
}
// test axes aligned with the vector between the box centers and one of the box axis
dir = a.center - center;
dir.Normalize();
for ( i = 2; i < 4; i++ ) {
ax[i][0] = dir;
ax[i][1] = ax[i-2][ Min3Index( dir * ax[i-2][0], dir * ax[i-2][1], dir * ax[i-2][2] ) ];
ax[i][1] = ax[i][1] - ( ax[i][1] * dir ) * dir;
ax[i][1].Normalize();
ax[i][2].Cross( dir, ax[i][1] );
AxisProjection( ax[i], bounds[i] );
a.AxisProjection( ax[i], b );
bounds[i].AddBounds( b );
}
// get the bounds with the smallest volume
bestv = idMath::INFINITY;
besti = 0;
for ( i = 0; i < 4; i++ ) {
v = bounds[i].GetVolume();
if ( v < bestv ) {
bestv = v;
besti = i;
}
}
// create a box from the smallest bounds axis pair
center = ( bounds[besti][0] + bounds[besti][1] ) * 0.5f;
extents = bounds[besti][1] - center;
center *= ax[besti];
axis = ax[besti];
return false;
}
/*
================
idBox::PlaneDistance
================
*/
float idBox::PlaneDistance( const idPlane &plane ) const {
float d1, d2;
d1 = plane.Distance( center );
d2 = idMath::Fabs( extents[0] * plane.Normal()[0] ) +
idMath::Fabs( extents[1] * plane.Normal()[1] ) +
idMath::Fabs( extents[2] * plane.Normal()[2] );
if ( d1 - d2 > 0.0f ) {
return d1 - d2;
}
if ( d1 + d2 < 0.0f ) {
return d1 + d2;
}
return 0.0f;
}
/*
================
idBox::PlaneSide
================
*/
int idBox::PlaneSide( const idPlane &plane, const float epsilon ) const {
float d1, d2;
d1 = plane.Distance( center );
d2 = idMath::Fabs( extents[0] * plane.Normal()[0] ) +
idMath::Fabs( extents[1] * plane.Normal()[1] ) +
idMath::Fabs( extents[2] * plane.Normal()[2] );
if ( d1 - d2 > epsilon ) {
return PLANESIDE_FRONT;
}
if ( d1 + d2 < -epsilon ) {
return PLANESIDE_BACK;
}
return PLANESIDE_CROSS;
}
/*
============
idBox::IntersectsBox
============
*/
bool idBox::IntersectsBox( const idBox &a ) const {
idVec3 dir; // vector between centers
float c[3][3]; // matrix c = axis.Transpose() * a.axis
float ac[3][3]; // absolute values of c
float axisdir[3]; // axis[i] * dir
float d, e0, e1; // distance between centers and projected extents
dir = a.center - center;
// axis C0 + t * A0
c[0][0] = axis[0] * a.axis[0];
c[0][1] = axis[0] * a.axis[1];
c[0][2] = axis[0] * a.axis[2];
axisdir[0] = axis[0] * dir;
ac[0][0] = idMath::Fabs( c[0][0] );
ac[0][1] = idMath::Fabs( c[0][1] );
ac[0][2] = idMath::Fabs( c[0][2] );
d = idMath::Fabs( axisdir[0] );
e0 = extents[0];
e1 = a.extents[0] * ac[0][0] + a.extents[1] * ac[0][1] + a.extents[2] * ac[0][2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1
c[1][0] = axis[1] * a.axis[0];
c[1][1] = axis[1] * a.axis[1];
c[1][2] = axis[1] * a.axis[2];
axisdir[1] = axis[1] * dir;
ac[1][0] = idMath::Fabs( c[1][0] );
ac[1][1] = idMath::Fabs( c[1][1] );
ac[1][2] = idMath::Fabs( c[1][2] );
d = idMath::Fabs( axisdir[1] );
e0 = extents[1];
e1 = a.extents[0] * ac[1][0] + a.extents[1] * ac[1][1] + a.extents[2] * ac[1][2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2
c[2][0] = axis[2] * a.axis[0];
c[2][1] = axis[2] * a.axis[1];
c[2][2] = axis[2] * a.axis[2];
axisdir[2] = axis[2] * dir;
ac[2][0] = idMath::Fabs( c[2][0] );
ac[2][1] = idMath::Fabs( c[2][1] );
ac[2][2] = idMath::Fabs( c[2][2] );
d = idMath::Fabs( axisdir[2] );
e0 = extents[2];
e1 = a.extents[0] * ac[2][0] + a.extents[1] * ac[2][1] + a.extents[2] * ac[2][2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * B0
d = idMath::Fabs( a.axis[0] * dir );
e0 = extents[0] * ac[0][0] + extents[1] * ac[1][0] + extents[2] * ac[2][0];
e1 = a.extents[0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * B1
d = idMath::Fabs( a.axis[1] * dir );
e0 = extents[0] * ac[0][1] + extents[1] * ac[1][1] + extents[2] * ac[2][1];
e1 = a.extents[1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * B2
d = idMath::Fabs( a.axis[2] * dir );
e0 = extents[0] * ac[0][2] + extents[1] * ac[1][2] + extents[2] * ac[2][2];
e1 = a.extents[2];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A0xB0
d = idMath::Fabs( axisdir[2] * c[1][0] - axisdir[1] * c[2][0] );
e0 = extents[1] * ac[2][0] + extents[2] * ac[1][0];
e1 = a.extents[1] * ac[0][2] + a.extents[2] * ac[0][1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A0xB1
d = idMath::Fabs( axisdir[2] * c[1][1] - axisdir[1] * c[2][1] );
e0 = extents[1] * ac[2][1] + extents[2] * ac[1][1];
e1 = a.extents[0] * ac[0][2] + a.extents[2] * ac[0][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A0xB2
d = idMath::Fabs( axisdir[2] * c[1][2] - axisdir[1] * c[2][2] );
e0 = extents[1] * ac[2][2] + extents[2] * ac[1][2];
e1 = a.extents[0] * ac[0][1] + a.extents[1] * ac[0][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1xB0
d = idMath::Fabs( axisdir[0] * c[2][0] - axisdir[2] * c[0][0] );
e0 = extents[0] * ac[2][0] + extents[2] * ac[0][0];
e1 = a.extents[1] * ac[1][2] + a.extents[2] * ac[1][1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1xB1
d = idMath::Fabs( axisdir[0] * c[2][1] - axisdir[2] * c[0][1] );
e0 = extents[0] * ac[2][1] + extents[2] * ac[0][1];
e1 = a.extents[0] * ac[1][2] + a.extents[2] * ac[1][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A1xB2
d = idMath::Fabs( axisdir[0] * c[2][2] - axisdir[2] * c[0][2] );
e0 = extents[0] * ac[2][2] + extents[2] * ac[0][2];
e1 = a.extents[0] * ac[1][1] + a.extents[1] * ac[1][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2xB0
d = idMath::Fabs( axisdir[1] * c[0][0] - axisdir[0] * c[1][0] );
e0 = extents[0] * ac[1][0] + extents[1] * ac[0][0];
e1 = a.extents[1] * ac[2][2] + a.extents[2] * ac[2][1];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2xB1
d = idMath::Fabs( axisdir[1] * c[0][1] - axisdir[0] * c[1][1] );
e0 = extents[0] * ac[1][1] + extents[1] * ac[0][1];
e1 = a.extents[0] * ac[2][2] + a.extents[2] * ac[2][0];
if ( d > e0 + e1 ) {
return false;
}
// axis C0 + t * A2xB2
d = idMath::Fabs( axisdir[1] * c[0][2] - axisdir[0] * c[1][2] );
e0 = extents[0] * ac[1][2] + extents[1] * ac[0][2];
e1 = a.extents[0] * ac[2][1] + a.extents[1] * ac[2][0];
if ( d > e0 + e1 ) {
return false;
}
return true;
}
/*
============
idBox::LineIntersection
Returns true if the line intersects the box between the start and end point.
============
*/
bool idBox::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
float ld[3];
idVec3 lineDir = 0.5f * ( end - start );
idVec3 lineCenter = start + lineDir;
idVec3 dir = lineCenter - center;
ld[0] = idMath::Fabs( lineDir * axis[0] );
if ( idMath::Fabs( dir * axis[0] ) > extents[0] + ld[0] ) {
return false;
}
ld[1] = idMath::Fabs( lineDir * axis[1] );
if ( idMath::Fabs( dir * axis[1] ) > extents[1] + ld[1] ) {
return false;
}
ld[2] = idMath::Fabs( lineDir * axis[2] );
if ( idMath::Fabs( dir * axis[2] ) > extents[2] + ld[2] ) {
return false;
}
idVec3 cross = lineDir.Cross( dir );
if ( idMath::Fabs( cross * axis[0] ) > extents[1] * ld[2] + extents[2] * ld[1] ) {
return false;
}
if ( idMath::Fabs( cross * axis[1] ) > extents[0] * ld[2] + extents[2] * ld[0] ) {
return false;
}
if ( idMath::Fabs( cross * axis[2] ) > extents[0] * ld[1] + extents[1] * ld[0] ) {
return false;
}
return true;
}
/*
============
BoxPlaneClip
============
*/
static bool BoxPlaneClip( const float denom, const float numer, float &scale0, float &scale1 ) {
if ( denom > 0.0f ) {
if ( numer > denom * scale1 ) {
return false;
}
if ( numer > denom * scale0 ) {
scale0 = numer / denom;
}
return true;
}
else if ( denom < 0.0f ) {
if ( numer > denom * scale0 ) {
return false;
}
if ( numer > denom * scale1 ) {
scale1 = numer / denom;
}
return true;
}
else {
return ( numer <= 0.0f );
}
}
/*
============
idBox::RayIntersection
Returns true if the ray intersects the box.
The ray can intersect the box in both directions from the start point.
If start is inside the box then scale1 < 0 and scale2 > 0.
============
*/
bool idBox::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
idVec3 localStart, localDir;
localStart = ( start - center ) * axis.Transpose();
localDir = dir * axis.Transpose();
scale1 = -idMath::INFINITY;
scale2 = idMath::INFINITY;
return BoxPlaneClip( localDir.x, -localStart.x - extents[0], scale1, scale2 ) &&
BoxPlaneClip( -localDir.x, localStart.x - extents[0], scale1, scale2 ) &&
BoxPlaneClip( localDir.y, -localStart.y - extents[1], scale1, scale2 ) &&
BoxPlaneClip( -localDir.y, localStart.y - extents[1], scale1, scale2 ) &&
BoxPlaneClip( localDir.z, -localStart.z - extents[2], scale1, scale2 ) &&
BoxPlaneClip( -localDir.z, localStart.z - extents[2], scale1, scale2 );
}
/*
============
idBox::FromPoints
Tight box for a collection of points.
============
*/
void idBox::FromPoints( const idVec3 *points, const int numPoints ) {
int i;
float invNumPoints, sumXX, sumXY, sumXZ, sumYY, sumYZ, sumZZ;
idVec3 dir;
idBounds bounds;
idMatX eigenVectors;
idVecX eigenValues;
// compute mean of points
center = points[0];
for ( i = 1; i < numPoints; i++ ) {
center += points[i];
}
invNumPoints = 1.0f / numPoints;
center *= invNumPoints;
// compute covariances of points
sumXX = 0.0f; sumXY = 0.0f; sumXZ = 0.0f;
sumYY = 0.0f; sumYZ = 0.0f; sumZZ = 0.0f;
for ( i = 0; i < numPoints; i++ ) {
dir = points[i] - center;
sumXX += dir.x * dir.x;
sumXY += dir.x * dir.y;
sumXZ += dir.x * dir.z;
sumYY += dir.y * dir.y;
sumYZ += dir.y * dir.z;
sumZZ += dir.z * dir.z;
}
sumXX *= invNumPoints;
sumXY *= invNumPoints;
sumXZ *= invNumPoints;
sumYY *= invNumPoints;
sumYZ *= invNumPoints;
sumZZ *= invNumPoints;
// compute eigenvectors for covariance matrix
eigenValues.SetData( 3, VECX_ALLOCA( 3 ) );
eigenVectors.SetData( 3, 3, MATX_ALLOCA( 3 * 3 ) );
eigenVectors[0][0] = sumXX;
eigenVectors[0][1] = sumXY;
eigenVectors[0][2] = sumXZ;
eigenVectors[1][0] = sumXY;
eigenVectors[1][1] = sumYY;
eigenVectors[1][2] = sumYZ;
eigenVectors[2][0] = sumXZ;
eigenVectors[2][1] = sumYZ;
eigenVectors[2][2] = sumZZ;
eigenVectors.Eigen_SolveSymmetric( eigenValues );
eigenVectors.Eigen_SortIncreasing( eigenValues );
axis[0][0] = eigenVectors[0][0];
axis[0][1] = eigenVectors[0][1];
axis[0][2] = eigenVectors[0][2];
axis[1][0] = eigenVectors[1][0];
axis[1][1] = eigenVectors[1][1];
axis[1][2] = eigenVectors[1][2];
axis[2][0] = eigenVectors[2][0];
axis[2][1] = eigenVectors[2][1];
axis[2][2] = eigenVectors[2][2];
extents[0] = eigenValues[0];
extents[1] = eigenValues[0];
extents[2] = eigenValues[0];
// refine by calculating the bounds of the points projected onto the axis and adjusting the center and extents
bounds.Clear();
for ( i = 0; i < numPoints; i++ ) {
bounds.AddPoint( idVec3( points[i] * axis[0], points[i] * axis[1], points[i] * axis[2] ) );
}
center = ( bounds[0] + bounds[1] ) * 0.5f;
extents = bounds[1] - center;
center *= axis;
}
/*
============
idBox::FromPointTranslation
Most tight box for the translational movement of the given point.
============
*/
void idBox::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
// FIXME: implement
}
/*
============
idBox::FromBoxTranslation
Most tight box for the translational movement of the given box.
============
*/
void idBox::FromBoxTranslation( const idBox &box, const idVec3 &translation ) {
// FIXME: implement
}
/*
============
idBox::FromPointRotation
Most tight bounds for the rotational movement of the given point.
============
*/
void idBox::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
// FIXME: implement
}
/*
============
idBox::FromBoxRotation
Most tight box for the rotational movement of the given box.
============
*/
void idBox::FromBoxRotation( const idBox &box, const idRotation &rotation ) {
// FIXME: implement
}
/*
============
idBox::ToPoints
============
*/
void idBox::ToPoints( idVec3 points[8] ) const {
idMat3 ax;
idVec3 temp[4];
ax[0] = extents[0] * axis[0];
ax[1] = extents[1] * axis[1];
ax[2] = extents[2] * axis[2];
temp[0] = center - ax[0];
temp[1] = center + ax[0];
temp[2] = ax[1] - ax[2];
temp[3] = ax[1] + ax[2];
points[0] = temp[0] - temp[3];
points[1] = temp[1] - temp[3];
points[2] = temp[1] + temp[2];
points[3] = temp[0] + temp[2];
points[4] = temp[0] - temp[2];
points[5] = temp[1] - temp[2];
points[6] = temp[1] + temp[3];
points[7] = temp[0] + temp[3];
}
/*
============
idBox::GetProjectionSilhouetteVerts
============
*/
int idBox::GetProjectionSilhouetteVerts( const idVec3 &projectionOrigin, idVec3 silVerts[6] ) const {
float f;
int i, planeBits, *index;
idVec3 points[8], dir1, dir2;
ToPoints( points );
dir1 = points[0] - projectionOrigin;
dir2 = points[6] - projectionOrigin;
f = dir1 * axis[0];
planeBits = IEEE_FLT_SIGNBITNOTSET( f );
f = dir2 * axis[0];
planeBits |= IEEE_FLT_SIGNBITSET( f ) << 1;
f = dir1 * axis[1];
planeBits |= IEEE_FLT_SIGNBITNOTSET( f ) << 2;
f = dir2 * axis[1];
planeBits |= IEEE_FLT_SIGNBITSET( f ) << 3;
f = dir1 * axis[2];
planeBits |= IEEE_FLT_SIGNBITNOTSET( f ) << 4;
f = dir2 * axis[2];
planeBits |= IEEE_FLT_SIGNBITSET( f ) << 5;
index = boxPlaneBitsSilVerts[planeBits];
for ( i = 0; i < index[0]; i++ ) {
silVerts[i] = points[index[i+1]];
}
return index[0];
}
/*
============
idBox::GetParallelProjectionSilhouetteVerts
============
*/
int idBox::GetParallelProjectionSilhouetteVerts( const idVec3 &projectionDir, idVec3 silVerts[6] ) const {
float f;
int i, planeBits, *index;
idVec3 points[8];
ToPoints( points );
planeBits = 0;
f = projectionDir * axis[0];
if ( IEEE_FLT_ISNOTZERO( f ) ) {
planeBits = 1 << IEEE_FLT_SIGNBITSET( f );
}
f = projectionDir * axis[1];
if ( IEEE_FLT_ISNOTZERO( f ) ) {
planeBits |= 4 << IEEE_FLT_SIGNBITSET( f );
}
f = projectionDir * axis[2];
if ( IEEE_FLT_ISNOTZERO( f ) ) {
planeBits |= 16 << IEEE_FLT_SIGNBITSET( f );
}
index = boxPlaneBitsSilVerts[planeBits];
for ( i = 0; i < index[0]; i++ ) {
silVerts[i] = points[index[i+1]];
}
return index[0];
}

297
neo/idlib/bv/Box.h Normal file
View File

@@ -0,0 +1,297 @@
/*
===========================================================================
Doom 3 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 __BV_BOX_H__
#define __BV_BOX_H__
/*
===============================================================================
Oriented Bounding Box
===============================================================================
*/
class idBox {
public:
idBox();
explicit idBox( const idVec3 &center, const idVec3 &extents, const idMat3 &axis );
explicit idBox( const idVec3 &point );
explicit idBox( const idBounds &bounds );
explicit idBox( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis );
idBox operator+( const idVec3 &t ) const; // returns translated box
idBox & operator+=( const idVec3 &t ); // translate the box
idBox operator*( const idMat3 &r ) const; // returns rotated box
idBox & operator*=( const idMat3 &r ); // rotate the box
idBox operator+( const idBox &a ) const;
idBox & operator+=( const idBox &a );
idBox operator-( const idBox &a ) const;
idBox & operator-=( const idBox &a );
bool Compare( const idBox &a ) const; // exact compare, no epsilon
bool Compare( const idBox &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idBox &a ) const; // exact compare, no epsilon
bool operator!=( const idBox &a ) const; // exact compare, no epsilon
void Clear(); // inside out box
void Zero(); // single point at origin
const idVec3 & GetCenter() const; // returns center of the box
const idVec3 & GetExtents() const; // returns extents of the box
const idMat3 & GetAxis() const; // returns the axis of the box
float GetVolume() const; // returns the volume of the box
bool IsCleared() const; // returns true if box are inside out
bool AddPoint( const idVec3 &v ); // add the point, returns true if the box expanded
bool AddBox( const idBox &a ); // add the box, returns true if the box expanded
idBox Expand( const float d ) const; // return box expanded in all directions with the given value
idBox & ExpandSelf( const float d ); // expand box in all directions with the given value
idBox Translate( const idVec3 &translation ) const; // return translated box
idBox & TranslateSelf( const idVec3 &translation ); // translate this box
idBox Rotate( const idMat3 &rotation ) const; // return rotated box
idBox & RotateSelf( const idMat3 &rotation ); // rotate this box
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool ContainsPoint( const idVec3 &p ) const; // includes touching
bool IntersectsBox( const idBox &a ) const; // includes touching
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
// intersection points are (start + dir * scale1) and (start + dir * scale2)
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
// tight box for a collection of points
void FromPoints( const idVec3 *points, const int numPoints );
// most tight box for a translation
void FromPointTranslation( const idVec3 &point, const idVec3 &translation );
void FromBoxTranslation( const idBox &box, const idVec3 &translation );
// most tight box for a rotation
void FromPointRotation( const idVec3 &point, const idRotation &rotation );
void FromBoxRotation( const idBox &box, const idRotation &rotation );
void ToPoints( idVec3 points[8] ) const;
idSphere ToSphere() const;
// calculates the projection of this box onto the given axis
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
void AxisProjection( const idMat3 &ax, idBounds &bounds ) const;
// calculates the silhouette of the box
int GetProjectionSilhouetteVerts( const idVec3 &projectionOrigin, idVec3 silVerts[6] ) const;
int GetParallelProjectionSilhouetteVerts( const idVec3 &projectionDir, idVec3 silVerts[6] ) const;
private:
idVec3 center;
idVec3 extents;
idMat3 axis;
};
extern idBox box_zero;
ID_INLINE idBox::idBox() {
}
ID_INLINE idBox::idBox( const idVec3 &center, const idVec3 &extents, const idMat3 &axis ) {
this->center = center;
this->extents = extents;
this->axis = axis;
}
ID_INLINE idBox::idBox( const idVec3 &point ) {
this->center = point;
this->extents.Zero();
this->axis.Identity();
}
ID_INLINE idBox::idBox( const idBounds &bounds ) {
this->center = ( bounds[0] + bounds[1] ) * 0.5f;
this->extents = bounds[1] - this->center;
this->axis.Identity();
}
ID_INLINE idBox::idBox( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis ) {
this->center = ( bounds[0] + bounds[1] ) * 0.5f;
this->extents = bounds[1] - this->center;
this->center = origin + this->center * axis;
this->axis = axis;
}
ID_INLINE idBox idBox::operator+( const idVec3 &t ) const {
return idBox( center + t, extents, axis );
}
ID_INLINE idBox &idBox::operator+=( const idVec3 &t ) {
center += t;
return *this;
}
ID_INLINE idBox idBox::operator*( const idMat3 &r ) const {
return idBox( center * r, extents, axis * r );
}
ID_INLINE idBox &idBox::operator*=( const idMat3 &r ) {
center *= r;
axis *= r;
return *this;
}
ID_INLINE idBox idBox::operator+( const idBox &a ) const {
idBox newBox;
newBox = *this;
newBox.AddBox( a );
return newBox;
}
ID_INLINE idBox &idBox::operator+=( const idBox &a ) {
idBox::AddBox( a );
return *this;
}
ID_INLINE idBox idBox::operator-( const idBox &a ) const {
return idBox( center, extents - a.extents, axis );
}
ID_INLINE idBox &idBox::operator-=( const idBox &a ) {
extents -= a.extents;
return *this;
}
ID_INLINE bool idBox::Compare( const idBox &a ) const {
return ( center.Compare( a.center ) && extents.Compare( a.extents ) && axis.Compare( a.axis ) );
}
ID_INLINE bool idBox::Compare( const idBox &a, const float epsilon ) const {
return ( center.Compare( a.center, epsilon ) && extents.Compare( a.extents, epsilon ) && axis.Compare( a.axis, epsilon ) );
}
ID_INLINE bool idBox::operator==( const idBox &a ) const {
return Compare( a );
}
ID_INLINE bool idBox::operator!=( const idBox &a ) const {
return !Compare( a );
}
ID_INLINE void idBox::Clear() {
center.Zero();
extents[0] = extents[1] = extents[2] = -idMath::INFINITY;
axis.Identity();
}
ID_INLINE void idBox::Zero() {
center.Zero();
extents.Zero();
axis.Identity();
}
ID_INLINE const idVec3 &idBox::GetCenter() const {
return center;
}
ID_INLINE const idVec3 &idBox::GetExtents() const {
return extents;
}
ID_INLINE const idMat3 &idBox::GetAxis() const {
return axis;
}
ID_INLINE float idBox::GetVolume() const {
return ( extents * 2.0f ).LengthSqr();
}
ID_INLINE bool idBox::IsCleared() const {
return extents[0] < 0.0f;
}
ID_INLINE idBox idBox::Expand( const float d ) const {
return idBox( center, extents + idVec3( d, d, d ), axis );
}
ID_INLINE idBox &idBox::ExpandSelf( const float d ) {
extents[0] += d;
extents[1] += d;
extents[2] += d;
return *this;
}
ID_INLINE idBox idBox::Translate( const idVec3 &translation ) const {
return idBox( center + translation, extents, axis );
}
ID_INLINE idBox &idBox::TranslateSelf( const idVec3 &translation ) {
center += translation;
return *this;
}
ID_INLINE idBox idBox::Rotate( const idMat3 &rotation ) const {
return idBox( center * rotation, extents, axis * rotation );
}
ID_INLINE idBox &idBox::RotateSelf( const idMat3 &rotation ) {
center *= rotation;
axis *= rotation;
return *this;
}
ID_INLINE bool idBox::ContainsPoint( const idVec3 &p ) const {
idVec3 lp = p - center;
if ( idMath::Fabs( lp * axis[0] ) > extents[0] ||
idMath::Fabs( lp * axis[1] ) > extents[1] ||
idMath::Fabs( lp * axis[2] ) > extents[2] ) {
return false;
}
return true;
}
ID_INLINE idSphere idBox::ToSphere() const {
return idSphere( center, extents.Length() );
}
ID_INLINE void idBox::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
float d1 = dir * center;
float d2 = idMath::Fabs( extents[0] * ( dir * axis[0] ) ) +
idMath::Fabs( extents[1] * ( dir * axis[1] ) ) +
idMath::Fabs( extents[2] * ( dir * axis[2] ) );
min = d1 - d2;
max = d1 + d2;
}
ID_INLINE void idBox::AxisProjection( const idMat3 &ax, idBounds &bounds ) const {
for ( int i = 0; i < 3; i++ ) {
float d1 = ax[i] * center;
float d2 = idMath::Fabs( extents[0] * ( ax[i] * axis[0] ) ) +
idMath::Fabs( extents[1] * ( ax[i] * axis[1] ) ) +
idMath::Fabs( extents[2] * ( ax[i] * axis[2] ) );
bounds[0][i] = d1 - d2;
bounds[1][i] = d1 + d2;
}
}
#endif /* !__BV_BOX_H__ */

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

@@ -0,0 +1,155 @@
/*
===========================================================================
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"
idSphere sphere_zero( vec3_zero, 0.0f );
/*
================
idSphere::PlaneDistance
================
*/
float idSphere::PlaneDistance( const idPlane &plane ) const {
float d;
d = plane.Distance( origin );
if ( d > radius ) {
return d - radius;
}
if ( d < -radius ) {
return d + radius;
}
return 0.0f;
}
/*
================
idSphere::PlaneSide
================
*/
int idSphere::PlaneSide( const idPlane &plane, const float epsilon ) const {
float d;
d = plane.Distance( origin );
if ( d > radius + epsilon ) {
return PLANESIDE_FRONT;
}
if ( d < -radius - epsilon ) {
return PLANESIDE_BACK;
}
return PLANESIDE_CROSS;
}
/*
============
idSphere::LineIntersection
Returns true if the line intersects the sphere between the start and end point.
============
*/
bool idSphere::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
idVec3 r, s, e;
float a;
s = start - origin;
e = end - origin;
r = e - s;
a = -s * r;
if ( a <= 0 ) {
return ( s * s < radius * radius );
}
else if ( a >= r * r ) {
return ( e * e < radius * radius );
}
else {
r = s + ( a / ( r * r ) ) * r;
return ( r * r < radius * radius );
}
}
/*
============
idSphere::RayIntersection
Returns true if the ray intersects the sphere.
The ray can intersect the sphere in both directions from the start point.
If start is inside the sphere then scale1 < 0 and scale2 > 0.
============
*/
bool idSphere::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
double a, b, c, d, sqrtd;
idVec3 p;
p = start - origin;
a = dir * dir;
b = dir * p;
c = p * p - radius * radius;
d = b * b - c * a;
if ( d < 0.0f ) {
return false;
}
sqrtd = idMath::Sqrt( d );
a = 1.0f / a;
scale1 = ( -b + sqrtd ) * a;
scale2 = ( -b - sqrtd ) * a;
return true;
}
/*
============
idSphere::FromPoints
Tight sphere for a point set.
============
*/
void idSphere::FromPoints( const idVec3 *points, const int numPoints ) {
int i;
float radiusSqr, dist;
idVec3 mins, maxs;
SIMDProcessor->MinMax( mins, maxs, points, numPoints );
origin = ( mins + maxs ) * 0.5f;
radiusSqr = 0.0f;
for ( i = 0; i < numPoints; i++ ) {
dist = ( points[i] - origin ).LengthSqr();
if ( dist > radiusSqr ) {
radiusSqr = dist;
}
}
radius = idMath::Sqrt( radiusSqr );
}

275
neo/idlib/bv/Sphere.h Normal file
View File

@@ -0,0 +1,275 @@
/*
===========================================================================
Doom 3 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 __BV_SPHERE_H__
#define __BV_SPHERE_H__
/*
===============================================================================
Sphere
===============================================================================
*/
class idSphere {
public:
idSphere();
explicit idSphere( const idVec3 &point );
explicit idSphere( const idVec3 &point, const float r );
float operator[]( const int index ) const;
float & operator[]( const int index );
idSphere operator+( const idVec3 &t ) const; // returns tranlated sphere
idSphere & operator+=( const idVec3 &t ); // translate the sphere
idSphere operator+( const idSphere &s ) const;
idSphere & operator+=( const idSphere &s );
bool Compare( const idSphere &a ) const; // exact compare, no epsilon
bool Compare( const idSphere &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idSphere &a ) const; // exact compare, no epsilon
bool operator!=( const idSphere &a ) const; // exact compare, no epsilon
void Clear(); // inside out sphere
void Zero(); // single point at origin
void SetOrigin( const idVec3 &o ); // set origin of sphere
void SetRadius( const float r ); // set square radius
const idVec3 & GetOrigin() const; // returns origin of sphere
float GetRadius() const; // returns sphere radius
bool IsCleared() const; // returns true if sphere is inside out
bool AddPoint( const idVec3 &p ); // add the point, returns true if the sphere expanded
bool AddSphere( const idSphere &s ); // add the sphere, returns true if the sphere expanded
idSphere Expand( const float d ) const; // return bounds expanded in all directions with the given value
idSphere & ExpandSelf( const float d ); // expand bounds in all directions with the given value
idSphere Translate( const idVec3 &translation ) const;
idSphere & TranslateSelf( const idVec3 &translation );
float PlaneDistance( const idPlane &plane ) const;
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
bool ContainsPoint( const idVec3 &p ) const; // includes touching
bool IntersectsSphere( const idSphere &s ) const; // includes touching
bool LineIntersection( const idVec3 &start, const idVec3 &end ) const;
// intersection points are (start + dir * scale1) and (start + dir * scale2)
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const;
// Tight sphere for a point set.
void FromPoints( const idVec3 *points, const int numPoints );
// Most tight sphere for a translation.
void FromPointTranslation( const idVec3 &point, const idVec3 &translation );
void FromSphereTranslation( const idSphere &sphere, const idVec3 &start, const idVec3 &translation );
// Most tight sphere for a rotation.
void FromPointRotation( const idVec3 &point, const idRotation &rotation );
void FromSphereRotation( const idSphere &sphere, const idVec3 &start, const idRotation &rotation );
void AxisProjection( const idVec3 &dir, float &min, float &max ) const;
private:
idVec3 origin;
float radius;
};
extern idSphere sphere_zero;
ID_INLINE idSphere::idSphere() {
}
ID_INLINE idSphere::idSphere( const idVec3 &point ) {
origin = point;
radius = 0.0f;
}
ID_INLINE idSphere::idSphere( const idVec3 &point, const float r ) {
origin = point;
radius = r;
}
ID_INLINE float idSphere::operator[]( const int index ) const {
return ((float *) &origin)[index];
}
ID_INLINE float &idSphere::operator[]( const int index ) {
return ((float *) &origin)[index];
}
ID_INLINE idSphere idSphere::operator+( const idVec3 &t ) const {
return idSphere( origin + t, radius );
}
ID_INLINE idSphere &idSphere::operator+=( const idVec3 &t ) {
origin += t;
return *this;
}
ID_INLINE bool idSphere::Compare( const idSphere &a ) const {
return ( origin.Compare( a.origin ) && radius == a.radius );
}
ID_INLINE bool idSphere::Compare( const idSphere &a, const float epsilon ) const {
return ( origin.Compare( a.origin, epsilon ) && idMath::Fabs( radius - a.radius ) <= epsilon );
}
ID_INLINE bool idSphere::operator==( const idSphere &a ) const {
return Compare( a );
}
ID_INLINE bool idSphere::operator!=( const idSphere &a ) const {
return !Compare( a );
}
ID_INLINE void idSphere::Clear() {
origin.Zero();
radius = -1.0f;
}
ID_INLINE void idSphere::Zero() {
origin.Zero();
radius = 0.0f;
}
ID_INLINE void idSphere::SetOrigin( const idVec3 &o ) {
origin = o;
}
ID_INLINE void idSphere::SetRadius( const float r ) {
radius = r;
}
ID_INLINE const idVec3 &idSphere::GetOrigin() const {
return origin;
}
ID_INLINE float idSphere::GetRadius() const {
return radius;
}
ID_INLINE bool idSphere::IsCleared() const {
return ( radius < 0.0f );
}
ID_INLINE bool idSphere::AddPoint( const idVec3 &p ) {
if ( radius < 0.0f ) {
origin = p;
radius = 0.0f;
return true;
}
else {
float r = ( p - origin ).LengthSqr();
if ( r > radius * radius ) {
r = idMath::Sqrt( r );
origin += ( p - origin ) * 0.5f * (1.0f - radius / r );
radius += 0.5f * ( r - radius );
return true;
}
return false;
}
}
ID_INLINE bool idSphere::AddSphere( const idSphere &s ) {
if ( radius < 0.0f ) {
origin = s.origin;
radius = s.radius;
return true;
}
else {
float r = ( s.origin - origin ).LengthSqr();
if ( r > ( radius + s.radius ) * ( radius + s.radius ) ) {
r = idMath::Sqrt( r );
origin += ( s.origin - origin ) * 0.5f * (1.0f - radius / ( r + s.radius ) );
radius += 0.5f * ( ( r + s.radius ) - radius );
return true;
}
return false;
}
}
ID_INLINE idSphere idSphere::Expand( const float d ) const {
return idSphere( origin, radius + d );
}
ID_INLINE idSphere &idSphere::ExpandSelf( const float d ) {
radius += d;
return *this;
}
ID_INLINE idSphere idSphere::Translate( const idVec3 &translation ) const {
return idSphere( origin + translation, radius );
}
ID_INLINE idSphere &idSphere::TranslateSelf( const idVec3 &translation ) {
origin += translation;
return *this;
}
ID_INLINE bool idSphere::ContainsPoint( const idVec3 &p ) const {
if ( ( p - origin ).LengthSqr() > radius * radius ) {
return false;
}
return true;
}
ID_INLINE bool idSphere::IntersectsSphere( const idSphere &s ) const {
float r = s.radius + radius;
if ( ( s.origin - origin ).LengthSqr() > r * r ) {
return false;
}
return true;
}
ID_INLINE void idSphere::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) {
origin = point + 0.5f * translation;
radius = idMath::Sqrt( 0.5f * translation.LengthSqr() );
}
ID_INLINE void idSphere::FromSphereTranslation( const idSphere &sphere, const idVec3 &start, const idVec3 &translation ) {
origin = start + sphere.origin + 0.5f * translation;
radius = idMath::Sqrt( 0.5f * translation.LengthSqr() ) + sphere.radius;
}
ID_INLINE void idSphere::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
idVec3 end = rotation * point;
origin = ( point + end ) * 0.5f;
radius = idMath::Sqrt( 0.5f * ( end - point ).LengthSqr() );
}
ID_INLINE void idSphere::FromSphereRotation( const idSphere &sphere, const idVec3 &start, const idRotation &rotation ) {
idVec3 end = rotation * sphere.origin;
origin = start + ( sphere.origin + end ) * 0.5f;
radius = idMath::Sqrt( 0.5f * ( end - sphere.origin ).LengthSqr() ) + sphere.radius;
}
ID_INLINE void idSphere::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
float d;
d = dir * origin;
min = d - radius;
max = d + radius;
}
#endif /* !__BV_SPHERE_H__ */

View File

@@ -0,0 +1,115 @@
/*
===========================================================================
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 __ARRAY_H__
#define __ARRAY_H__
/*
================================================
idArray is a replacement for a normal C array.
int myArray[ARRAY_SIZE];
becomes:
idArray<int,ARRAY_SIZE> myArray;
Has no performance overhead in release builds, but
does index range checking in debug builds.
Unlike idTempArray, the memory is allocated inline with the
object, rather than on the heap.
Unlike idStaticList, there are no fields other than the
actual raw data, and the size is fixed.
================================================
*/
template<class T_, int numElements > class idArray {
public:
// returns number of elements in list
int Num() const { return numElements; }
// returns the number of bytes the array takes up
int ByteSize() const { return sizeof( ptr ); }
// memset the entire array to zero
void Zero() { memset( ptr, 0, sizeof( ptr ) ); }
// memset the entire array to a specific value
void Memset( const char fill ) { memset( ptr, fill, numElements * sizeof( *ptr ) ); }
// array operators
const T_ & operator[]( int index ) const { assert( (unsigned)index < (unsigned)numElements ); return ptr[index]; }
T_ & operator[]( int index ) { assert( (unsigned)index < (unsigned)numElements ); return ptr[index]; }
// returns a pointer to the list
const T_ * Ptr() const { return ptr; }
T_ * Ptr() { return ptr; }
private:
T_ ptr[numElements];
};
#define ARRAY_COUNT( arrayName ) ( sizeof( arrayName )/sizeof( arrayName[0] ) )
#define ARRAY_DEF( arrayName ) arrayName, ARRAY_COUNT( arrayName )
/*
================================================
id2DArray is essentially a typedef (as close as we can
get for templates before C++11 anyway) to make
declaring two-dimensional idArrays easier.
Usage:
id2DArray< int, 5, 10 >::type someArray;
================================================
*/
template<class _type_, int _dim1_, int _dim2_ >
struct id2DArray {
typedef idArray< idArray< _type_, _dim2_ >, _dim1_ > type;
};
/*
================================================
idTupleSize
Generic way to get the size of a tuple-like type.
Add specializations as needed.
This is modeled after std::tuple_size from C++11,
which works for std::arrays also.
================================================
*/
template< class _type_ >
struct idTupleSize;
template< class _type_, int _num_ >
struct idTupleSize< idArray< _type_, _num_ > > {
enum { value = _num_ };
};
#endif // !__ARRAY_H__

View File

@@ -0,0 +1,573 @@
/*
===========================================================================
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 __BTREE_H__
#define __BTREE_H__
/*
===============================================================================
Balanced Search Tree
===============================================================================
*/
//#define BTREE_CHECK
template< class objType, class keyType >
class idBTreeNode {
public:
keyType key; // key used for sorting
objType * object; // if != NULL pointer to object stored in leaf node
idBTreeNode * parent; // parent node
idBTreeNode * next; // next sibling
idBTreeNode * prev; // prev sibling
int numChildren; // number of children
idBTreeNode * firstChild; // first child
idBTreeNode * lastChild; // last child
};
template< class objType, class keyType, int maxChildrenPerNode >
class idBTree {
public:
idBTree();
~idBTree();
void Init();
void Shutdown();
idBTreeNode<objType,keyType> * Add( objType *object, keyType key ); // add an object to the tree
void Remove( idBTreeNode<objType,keyType> *node ); // remove an object node from the tree
idBTreeNode<objType,keyType> * NodeFind( keyType key ) const; // find an object using the given key
idBTreeNode<objType,keyType> * NodeFindSmallestLargerEqual( keyType key ) const; // find an object with the smallest key larger equal the given key
idBTreeNode<objType,keyType> * NodeFindLargestSmallerEqual( keyType key ) const; // find an object with the largest key smaller equal the given key
objType * Find( keyType key ) const; // find an object using the given key
objType * FindSmallestLargerEqual( keyType key ) const; // find an object with the smallest key larger equal the given key
objType * FindLargestSmallerEqual( keyType key ) const; // find an object with the largest key smaller equal the given key
idBTreeNode<objType,keyType> * GetRoot() const; // returns the root node of the tree
int GetNodeCount() const; // returns the total number of nodes in the tree
idBTreeNode<objType,keyType> * GetNext( idBTreeNode<objType,keyType> *node ) const; // goes through all nodes of the tree
idBTreeNode<objType,keyType> * GetNextLeaf( idBTreeNode<objType,keyType> *node ) const; // goes through all leaf nodes of the tree
private:
idBTreeNode<objType,keyType> * root;
idBlockAlloc<idBTreeNode<objType,keyType>,128> nodeAllocator;
idBTreeNode<objType,keyType> * AllocNode();
void FreeNode( idBTreeNode<objType,keyType> *node );
void SplitNode( idBTreeNode<objType,keyType> *node );
idBTreeNode<objType,keyType> * MergeNodes( idBTreeNode<objType,keyType> *node1, idBTreeNode<objType,keyType> *node2 );
void CheckTree_r( idBTreeNode<objType,keyType> *node, int &numNodes ) const;
void CheckTree() const;
};
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTree<objType,keyType,maxChildrenPerNode>::idBTree() {
assert( maxChildrenPerNode >= 4 );
root = NULL;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTree<objType,keyType,maxChildrenPerNode>::~idBTree() {
Shutdown();
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::Init() {
root = AllocNode();
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::Shutdown() {
nodeAllocator.Shutdown();
root = NULL;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::Add( objType *object, keyType key ) {
idBTreeNode<objType,keyType> *node, *child, *newNode;
if ( root == NULL ) {
root = AllocNode();
}
if ( root->numChildren >= maxChildrenPerNode ) {
newNode = AllocNode();
newNode->key = root->key;
newNode->firstChild = root;
newNode->lastChild = root;
newNode->numChildren = 1;
root->parent = newNode;
SplitNode( root );
root = newNode;
}
newNode = AllocNode();
newNode->key = key;
newNode->object = object;
for ( node = root; node->firstChild != NULL; node = child ) {
if ( key > node->key ) {
node->key = key;
}
// find the first child with a key larger equal to the key of the new node
for( child = node->firstChild; child->next; child = child->next ) {
if ( key <= child->key ) {
break;
}
}
if ( child->object ) {
if ( key <= child->key ) {
// insert new node before child
if ( child->prev ) {
child->prev->next = newNode;
} else {
node->firstChild = newNode;
}
newNode->prev = child->prev;
newNode->next = child;
child->prev = newNode;
} else {
// insert new node after child
if ( child->next ) {
child->next->prev = newNode;
} else {
node->lastChild = newNode;
}
newNode->prev = child;
newNode->next = child->next;
child->next = newNode;
}
newNode->parent = node;
node->numChildren++;
#ifdef BTREE_CHECK
CheckTree();
#endif
return newNode;
}
// make sure the child has room to store another node
if ( child->numChildren >= maxChildrenPerNode ) {
SplitNode( child );
if ( key <= child->prev->key ) {
child = child->prev;
}
}
}
// we only end up here if the root node is empty
newNode->parent = root;
root->key = key;
root->firstChild = newNode;
root->lastChild = newNode;
root->numChildren++;
#ifdef BTREE_CHECK
CheckTree();
#endif
return newNode;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::Remove( idBTreeNode<objType,keyType> *node ) {
idBTreeNode<objType,keyType> *parent;
assert( node->object != NULL );
// unlink the node from it's parent
if ( node->prev ) {
node->prev->next = node->next;
} else {
node->parent->firstChild = node->next;
}
if ( node->next ) {
node->next->prev = node->prev;
} else {
node->parent->lastChild = node->prev;
}
node->parent->numChildren--;
// make sure there are no parent nodes with a single child
for ( parent = node->parent; parent != root && parent->numChildren <= 1; parent = parent->parent ) {
if ( parent->next ) {
parent = MergeNodes( parent, parent->next );
} else if ( parent->prev ) {
parent = MergeNodes( parent->prev, parent );
}
// a parent may not use a key higher than the key of it's last child
if ( parent->key > parent->lastChild->key ) {
parent->key = parent->lastChild->key;
}
if ( parent->numChildren > maxChildrenPerNode ) {
SplitNode( parent );
break;
}
}
for ( ; parent != NULL && parent->lastChild != NULL; parent = parent->parent ) {
// a parent may not use a key higher than the key of it's last child
if ( parent->key > parent->lastChild->key ) {
parent->key = parent->lastChild->key;
}
}
// free the node
FreeNode( node );
// remove the root node if it has a single internal node as child
if ( root->numChildren == 1 && root->firstChild->object == NULL ) {
idBTreeNode<objType,keyType> *oldRoot = root;
root->firstChild->parent = NULL;
root = root->firstChild;
FreeNode( oldRoot );
}
#ifdef BTREE_CHECK
CheckTree();
#endif
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> * idBTree<objType,keyType,maxChildrenPerNode>::NodeFind( keyType key ) const {
idBTreeNode<objType,keyType> *node;
for ( node = root->firstChild; node != NULL; node = node->firstChild ) {
while( node->next ) {
if ( node->key >= key ) {
break;
}
node = node->next;
}
if ( node->object ) {
if ( node->key == key ) {
return node;
} else {
return NULL;
}
}
}
return NULL;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> * idBTree<objType,keyType,maxChildrenPerNode>::NodeFindSmallestLargerEqual( keyType key ) const {
idBTreeNode<objType,keyType> *node;
if ( root == NULL ) {
return NULL;
}
for ( node = root->firstChild; node != NULL; node = node->firstChild ) {
while( node->next ) {
if ( node->key >= key ) {
break;
}
node = node->next;
}
if ( node->object ) {
if ( node->key >= key ) {
return node;
} else {
return NULL;
}
}
}
return NULL;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> * idBTree<objType,keyType,maxChildrenPerNode>::NodeFindLargestSmallerEqual( keyType key ) const {
idBTreeNode<objType,keyType> *node;
if ( root == NULL ) {
return NULL;
}
idBTreeNode<objType,keyType> * smaller = NULL;
for ( node = root->firstChild; node != NULL; node = node->firstChild ) {
while( node->next ) {
if ( node->key >= key ) {
break;
}
smaller = node;
node = node->next;
}
if ( node->object ) {
if ( node->key <= key ) {
return node;
} else if ( smaller == NULL ) {
return NULL;
} else {
node = smaller;
if ( node->object ) {
return node;
}
}
}
}
return NULL;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE objType *idBTree<objType,keyType,maxChildrenPerNode>::Find( keyType key ) const {
idBTreeNode<objType,keyType> * node = NodeFind( key );
if ( node == NULL ) {
return NULL;
} else {
return node->object;
}
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE objType *idBTree<objType,keyType,maxChildrenPerNode>::FindSmallestLargerEqual( keyType key ) const {
idBTreeNode<objType,keyType> * node = NodeFindSmallestLargerEqual( key );
if ( node == NULL ) {
return NULL;
} else {
return node->object;
}
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE objType *idBTree<objType,keyType,maxChildrenPerNode>::FindLargestSmallerEqual( keyType key ) const {
idBTreeNode<objType,keyType> * node = NodeFindLargestSmallerEqual( key );
if ( node == NULL ) {
return NULL;
} else {
return node->object;
}
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::GetRoot() const {
return root;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE int idBTree<objType,keyType,maxChildrenPerNode>::GetNodeCount() const {
return nodeAllocator.GetAllocCount();
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::GetNext( idBTreeNode<objType,keyType> *node ) const {
if ( node->firstChild ) {
return node->firstChild;
} else {
while( node && node->next == NULL ) {
node = node->parent;
}
return node;
}
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::GetNextLeaf( idBTreeNode<objType,keyType> *node ) const {
if ( node->firstChild ) {
while ( node->firstChild ) {
node = node->firstChild;
}
return node;
} else {
while( node && node->next == NULL ) {
node = node->parent;
}
if ( node ) {
node = node->next;
while ( node->firstChild ) {
node = node->firstChild;
}
return node;
} else {
return NULL;
}
}
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::AllocNode() {
idBTreeNode<objType,keyType> *node = nodeAllocator.Alloc();
node->key = 0;
node->parent = NULL;
node->next = NULL;
node->prev = NULL;
node->numChildren = 0;
node->firstChild = NULL;
node->lastChild = NULL;
node->object = NULL;
return node;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::FreeNode( idBTreeNode<objType,keyType> *node ) {
nodeAllocator.Free( node );
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::SplitNode( idBTreeNode<objType,keyType> *node ) {
int i;
idBTreeNode<objType,keyType> *child, *newNode;
// allocate a new node
newNode = AllocNode();
newNode->parent = node->parent;
// divide the children over the two nodes
child = node->firstChild;
child->parent = newNode;
for ( i = 3; i < node->numChildren; i += 2 ) {
child = child->next;
child->parent = newNode;
}
newNode->key = child->key;
newNode->numChildren = node->numChildren / 2;
newNode->firstChild = node->firstChild;
newNode->lastChild = child;
node->numChildren -= newNode->numChildren;
node->firstChild = child->next;
child->next->prev = NULL;
child->next = NULL;
// add the new child to the parent before the split node
assert( node->parent->numChildren < maxChildrenPerNode );
if ( node->prev ) {
node->prev->next = newNode;
} else {
node->parent->firstChild = newNode;
}
newNode->prev = node->prev;
newNode->next = node;
node->prev = newNode;
node->parent->numChildren++;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::MergeNodes( idBTreeNode<objType,keyType> *node1, idBTreeNode<objType,keyType> *node2 ) {
idBTreeNode<objType,keyType> *child;
assert( node1->parent == node2->parent );
assert( node1->next == node2 && node2->prev == node1 );
assert( node1->object == NULL && node2->object == NULL );
assert( node1->numChildren >= 1 && node2->numChildren >= 1 );
for ( child = node1->firstChild; child->next; child = child->next ) {
child->parent = node2;
}
child->parent = node2;
child->next = node2->firstChild;
node2->firstChild->prev = child;
node2->firstChild = node1->firstChild;
node2->numChildren += node1->numChildren;
// unlink the first node from the parent
if ( node1->prev ) {
node1->prev->next = node2;
} else {
node1->parent->firstChild = node2;
}
node2->prev = node1->prev;
node2->parent->numChildren--;
FreeNode( node1 );
return node2;
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::CheckTree_r( idBTreeNode<objType,keyType> *node, int &numNodes ) const {
int numChildren;
idBTreeNode<objType,keyType> *child;
numNodes++;
// the root node may have zero children and leaf nodes always have zero children, all other nodes should have at least 2 and at most maxChildrenPerNode children
assert( ( node == root ) || ( node->object != NULL && node->numChildren == 0 ) || ( node->numChildren >= 2 && node->numChildren <= maxChildrenPerNode ) );
// the key of a node may never be larger than the key of it's last child
assert( ( node->lastChild == NULL ) || ( node->key <= node->lastChild->key ) );
numChildren = 0;
for ( child = node->firstChild; child; child = child->next ) {
numChildren++;
// make sure the children are properly linked
if ( child->prev == NULL ) {
assert( node->firstChild == child );
} else {
assert( child->prev->next == child );
}
if ( child->next == NULL ) {
assert( node->lastChild == child );
} else {
assert( child->next->prev == child );
}
// recurse down the tree
CheckTree_r( child, numNodes );
}
// the number of children should equal the number of linked children
assert( numChildren == node->numChildren );
}
template< class objType, class keyType, int maxChildrenPerNode >
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::CheckTree() const {
int numNodes = 0;
idBTreeNode<objType,keyType> *node, *lastNode;
CheckTree_r( root, numNodes );
// the number of nodes in the tree should equal the number of allocated nodes
assert( numNodes == nodeAllocator.GetAllocCount() );
// all the leaf nodes should be ordered
lastNode = GetNextLeaf( GetRoot() );
if ( lastNode ) {
for ( node = GetNextLeaf( lastNode ); node; lastNode = node, node = GetNextLeaf( node ) ) {
assert( lastNode->key <= node->key );
}
}
}
#endif /* !__BTREE_H__ */

View File

@@ -0,0 +1,138 @@
/*
===========================================================================
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 __BINSEARCH_H__
#define __BINSEARCH_H__
/*
===============================================================================
Binary Search templates
The array elements have to be ordered in increasing order.
===============================================================================
*/
/*
====================
idBinSearch_GreaterEqual
Finds the last array element which is smaller than the given value.
====================
*/
template< class type >
ID_INLINE int idBinSearch_Less( const type *array, const int arraySize, const type &value ) {
int len = arraySize;
int mid = len;
int offset = 0;
while( mid > 0 ) {
mid = len >> 1;
if ( array[offset+mid] < value ) {
offset += mid;
}
len -= mid;
}
return offset;
}
/*
====================
idBinSearch_GreaterEqual
Finds the last array element which is smaller than or equal to the given value.
====================
*/
template< class type >
ID_INLINE int idBinSearch_LessEqual( const type *array, const int arraySize, const type &value ) {
int len = arraySize;
int mid = len;
int offset = 0;
while( mid > 0 ) {
mid = len >> 1;
if ( array[offset+mid] <= value ) {
offset += mid;
}
len -= mid;
}
return offset;
}
/*
====================
idBinSearch_Greater
Finds the first array element which is greater than the given value.
====================
*/
template< class type >
ID_INLINE int idBinSearch_Greater( const type *array, const int arraySize, const type &value ) {
int len = arraySize;
int mid = len;
int offset = 0;
int res = 0;
while( mid > 0 ) {
mid = len >> 1;
if ( array[offset+mid] > value ) {
res = 0;
} else {
offset += mid;
res = 1;
}
len -= mid;
}
return offset+res;
}
/*
====================
idBinSearch_GreaterEqual
Finds the first array element which is greater than or equal to the given value.
====================
*/
template< class type >
ID_INLINE int idBinSearch_GreaterEqual( const type *array, const int arraySize, const type &value ) {
int len = arraySize;
int mid = len;
int offset = 0;
int res = 0;
while( mid > 0 ) {
mid = len >> 1;
if ( array[offset+mid] >= value ) {
res = 0;
} else {
offset += mid;
res = 1;
}
len -= mid;
}
return offset+res;
}
#endif /* !__BINSEARCH_H__ */

View File

@@ -0,0 +1,155 @@
/*
===========================================================================
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"
int idHashIndex::INVALID_INDEX[1] = { -1 };
/*
================
idHashIndex::Init
================
*/
void idHashIndex::Init( const int initialHashSize, const int initialIndexSize ) {
assert( idMath::IsPowerOfTwo( initialHashSize ) );
hashSize = initialHashSize;
hash = INVALID_INDEX;
indexSize = initialIndexSize;
indexChain = INVALID_INDEX;
granularity = DEFAULT_HASH_GRANULARITY;
hashMask = hashSize - 1;
lookupMask = 0;
}
/*
================
idHashIndex::Allocate
================
*/
void idHashIndex::Allocate( const int newHashSize, const int newIndexSize ) {
assert( idMath::IsPowerOfTwo( newHashSize ) );
Free();
hashSize = newHashSize;
hash = new (TAG_IDLIB_HASH) int[hashSize];
memset( hash, 0xff, hashSize * sizeof( hash[0] ) );
indexSize = newIndexSize;
indexChain = new (TAG_IDLIB_HASH) int[indexSize];
memset( indexChain, 0xff, indexSize * sizeof( indexChain[0] ) );
hashMask = hashSize - 1;
lookupMask = -1;
}
/*
================
idHashIndex::Free
================
*/
void idHashIndex::Free() {
if ( hash != INVALID_INDEX ) {
delete[] hash;
hash = INVALID_INDEX;
}
if ( indexChain != INVALID_INDEX ) {
delete[] indexChain;
indexChain = INVALID_INDEX;
}
lookupMask = 0;
}
/*
================
idHashIndex::ResizeIndex
================
*/
void idHashIndex::ResizeIndex( const int newIndexSize ) {
int *oldIndexChain, mod, newSize;
if ( newIndexSize <= indexSize ) {
return;
}
mod = newIndexSize % granularity;
if ( !mod ) {
newSize = newIndexSize;
} else {
newSize = newIndexSize + granularity - mod;
}
if ( indexChain == INVALID_INDEX ) {
indexSize = newSize;
return;
}
oldIndexChain = indexChain;
indexChain = new (TAG_IDLIB_HASH) int[newSize];
memcpy( indexChain, oldIndexChain, indexSize * sizeof(int) );
memset( indexChain + indexSize, 0xff, (newSize - indexSize) * sizeof(int) );
delete[] oldIndexChain;
indexSize = newSize;
}
/*
================
idHashIndex::GetSpread
================
*/
int idHashIndex::GetSpread() const {
int i, index, totalItems, *numHashItems, average, error, e;
if ( hash == INVALID_INDEX ) {
return 100;
}
totalItems = 0;
numHashItems = new (TAG_IDLIB_HASH) int[hashSize];
for ( i = 0; i < hashSize; i++ ) {
numHashItems[i] = 0;
for ( index = hash[i]; index >= 0; index = indexChain[index] ) {
numHashItems[i]++;
}
totalItems += numHashItems[i];
}
// if no items in hash
if ( totalItems <= 1 ) {
delete[] numHashItems;
return 100;
}
average = totalItems / hashSize;
error = 0;
for ( i = 0; i < hashSize; i++ ) {
e = abs( numHashItems[i] - average );
if ( e > 1 ) {
error += e - 1;
}
}
delete[] numHashItems;
return 100 - (error * 100 / totalItems);
}

View File

@@ -0,0 +1,422 @@
/*
===========================================================================
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 __HASHINDEX_H__
#define __HASHINDEX_H__
/*
===============================================================================
Fast hash table for indexes and arrays.
Does not allocate memory until the first key/index pair is added.
===============================================================================
*/
#define DEFAULT_HASH_SIZE 1024
#define DEFAULT_HASH_GRANULARITY 1024
class idHashIndex {
public:
static const int NULL_INDEX = -1;
idHashIndex();
idHashIndex( const int initialHashSize, const int initialIndexSize );
~idHashIndex();
// returns total size of allocated memory
size_t Allocated() const;
// returns total size of allocated memory including size of hash index type
size_t Size() const;
idHashIndex & operator=( const idHashIndex &other );
// add an index to the hash, assumes the index has not yet been added to the hash
void Add( const int key, const int index );
// remove an index from the hash
void Remove( const int key, const int index );
// get the first index from the hash, returns -1 if empty hash entry
int First( const int key ) const;
// get the next index from the hash, returns -1 if at the end of the hash chain
int Next( const int index ) const;
// For porting purposes...
int GetFirst( const int key ) const { return First( key ); }
int GetNext( const int index ) const { return Next( index ); }
// insert an entry into the index and add it to the hash, increasing all indexes >= index
void InsertIndex( const int key, const int index );
// remove an entry from the index and remove it from the hash, decreasing all indexes >= index
void RemoveIndex( const int key, const int index );
// clear the hash
void Clear();
// clear and resize
void Clear( const int newHashSize, const int newIndexSize );
// free allocated memory
void Free();
// get size of hash table
int GetHashSize() const;
// get size of the index
int GetIndexSize() const;
// set granularity
void SetGranularity( const int newGranularity );
// force resizing the index, current hash table stays intact
void ResizeIndex( const int newIndexSize );
// returns number in the range [0-100] representing the spread over the hash table
int GetSpread() const;
// returns a key for a string
int GenerateKey( const char *string, bool caseSensitive = true ) const;
// returns a key for a vector
int GenerateKey( const idVec3 &v ) const;
// returns a key for two integers
int GenerateKey( const int n1, const int n2 ) const;
// returns a key for a single integer
int GenerateKey( const int n ) const;
private:
int hashSize;
int * hash;
int indexSize;
int * indexChain;
int granularity;
int hashMask;
int lookupMask;
static int INVALID_INDEX[1];
void Init( const int initialHashSize, const int initialIndexSize );
void Allocate( const int newHashSize, const int newIndexSize );
};
/*
================
idHashIndex::idHashIndex
================
*/
ID_INLINE idHashIndex::idHashIndex() {
Init( DEFAULT_HASH_SIZE, DEFAULT_HASH_SIZE );
}
/*
================
idHashIndex::idHashIndex
================
*/
ID_INLINE idHashIndex::idHashIndex( const int initialHashSize, const int initialIndexSize ) {
Init( initialHashSize, initialIndexSize );
}
/*
================
idHashIndex::~idHashIndex
================
*/
ID_INLINE idHashIndex::~idHashIndex() {
Free();
}
/*
================
idHashIndex::Allocated
================
*/
ID_INLINE size_t idHashIndex::Allocated() const {
return hashSize * sizeof( int ) + indexSize * sizeof( int );
}
/*
================
idHashIndex::Size
================
*/
ID_INLINE size_t idHashIndex::Size() const {
return sizeof( *this ) + Allocated();
}
/*
================
idHashIndex::operator=
================
*/
ID_INLINE idHashIndex &idHashIndex::operator=( const idHashIndex &other ) {
granularity = other.granularity;
hashMask = other.hashMask;
lookupMask = other.lookupMask;
if ( other.lookupMask == 0 ) {
hashSize = other.hashSize;
indexSize = other.indexSize;
Free();
}
else {
if ( other.hashSize != hashSize || hash == INVALID_INDEX ) {
if ( hash != INVALID_INDEX ) {
delete[] hash;
}
hashSize = other.hashSize;
hash = new (TAG_IDLIB_HASH) int[hashSize];
}
if ( other.indexSize != indexSize || indexChain == INVALID_INDEX ) {
if ( indexChain != INVALID_INDEX ) {
delete[] indexChain;
}
indexSize = other.indexSize;
indexChain = new (TAG_IDLIB_HASH) int[indexSize];
}
memcpy( hash, other.hash, hashSize * sizeof( hash[0] ) );
memcpy( indexChain, other.indexChain, indexSize * sizeof( indexChain[0] ) );
}
return *this;
}
/*
================
idHashIndex::Add
================
*/
ID_INLINE void idHashIndex::Add( const int key, const int index ) {
int h;
assert( index >= 0 );
if ( hash == INVALID_INDEX ) {
Allocate( hashSize, index >= indexSize ? index + 1 : indexSize );
}
else if ( index >= indexSize ) {
ResizeIndex( index + 1 );
}
h = key & hashMask;
indexChain[index] = hash[h];
hash[h] = index;
}
/*
================
idHashIndex::Remove
================
*/
ID_INLINE void idHashIndex::Remove( const int key, const int index ) {
int k = key & hashMask;
if ( hash == INVALID_INDEX ) {
return;
}
if ( hash[k] == index ) {
hash[k] = indexChain[index];
}
else {
for ( int i = hash[k]; i != -1; i = indexChain[i] ) {
if ( indexChain[i] == index ) {
indexChain[i] = indexChain[index];
break;
}
}
}
indexChain[index] = -1;
}
/*
================
idHashIndex::First
================
*/
ID_INLINE int idHashIndex::First( const int key ) const {
return hash[key & hashMask & lookupMask];
}
/*
================
idHashIndex::Next
================
*/
ID_INLINE int idHashIndex::Next( const int index ) const {
assert( index >= 0 && index < indexSize );
return indexChain[index & lookupMask];
}
/*
================
idHashIndex::InsertIndex
================
*/
ID_INLINE void idHashIndex::InsertIndex( const int key, const int index ) {
int i, max;
if ( hash != INVALID_INDEX ) {
max = index;
for ( i = 0; i < hashSize; i++ ) {
if ( hash[i] >= index ) {
hash[i]++;
if ( hash[i] > max ) {
max = hash[i];
}
}
}
for ( i = 0; i < indexSize; i++ ) {
if ( indexChain[i] >= index ) {
indexChain[i]++;
if ( indexChain[i] > max ) {
max = indexChain[i];
}
}
}
if ( max >= indexSize ) {
ResizeIndex( max + 1 );
}
for ( i = max; i > index; i-- ) {
indexChain[i] = indexChain[i-1];
}
indexChain[index] = -1;
}
Add( key, index );
}
/*
================
idHashIndex::RemoveIndex
================
*/
ID_INLINE void idHashIndex::RemoveIndex( const int key, const int index ) {
int i, max;
Remove( key, index );
if ( hash != INVALID_INDEX ) {
max = index;
for ( i = 0; i < hashSize; i++ ) {
if ( hash[i] >= index ) {
if ( hash[i] > max ) {
max = hash[i];
}
hash[i]--;
}
}
for ( i = 0; i < indexSize; i++ ) {
if ( indexChain[i] >= index ) {
if ( indexChain[i] > max ) {
max = indexChain[i];
}
indexChain[i]--;
}
}
for ( i = index; i < max; i++ ) {
indexChain[i] = indexChain[i+1];
}
indexChain[max] = -1;
}
}
/*
================
idHashIndex::Clear
================
*/
ID_INLINE void idHashIndex::Clear() {
// only clear the hash table because clearing the indexChain is not really needed
if ( hash != INVALID_INDEX ) {
memset( hash, 0xff, hashSize * sizeof( hash[0] ) );
}
}
/*
================
idHashIndex::Clear
================
*/
ID_INLINE void idHashIndex::Clear( const int newHashSize, const int newIndexSize ) {
Free();
hashSize = newHashSize;
indexSize = newIndexSize;
}
/*
================
idHashIndex::GetHashSize
================
*/
ID_INLINE int idHashIndex::GetHashSize() const {
return hashSize;
}
/*
================
idHashIndex::GetIndexSize
================
*/
ID_INLINE int idHashIndex::GetIndexSize() const {
return indexSize;
}
/*
================
idHashIndex::SetGranularity
================
*/
ID_INLINE void idHashIndex::SetGranularity( const int newGranularity ) {
assert( newGranularity > 0 );
granularity = newGranularity;
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const char *string, bool caseSensitive ) const {
if ( caseSensitive ) {
return ( idStr::Hash( string ) & hashMask );
} else {
return ( idStr::IHash( string ) & hashMask );
}
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const idVec3 &v ) const {
return ( (((int) v[0]) + ((int) v[1]) + ((int) v[2])) & hashMask );
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const int n1, const int n2 ) const {
return ( ( n1 + n2 ) & hashMask );
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const int n ) const {
return n & hashMask;
}
#endif /* !__HASHINDEX_H__ */

View File

@@ -0,0 +1,897 @@
/*
===========================================================================
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 __HASHTABLE_H__
#define __HASHTABLE_H__
/*
================================================================================================
idHashNodeT is a generic node for a HashTable. It is specialized by the
StringHashNode and CStringHashNode template classes.
================================================================================================
*/
template< typename _key_, class _value_ >
class idHashNodeT {
public:
idHashNodeT()
: next( NULL ) {
}
idHashNodeT( const _key_ & key, const _value_ & value, idHashNodeT * next )
: key( key ),
value( value ),
next( next ) {
}
static int GetHash( const _key_ & key, const int tableMask ) {
return key & tableMask;
}
static int Compare( const _key_ & key1, const _key_ & key2 ) {
if ( key1 < key2 ) {
return -1;
} else if ( key1 > key2 ) {
return 1;
}
return 0;
}
public:
_key_ key;
_value_ value;
idHashNodeT< _key_, _value_ > * next;
};
/*
================================================
idHashNodeT is a HashNode that provides for partial
specialization for the HashTable, allowing the String class's Cmp function to be used
for inserting values in sorted order.
================================================
*/
template< class _value_ >
class idHashNodeT< idStr, _value_ > {
public:
idHashNodeT( const idStr & key, const _value_ & value, idHashNodeT * next )
: key( key ),
value( value ),
next( next ) {
}
static int GetHash( const idStr & key, const int tableMask ) {
return ( idStr::Hash( key ) & tableMask );
}
static int Compare( const idStr & key1, const idStr & key2 ) {
return idStr::Icmp( key1, key2 );
}
public:
idStr key;
_value_ value;
idHashNodeT< idStr, _value_ > * next;
};
/*
================================================
idHashNodeT is a HashNode that provides for a partial specialization
for the HashTable, allowing the String class's Cmp function to
be used for inserting values in sorted order. It also ensures that a copy of the the key is
stored in a String (to more closely model the original implementation of the HashTable).
================================================
*/
template< class _value_ >
class idHashNodeT< const char*, _value_ > {
public:
idHashNodeT( const char* const & key, const _value_ & value, idHashNodeT * next )
: key( key ),
value( value ),
next( next ) {
}
static int GetHash( const char* const & key, const int tableMask ) {
return ( idStr::Hash( key ) & tableMask );
}
static int Compare( const char* const & key1, const char* const & key2 ) {
return idStr::Icmp( key1, key2 );
}
public:
idStr key; // char * keys must still get stored in an idStr
_value_ value;
idHashNodeT< const char *, _value_ > * next;
};
/*
================================================
idHashTableT is a general implementation of a hash table data type. It is
slower than the HashIndex, but it can also be used for LinkedLists and other data structures,
rather than just indexes and arrays.
It uses an arbitrary key type. For String keys, use the StringHashTable template
specialization.
================================================
*/
template< typename _key_, class _value_ >
class idHashTableT {
public:
idHashTableT( const int tableSize = 256 );
idHashTableT( const idHashTableT & other );
~idHashTableT();
size_t Allocated() const;
size_t Size() const;
_value_ & Set( const _key_ & key, const _value_ & value );
bool Get( const _key_ & key, _value_ ** value = NULL );
bool Get( const _key_ & key, const _value_ ** value = NULL ) const;
bool Remove( const _key_ & key );
void Clear();
void DeleteContents();
int Num() const;
_value_ * GetIndex( const int index ) const;
bool GetIndexKey( const int index, _key_ & key ) const;
int GetSpread() const;
idHashTableT & operator=( const idHashTableT & other );
protected:
void Copy( const idHashTableT & other );
private:
typedef idHashNodeT< _key_, _value_ > hashnode_t;
hashnode_t ** heads;
int tableSize;
int numEntries;
int tableSizeMask;
};
/*
========================
idHashTableT<_key_,_value_>::idHashTableT
========================
*/
template< typename _key_, class _value_ >
ID_INLINE idHashTableT<_key_,_value_>::idHashTableT( const int tableSize ) {
assert( idMath::IsPowerOfTwo( tableSize ) );
this->tableSize = tableSize;
heads = new (TAG_IDLIB_HASH) hashnode_t *[ tableSize ];
memset( heads, 0, sizeof( hashnode_t * ) * tableSize );
numEntries = 0;
tableSizeMask = tableSize - 1;
}
/*
========================
idHashTableT<_key_,_value_>::idHashTableT
========================
*/
template< typename _key_, class _value_ >
ID_INLINE idHashTableT<_key_,_value_>::idHashTableT( const idHashTableT & other ) {
Copy( other );
}
/*
========================
idHashTableT<_key_,_value_>::~idHashTableT
========================
*/
template< typename _key_, class _value_ >
ID_INLINE idHashTableT<_key_,_value_>::~idHashTableT() {
Clear();
delete [] heads;
heads = NULL;
tableSize = 0;
tableSizeMask = 0;
numEntries = 0;
}
/*
========================
idHashTableT<_key_,_value_>::Allocated
========================
*/
template< typename _key_, class _value_ >
ID_INLINE size_t idHashTableT<_key_,_value_>::Allocated() const {
return sizeof( heads ) * tableSize + sizeof( hashnode_t* ) * numEntries;
}
/*
========================
idHashTableT<_key_,_value_>::Size
========================
*/
template< typename _key_, class _value_ >
ID_INLINE size_t idHashTableT<_key_,_value_>::Size() const {
return sizeof( idHashTableT ) + sizeof( heads )* tableSize + sizeof( hashnode_t* ) * numEntries;
}
/*
========================
idHashTableT<_key_,_value_>::Set
========================
*/
template< typename _key_, class _value_ >
ID_INLINE _value_ & idHashTableT<_key_,_value_>::Set( const _key_ & key, const _value_ & value ) {
// insert sorted
int hash = hashnode_t::GetHash( key, tableSizeMask );
hashnode_t ** nextPtr = &(heads[ hash ] );
hashnode_t * node = * nextPtr;
for ( ;
node != NULL;
nextPtr = &(node->next), node = *nextPtr ) {
int s = node->Compare( node->key, key );
if ( s == 0 ) {
// return existing hashed item
node->value = value;
return node->value;
}
if ( s > 0 ) {
break;
}
}
numEntries++;
*nextPtr = new (TAG_IDLIB_HASH) hashnode_t( key, value, heads[ hash ] );
(*nextPtr)->next = node;
return (*nextPtr)->value;
}
/*
========================
idHashTableT<_key_,_value_>::Get
========================
*/
template< typename _key_, class _value_ >
ID_INLINE bool idHashTableT<_key_,_value_>::Get( const _key_ & key, _value_ ** value ) {
int hash = hashnode_t::GetHash( key, tableSizeMask );
hashnode_t * node = heads[ hash ];
for ( ; node != NULL; node = node->next ) {
int s = node->Compare( node->key, key );
if ( s == 0 ) {
if ( value ) {
*value = &node->value;
}
return true;
}
if ( s > 0 ) {
break;
}
}
if ( value ) {
*value = NULL;
}
return false;
}
/*
========================
idHashTableT<_key_,_value_>::Get
========================
*/
template< typename _key_, class _value_ >
ID_INLINE bool idHashTableT<_key_,_value_>::Get( const _key_ & key, const _value_ ** value ) const {
int hash = hashnode_t::GetHash( key, tableSizeMask );
hashnode_t * node = heads[ hash ];
for ( ; node != NULL; node = node->next ) {
int s = node->Compare( node->key, key );
if ( s == 0 ) {
if ( value ) {
*value = &node->value;
}
return true;
}
if ( s > 0 ) {
break;
}
}
if ( value ) {
*value = NULL;
}
return false;
}
/*
========================
idHashTableT<_key_,_value_>::GetIndex
========================
*/
template< typename _key_, class _value_ >
ID_INLINE _value_ * idHashTableT<_key_,_value_>::GetIndex( const int index ) const {
if ( index < 0 || index > numEntries ) {
assert( 0 );
return NULL;
}
int count = 0;
for ( int i = 0; i < tableSize; i++ ) {
for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) {
if ( count == index ) {
return &node->value;
}
count++;
}
}
return NULL;
}
/*
========================
idHashTableT<_key_,_value_>::GetIndexKey
========================
*/
template< typename _key_, class _value_ >
ID_INLINE bool idHashTableT<_key_,_value_>::GetIndexKey( const int index, _key_ & key ) const {
if ( index < 0 || index > numEntries ) {
assert( 0 );
return false;
}
int count = 0;
for ( int i = 0; i < tableSize; i++ ) {
for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) {
if ( count == index ) {
key = node->key;
return true;
}
count++;
}
}
return false;
}
/*
========================
idHashTableT<_key_,_value_>::Remove
========================
*/
template< typename _key_, class _value_ >
ID_INLINE bool idHashTableT<_key_,_value_>::Remove( const _key_ & key ) {
int hash = hashnode_t::GetHash( key, tableSizeMask );
hashnode_t ** head = &heads[ hash ];
if ( *head ) {
hashnode_t * prev = NULL;
hashnode_t * node = *head;
for ( ; node != NULL; prev = node, node = node->next ) {
if ( node->key == key ) {
if ( prev ) {
prev->next = node->next;
} else {
*head = node->next;
}
delete node;
numEntries--;
return true;
}
}
}
return false;
}
/*
========================
idHashTableT<_key_,_value_>::Clear
========================
*/
template< typename _key_, class _value_ >
ID_INLINE void idHashTableT<_key_,_value_>::Clear() {
for ( int i = 0; i < tableSize; i++ ) {
hashnode_t * next = heads[ i ];
while ( next != NULL ) {
hashnode_t * node = next;
next = next->next;
delete node;
}
heads[ i ] = NULL;
}
numEntries = 0;
}
/*
========================
idHashTableT<_key_,_value_>::DeleteContents
========================
*/
template< typename _key_, class _value_ >
ID_INLINE void idHashTableT<_key_,_value_>::DeleteContents() {
for ( int i = 0; i < tableSize; i++ ) {
hashnode_t * next = heads[ i ];
while ( next != NULL ) {
hashnode_t * node = next;
next = next->next;
delete node->value;
delete node;
}
heads[ i ] = NULL;
}
numEntries = 0;
}
/*
========================
idHashTableT<_key_,_value_>::Num
========================
*/
template< typename _key_, class _value_ >
ID_INLINE int idHashTableT<_key_,_value_>::Num() const {
return numEntries;
}
/*
========================
idHashTableT<_key_,_value_>::GetSpread
========================
*/
template< typename _key_, class _value_ >
ID_INLINE int idHashTableT<_key_,_value_>::GetSpread() const {
if ( !numEntries ) {
return 100;
}
int average = numEntries / tableSize;
int error = 0;
for ( int i = 0; i < tableSize; i++ ) {
int numItems = 0;
for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) {
numItems++;
}
int e = abs( numItems - average );
if ( e > 1 ) {
error += e - 1;
}
}
return 100 - ( error * 100 / numEntries );
}
/*
========================
idHashTableT<_key_,_value_>::operator=
========================
*/
template< typename _key_, class _value_ >
ID_INLINE idHashTableT< _key_, _value_ > & idHashTableT<_key_,_value_>::operator=( const idHashTableT & other ) {
Copy( other );
return *this;
}
/*
========================
idHashTableT<_key_,_value_>::Copy
========================
*/
template< typename _key_, class _value_ >
ID_INLINE void idHashTableT<_key_,_value_>::Copy( const idHashTableT & other ) {
if ( &other == this ) {
return;
}
assert( other.tableSize > 0 );
tableSize = other.tableSize;
heads = new (TAG_IDLIB_HASH) hashnode_t *[ tableSize ];
numEntries = other.numEntries;
tableSizeMask = other.tableSizeMask;
for ( int i = 0; i < tableSize; i++ ) {
if ( !other.heads[ i ] ) {
heads[ i ] = NULL;
continue;
}
hashnode_t ** prev = & heads[ i ];
for ( hashnode_t * node = other.heads[ i ]; node != NULL; node = node->next ) {
*prev = new (TAG_IDLIB_HASH) hashnode_t( node->key, node->value, NULL );
prev = &( *prev )->next;
}
}
}
/*
===============================================================================
General hash table. Slower than idHashIndex but it can also be used for
linked lists and other data structures than just indexes or arrays.
===============================================================================
*/
template< class Type >
class idHashTable {
public:
idHashTable( int newtablesize = 256 );
idHashTable( const idHashTable<Type> &map );
~idHashTable();
// returns total size of allocated memory
size_t Allocated() const;
// returns total size of allocated memory including size of hash table type
size_t Size() const;
void Set( const char *key, Type &value );
bool Get( const char *key, Type **value = NULL ) const;
bool Remove( const char *key );
void Clear();
void DeleteContents();
// the entire contents can be itterated over, but note that the
// exact index for a given element may change when new elements are added
int Num() const;
Type * GetIndex( int index ) const;
int GetSpread() const;
private:
struct hashnode_s {
idStr key;
Type value;
hashnode_s *next;
hashnode_s( const idStr &k, Type v, hashnode_s *n ) : key( k ), value( v ), next( n ) {};
hashnode_s( const char *k, Type v, hashnode_s *n ) : key( k ), value( v ), next( n ) {};
};
hashnode_s ** heads;
int tablesize;
int numentries;
int tablesizemask;
int GetHash( const char *key ) const;
};
/*
================
idHashTable<Type>::idHashTable
================
*/
template< class Type >
ID_INLINE idHashTable<Type>::idHashTable( int newtablesize ) {
assert( idMath::IsPowerOfTwo( newtablesize ) );
tablesize = newtablesize;
assert( tablesize > 0 );
heads = new (TAG_IDLIB_HASH) hashnode_s *[ tablesize ];
memset( heads, 0, sizeof( *heads ) * tablesize );
numentries = 0;
tablesizemask = tablesize - 1;
}
/*
================
idHashTable<Type>::idHashTable
================
*/
template< class Type >
ID_INLINE idHashTable<Type>::idHashTable( const idHashTable<Type> &map ) {
int i;
hashnode_s *node;
hashnode_s **prev;
assert( map.tablesize > 0 );
tablesize = map.tablesize;
heads = new (TAG_IDLIB_HASH) hashnode_s *[ tablesize ];
numentries = map.numentries;
tablesizemask = map.tablesizemask;
for( i = 0; i < tablesize; i++ ) {
if ( !map.heads[ i ] ) {
heads[ i ] = NULL;
continue;
}
prev = &heads[ i ];
for( node = map.heads[ i ]; node != NULL; node = node->next ) {
*prev = new (TAG_IDLIB_HASH) hashnode_s( node->key, node->value, NULL );
prev = &( *prev )->next;
}
}
}
/*
================
idHashTable<Type>::~idHashTable<Type>
================
*/
template< class Type >
ID_INLINE idHashTable<Type>::~idHashTable() {
Clear();
delete[] heads;
}
/*
================
idHashTable<Type>::Allocated
================
*/
template< class Type >
ID_INLINE size_t idHashTable<Type>::Allocated() const {
return sizeof( heads ) * tablesize + sizeof( *heads ) * numentries;
}
/*
================
idHashTable<Type>::Size
================
*/
template< class Type >
ID_INLINE size_t idHashTable<Type>::Size() const {
return sizeof( idHashTable<Type> ) + sizeof( heads ) * tablesize + sizeof( *heads ) * numentries;
}
/*
================
idHashTable<Type>::GetHash
================
*/
template< class Type >
ID_INLINE int idHashTable<Type>::GetHash( const char *key ) const {
return ( idStr::Hash( key ) & tablesizemask );
}
/*
================
idHashTable<Type>::Set
================
*/
template< class Type >
ID_INLINE void idHashTable<Type>::Set( const char *key, Type &value ) {
hashnode_s *node, **nextPtr;
int hash, s;
hash = GetHash( key );
for( nextPtr = &(heads[hash]), node = *nextPtr; node != NULL; nextPtr = &(node->next), node = *nextPtr ) {
s = node->key.Cmp( key );
if ( s == 0 ) {
node->value = value;
return;
}
if ( s > 0 ) {
break;
}
}
numentries++;
*nextPtr = new (TAG_IDLIB_HASH) hashnode_s( key, value, heads[ hash ] );
(*nextPtr)->next = node;
}
/*
================
idHashTable<Type>::Get
================
*/
template< class Type >
ID_INLINE bool idHashTable<Type>::Get( const char *key, Type **value ) const {
hashnode_s *node;
int hash, s;
hash = GetHash( key );
for( node = heads[ hash ]; node != NULL; node = node->next ) {
s = node->key.Cmp( key );
if ( s == 0 ) {
if ( value ) {
*value = &node->value;
}
return true;
}
if ( s > 0 ) {
break;
}
}
if ( value ) {
*value = NULL;
}
return false;
}
/*
================
idHashTable<Type>::GetIndex
the entire contents can be itterated over, but note that the
exact index for a given element may change when new elements are added
================
*/
template< class Type >
ID_INLINE Type *idHashTable<Type>::GetIndex( int index ) const {
hashnode_s *node;
int count;
int i;
if ( ( index < 0 ) || ( index > numentries ) ) {
assert( 0 );
return NULL;
}
count = 0;
for( i = 0; i < tablesize; i++ ) {
for( node = heads[ i ]; node != NULL; node = node->next ) {
if ( count == index ) {
return &node->value;
}
count++;
}
}
return NULL;
}
/*
================
idHashTable<Type>::Remove
================
*/
template< class Type >
ID_INLINE bool idHashTable<Type>::Remove( const char *key ) {
hashnode_s **head;
hashnode_s *node;
hashnode_s *prev;
int hash;
hash = GetHash( key );
head = &heads[ hash ];
if ( *head ) {
for( prev = NULL, node = *head; node != NULL; prev = node, node = node->next ) {
if ( node->key == key ) {
if ( prev ) {
prev->next = node->next;
} else {
*head = node->next;
}
delete node;
numentries--;
return true;
}
}
}
return false;
}
/*
================
idHashTable<Type>::Clear
================
*/
template< class Type >
ID_INLINE void idHashTable<Type>::Clear() {
int i;
hashnode_s *node;
hashnode_s *next;
for( i = 0; i < tablesize; i++ ) {
next = heads[ i ];
while( next != NULL ) {
node = next;
next = next->next;
delete node;
}
heads[ i ] = NULL;
}
numentries = 0;
}
/*
================
idHashTable<Type>::DeleteContents
================
*/
template< class Type >
ID_INLINE void idHashTable<Type>::DeleteContents() {
int i;
hashnode_s *node;
hashnode_s *next;
for( i = 0; i < tablesize; i++ ) {
next = heads[ i ];
while( next != NULL ) {
node = next;
next = next->next;
delete node->value;
delete node;
}
heads[ i ] = NULL;
}
numentries = 0;
}
/*
================
idHashTable<Type>::Num
================
*/
template< class Type >
ID_INLINE int idHashTable<Type>::Num() const {
return numentries;
}
#if defined(ID_TYPEINFO)
#define __GNUC__ 99
#endif
#if !defined(__GNUC__) || __GNUC__ < 4
/*
================
idHashTable<Type>::GetSpread
================
*/
template< class Type >
int idHashTable<Type>::GetSpread() const {
int i, average, error, e;
hashnode_s *node;
// if no items in hash
if ( !numentries ) {
return 100;
}
average = numentries / tablesize;
error = 0;
for ( i = 0; i < tablesize; i++ ) {
numItems = 0;
for( node = heads[ i ]; node != NULL; node = node->next ) {
numItems++;
}
e = abs( numItems - average );
if ( e > 1 ) {
error += e - 1;
}
}
return 100 - (error * 100 / numentries);
}
#endif
#if defined(ID_TYPEINFO)
#undef __GNUC__
#endif
#endif /* !__HASHTABLE_H__ */

View File

@@ -0,0 +1,362 @@
/*
===========================================================================
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 __HIERARCHY_H__
#define __HIERARCHY_H__
/*
==============================================================================
idHierarchy
==============================================================================
*/
template< class type >
class idHierarchy {
public:
idHierarchy();
~idHierarchy();
void SetOwner( type *object );
type * Owner() const;
void ParentTo( idHierarchy &node );
void MakeSiblingAfter( idHierarchy &node );
bool ParentedBy( const idHierarchy &node ) const;
void RemoveFromParent();
void RemoveFromHierarchy();
type * GetParent() const; // parent of this node
type * GetChild() const; // first child of this node
type * GetSibling() const; // next node with the same parent
type * GetPriorSibling() const; // previous node with the same parent
type * GetNext() const; // goes through all nodes of the hierarchy
type * GetNextLeaf() const; // goes through all leaf nodes of the hierarchy
private:
idHierarchy * parent;
idHierarchy * sibling;
idHierarchy * child;
type * owner;
idHierarchy<type> *GetPriorSiblingNode() const; // previous node with the same parent
};
/*
================
idHierarchy<type>::idHierarchy
================
*/
template< class type >
idHierarchy<type>::idHierarchy() {
owner = NULL;
parent = NULL;
sibling = NULL;
child = NULL;
}
/*
================
idHierarchy<type>::~idHierarchy
================
*/
template< class type >
idHierarchy<type>::~idHierarchy() {
RemoveFromHierarchy();
}
/*
================
idHierarchy<type>::Owner
Gets the object that is associated with this node.
================
*/
template< class type >
type *idHierarchy<type>::Owner() const {
return owner;
}
/*
================
idHierarchy<type>::SetOwner
Sets the object that this node is associated with.
================
*/
template< class type >
void idHierarchy<type>::SetOwner( type *object ) {
owner = object;
}
/*
================
idHierarchy<type>::ParentedBy
================
*/
template< class type >
bool idHierarchy<type>::ParentedBy( const idHierarchy &node ) const {
if ( parent == &node ) {
return true;
} else if ( parent ) {
return parent->ParentedBy( node );
}
return false;
}
/*
================
idHierarchy<type>::ParentTo
Makes the given node the parent.
================
*/
template< class type >
void idHierarchy<type>::ParentTo( idHierarchy &node ) {
RemoveFromParent();
parent = &node;
sibling = node.child;
node.child = this;
}
/*
================
idHierarchy<type>::MakeSiblingAfter
Makes the given node a sibling after the passed in node.
================
*/
template< class type >
void idHierarchy<type>::MakeSiblingAfter( idHierarchy &node ) {
RemoveFromParent();
parent = node.parent;
sibling = node.sibling;
node.sibling = this;
}
/*
================
idHierarchy<type>::RemoveFromParent
================
*/
template< class type >
void idHierarchy<type>::RemoveFromParent() {
idHierarchy<type> *prev;
if ( parent ) {
prev = GetPriorSiblingNode();
if ( prev ) {
prev->sibling = sibling;
} else {
parent->child = sibling;
}
}
parent = NULL;
sibling = NULL;
}
/*
================
idHierarchy<type>::RemoveFromHierarchy
Removes the node from the hierarchy and adds it's children to the parent.
================
*/
template< class type >
void idHierarchy<type>::RemoveFromHierarchy() {
idHierarchy<type> *parentNode;
idHierarchy<type> *node;
parentNode = parent;
RemoveFromParent();
if ( parentNode ) {
while( child ) {
node = child;
node->RemoveFromParent();
node->ParentTo( *parentNode );
}
} else {
while( child ) {
child->RemoveFromParent();
}
}
}
/*
================
idHierarchy<type>::GetParent
================
*/
template< class type >
type *idHierarchy<type>::GetParent() const {
if ( parent ) {
return parent->owner;
}
return NULL;
}
/*
================
idHierarchy<type>::GetChild
================
*/
template< class type >
type *idHierarchy<type>::GetChild() const {
if ( child ) {
return child->owner;
}
return NULL;
}
/*
================
idHierarchy<type>::GetSibling
================
*/
template< class type >
type *idHierarchy<type>::GetSibling() const {
if ( sibling ) {
return sibling->owner;
}
return NULL;
}
/*
================
idHierarchy<type>::GetPriorSiblingNode
Returns NULL if no parent, or if it is the first child.
================
*/
template< class type >
idHierarchy<type> *idHierarchy<type>::GetPriorSiblingNode() const {
if ( !parent || ( parent->child == this ) ) {
return NULL;
}
idHierarchy<type> *prev;
idHierarchy<type> *node;
node = parent->child;
prev = NULL;
while( ( node != this ) && ( node != NULL ) ) {
prev = node;
node = node->sibling;
}
if ( node != this ) {
idLib::Error( "idHierarchy::GetPriorSibling: could not find node in parent's list of children" );
}
return prev;
}
/*
================
idHierarchy<type>::GetPriorSibling
Returns NULL if no parent, or if it is the first child.
================
*/
template< class type >
type *idHierarchy<type>::GetPriorSibling() const {
idHierarchy<type> *prior;
prior = GetPriorSiblingNode();
if ( prior ) {
return prior->owner;
}
return NULL;
}
/*
================
idHierarchy<type>::GetNext
Goes through all nodes of the hierarchy.
================
*/
template< class type >
type *idHierarchy<type>::GetNext() const {
const idHierarchy<type> *node;
if ( child ) {
return child->owner;
} else {
node = this;
while( node && node->sibling == NULL ) {
node = node->parent;
}
if ( node ) {
return node->sibling->owner;
} else {
return NULL;
}
}
}
/*
================
idHierarchy<type>::GetNextLeaf
Goes through all leaf nodes of the hierarchy.
================
*/
template< class type >
type *idHierarchy<type>::GetNextLeaf() const {
const idHierarchy<type> *node;
if ( child ) {
node = child;
while ( node->child ) {
node = node->child;
}
return node->owner;
} else {
node = this;
while( node && node->sibling == NULL ) {
node = node->parent;
}
if ( node ) {
node = node->sibling;
while ( node->child ) {
node = node->child;
}
return node->owner;
} else {
return NULL;
}
}
}
#endif /* !__HIERARCHY_H__ */

View File

@@ -0,0 +1,343 @@
/*
===========================================================================
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 __LINKLIST_H__
#define __LINKLIST_H__
/*
==============================================================================
idLinkList
Circular linked list template
==============================================================================
*/
template< class type >
class idLinkList {
public:
idLinkList();
~idLinkList();
bool IsListEmpty() const;
bool InList() const;
int Num() const;
void Clear();
void InsertBefore( idLinkList &node );
void InsertAfter( idLinkList &node );
void AddToEnd( idLinkList &node );
void AddToFront( idLinkList &node );
void Remove();
type * Next() const;
type * Prev() const;
type * Owner() const;
void SetOwner( type *object );
idLinkList * ListHead() const;
idLinkList * NextNode() const;
idLinkList * PrevNode() const;
private:
idLinkList * head;
idLinkList * next;
idLinkList * prev;
type * owner;
};
/*
================
idLinkList<type>::idLinkList
Node is initialized to be the head of an empty list
================
*/
template< class type >
idLinkList<type>::idLinkList() {
owner = NULL;
head = this;
next = this;
prev = this;
}
/*
================
idLinkList<type>::~idLinkList
Removes the node from the list, or if it's the head of a list, removes
all the nodes from the list.
================
*/
template< class type >
idLinkList<type>::~idLinkList() {
Clear();
}
/*
================
idLinkList<type>::IsListEmpty
Returns true if the list is empty.
================
*/
template< class type >
bool idLinkList<type>::IsListEmpty() const {
return head->next == head;
}
/*
================
idLinkList<type>::InList
Returns true if the node is in a list. If called on the head of a list, will always return false.
================
*/
template< class type >
bool idLinkList<type>::InList() const {
return head != this;
}
/*
================
idLinkList<type>::Num
Returns the number of nodes in the list.
================
*/
template< class type >
int idLinkList<type>::Num() const {
idLinkList<type> *node;
int num;
num = 0;
for( node = head->next; node != head; node = node->next ) {
num++;
}
return num;
}
/*
================
idLinkList<type>::Clear
If node is the head of the list, clears the list. Otherwise it just removes the node from the list.
================
*/
template< class type >
void idLinkList<type>::Clear() {
if ( head == this ) {
while( next != this ) {
next->Remove();
}
} else {
Remove();
}
}
/*
================
idLinkList<type>::Remove
Removes node from list
================
*/
template< class type >
void idLinkList<type>::Remove() {
prev->next = next;
next->prev = prev;
next = this;
prev = this;
head = this;
}
/*
================
idLinkList<type>::InsertBefore
Places the node before the existing node in the list. If the existing node is the head,
then the new node is placed at the end of the list.
================
*/
template< class type >
void idLinkList<type>::InsertBefore( idLinkList &node ) {
Remove();
next = &node;
prev = node.prev;
node.prev = this;
prev->next = this;
head = node.head;
}
/*
================
idLinkList<type>::InsertAfter
Places the node after the existing node in the list. If the existing node is the head,
then the new node is placed at the beginning of the list.
================
*/
template< class type >
void idLinkList<type>::InsertAfter( idLinkList &node ) {
Remove();
prev = &node;
next = node.next;
node.next = this;
next->prev = this;
head = node.head;
}
/*
================
idLinkList<type>::AddToEnd
Adds node at the end of the list
================
*/
template< class type >
void idLinkList<type>::AddToEnd( idLinkList &node ) {
InsertBefore( *node.head );
}
/*
================
idLinkList<type>::AddToFront
Adds node at the beginning of the list
================
*/
template< class type >
void idLinkList<type>::AddToFront( idLinkList &node ) {
InsertAfter( *node.head );
}
/*
================
idLinkList<type>::ListHead
Returns the head of the list. If the node isn't in a list, it returns
a pointer to itself.
================
*/
template< class type >
idLinkList<type> *idLinkList<type>::ListHead() const {
return head;
}
/*
================
idLinkList<type>::Next
Returns the next object in the list, or NULL if at the end.
================
*/
template< class type >
type *idLinkList<type>::Next() const {
if ( !next || ( next == head ) ) {
return NULL;
}
return next->owner;
}
/*
================
idLinkList<type>::Prev
Returns the previous object in the list, or NULL if at the beginning.
================
*/
template< class type >
type *idLinkList<type>::Prev() const {
if ( !prev || ( prev == head ) ) {
return NULL;
}
return prev->owner;
}
/*
================
idLinkList<type>::NextNode
Returns the next node in the list, or NULL if at the end.
================
*/
template< class type >
idLinkList<type> *idLinkList<type>::NextNode() const {
if ( next == head ) {
return NULL;
}
return next;
}
/*
================
idLinkList<type>::PrevNode
Returns the previous node in the list, or NULL if at the beginning.
================
*/
template< class type >
idLinkList<type> *idLinkList<type>::PrevNode() const {
if ( prev == head ) {
return NULL;
}
return prev;
}
/*
================
idLinkList<type>::Owner
Gets the object that is associated with this node.
================
*/
template< class type >
type *idLinkList<type>::Owner() const {
return owner;
}
/*
================
idLinkList<type>::SetOwner
Sets the object that this node is associated with.
================
*/
template< class type >
void idLinkList<type>::SetOwner( type *object ) {
owner = object;
}
#endif /* !__LINKLIST_H__ */

1037
neo/idlib/containers/List.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/*
===========================================================================
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 __PLANESET_H__
#define __PLANESET_H__
/*
===============================================================================
Plane Set
===============================================================================
*/
class idPlaneSet : public idList<idPlane> {
public:
void Clear() { idList<idPlane>::Clear(); hash.Free(); }
int FindPlane( const idPlane &plane, const float normalEps, const float distEps );
private:
idHashIndex hash;
};
ID_INLINE int idPlaneSet::FindPlane( const idPlane &plane, const float normalEps, const float distEps ) {
int i, border, hashKey;
assert( distEps <= 0.125f );
hashKey = (int)( idMath::Fabs( plane.Dist() ) * 0.125f );
for ( border = -1; border <= 1; border++ ) {
for ( i = hash.First( hashKey + border ); i >= 0; i = hash.Next( i ) ) {
if ( (*this)[i].Compare( plane, normalEps, distEps ) ) {
return i;
}
}
}
if ( plane.Type() >= PLANETYPE_NEGX && plane.Type() < PLANETYPE_TRUEAXIAL ) {
Append( -plane );
hash.Add( hashKey, Num()-1 );
Append( plane );
hash.Add( hashKey, Num()-1 );
return ( Num() - 1 );
}
else {
Append( plane );
hash.Add( hashKey, Num()-1 );
Append( -plane );
hash.Add( hashKey, Num()-1 );
return ( Num() - 2 );
}
}
#endif /* !__PLANESET_H__ */

View File

@@ -0,0 +1,211 @@
/*
===========================================================================
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 __QUEUE_H__
#define __QUEUE_H__
/*
===============================================================================
Queue template
===============================================================================
*/
template< class type, int nextOffset >
class idQueueTemplate {
public:
idQueueTemplate();
void Add( type *element );
type * Get();
private:
type * first;
type * last;
};
#define QUEUE_NEXT_PTR( element ) (*((type**)(((byte*)element)+nextOffset)))
template< class type, int nextOffset >
idQueueTemplate<type,nextOffset>::idQueueTemplate() {
first = last = NULL;
}
template< class type, int nextOffset >
void idQueueTemplate<type,nextOffset>::Add( type *element ) {
QUEUE_NEXT_PTR(element) = NULL;
if ( last ) {
QUEUE_NEXT_PTR(last) = element;
} else {
first = element;
}
last = element;
}
template< class type, int nextOffset >
type *idQueueTemplate<type,nextOffset>::Get() {
type *element;
element = first;
if ( element ) {
first = QUEUE_NEXT_PTR(first);
if ( last == element ) {
last = NULL;
}
QUEUE_NEXT_PTR(element) = NULL;
}
return element;
}
/*
================================================
A node of a Queue
================================================
*/
template< typename type >
class idQueueNode {
public:
idQueueNode() { next = NULL; }
type * GetNext() const { return next; }
void SetNext( type *next ) { this->next = next; }
private:
type * next;
};
/*
================================================
A Queue, idQueue, is a template Container class implementing the Queue abstract data
type.
================================================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
class idQueue {
public:
idQueue();
void Add( type *element );
type * RemoveFirst();
type * Peek() const;
bool IsEmpty();
static void Test();
private:
type * first;
type * last;
};
/*
========================
idQueue<type,nodePtr>::idQueue
========================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
idQueue<type,nodePtr>::idQueue() {
first = last = NULL;
}
/*
========================
idQueue<type,nodePtr>::Add
========================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
void idQueue<type,nodePtr>::Add( type *element ) {
(element->*nodePtr).SetNext( NULL );
if ( last ) {
(last->*nodePtr).SetNext( element );
} else {
first = element;
}
last = element;
}
/*
========================
idQueue<type,nodePtr>::RemoveFirst
========================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
type *idQueue<type,nodePtr>::RemoveFirst() {
type *element;
element = first;
if ( element ) {
first = (first->*nodePtr).GetNext();
if ( last == element ) {
last = NULL;
}
(element->*nodePtr).SetNext( NULL );
}
return element;
}
/*
========================
idQueue<type,nodePtr>::Peek
========================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
type *idQueue<type,nodePtr>::Peek() const {
return first;
}
/*
========================
idQueue<type,nodePtr>::IsEmpty
========================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
bool idQueue<type,nodePtr>::IsEmpty() {
return ( first == NULL );
}
/*
========================
idQueue<type,nodePtr>::Test
========================
*/
template< typename type, idQueueNode<type> type::*nodePtr >
void idQueue<type,nodePtr>::Test() {
class idMyType {
public:
idQueueNode<idMyType> queueNode;
};
idQueue<idMyType,&idMyType::queueNode> myQueue;
idMyType *element = new (TAG_IDLIB) idMyType;
myQueue.Add( element );
element = myQueue.RemoveFirst();
delete element;
}
#endif // !__QUEUE_H__

338
neo/idlib/containers/Sort.h Normal file
View File

@@ -0,0 +1,338 @@
/*
===========================================================================
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 __SORT_H__
#define __SORT_H__
/*
================================================================================================
Contains the generic templated sort algorithms for quick-sort, heap-sort and insertion-sort.
The sort algorithms do not use class operators or overloaded functions to compare
objects because it is often desireable to sort the same objects in different ways
based on different keys (not just ascending and descending but sometimes based on
name and other times based on say priority). So instead, for each different sort a
separate class is implemented with a Compare() function.
This class is derived from one of the classes that implements a sort algorithm.
The Compare() member function does not only define how objects are sorted, the class
can also store additional data that can be used by the Compare() function. This, for
instance, allows a list of indices to be sorted where the indices point to objects
in an array. The base pointer of the array with objects can be stored on the class
that implements the Compare() function such that the Compare() function can use keys
that are stored on the objects.
The Compare() function is not virtual because this would incur significant overhead.
Do NOT make the Compare() function virtual on the derived class!
The sort implementations also explicitely call the Compare() function of the derived
class. This is to avoid various compiler bugs with using overloaded compare functions
and the inability of various compilers to find the right overloaded compare function.
To sort an array, an idList or an idStaticList, a new sort class, typically derived from
idSort_Quick, is implemented as follows:
class idSort_MySort : public idSort_Quick< idMyObject, idSort_MySort > {
public:
int Compare( const idMyObject & a, const idMyObject & b ) const {
if ( a should come before b ) {
return -1; // or any negative integer
} if ( a should come after b ) {
return 1; // or any positive integer
} else {
return 0;
}
}
};
To sort an array:
idMyObject array[100];
idSort_MySort().Sort( array, 100 );
To sort an idList:
idList< idMyObject > list;
list.Sort( idSort_MySort() );
The sort implementations never create temporaries of the template type. Only the
'SwapValues' template is used to move data around. This 'SwapValues' template can be
specialized to implement fast swapping of data. For instance, when sorting a list with
objects of some string class it is important to implement a specialized 'SwapValues' for
this string class to avoid excessive re-allocation and copying of strings.
================================================================================================
*/
/*
========================
SwapValues
========================
*/
template< typename _type_ >
ID_INLINE void SwapValues( _type_ & a, _type_ & b ) {
_type_ c = a;
a = b;
b = c;
}
/*
================================================
idSort is an abstract template class for sorting an array of objects of the specified data type.
The array of objects is sorted such that: Compare( array[i], array[i+1] ) <= 0 for all i
================================================
*/
template< typename _type_ >
class idSort {
public:
virtual ~idSort() {}
virtual void Sort( _type_ * base, unsigned int num ) const = 0;
};
/*
================================================
idSort_Quick is a sort template that implements the
quick-sort algorithm on an array of objects of the specified data type.
================================================
*/
template< typename _type_, typename _derived_ >
class idSort_Quick : public idSort< _type_ > {
public:
virtual void Sort( _type_ * base, unsigned int num ) const {
if ( num <= 0 ) {
return;
}
const int64 MAX_LEVELS = 128;
int64 lo[MAX_LEVELS], hi[MAX_LEVELS];
// 'lo' is the lower index, 'hi' is the upper index
// of the region of the array that is being sorted.
lo[0] = 0;
hi[0] = num - 1;
for ( int64 level = 0; level >= 0; ) {
int64 i = lo[level];
int64 j = hi[level];
// Only use quick-sort when there are 4 or more elements in this region and we are below MAX_LEVELS.
// Otherwise fall back to an insertion-sort.
if ( ( ( j - i ) >= 4 ) && ( level < ( MAX_LEVELS - 1 ) ) ) {
// Use the center element as the pivot.
// The median of a multi point sample could be used
// but simply taking the center works quite well.
int64 pi = ( i + j ) / 2;
// Move the pivot element to the end of the region.
SwapValues( base[j], base[pi] );
// Get a reference to the pivot element.
_type_ & pivot = base[j--];
// Partition the region.
do {
while( static_cast< const _derived_ * >( this )->Compare( base[i], pivot ) < 0 ) { if ( ++i >= j ) break; }
while( static_cast< const _derived_ * >( this )->Compare( base[j], pivot ) > 0 ) { if ( --j <= i ) break; }
if ( i >= j ) break;
SwapValues( base[i], base[j] );
} while( ++i < --j );
// Without these iterations sorting of arrays with many duplicates may
// become really slow because the partitioning can be very unbalanced.
// However, these iterations are unnecessary if all elements are unique.
while ( static_cast< const _derived_ * >( this )->Compare( base[i], pivot ) <= 0 && i < hi[level] ) { i++; }
while ( static_cast< const _derived_ * >( this )->Compare( base[j], pivot ) >= 0 && lo[level] < j ) { j--; }
// Move the pivot element in place.
SwapValues( pivot, base[i] );
assert( level < MAX_LEVELS - 1 );
lo[level+1] = i;
hi[level+1] = hi[level];
hi[level] = j;
level++;
} else {
// Insertion-sort of the remaining elements.
for( ; i < j; j-- ) {
int64 m = i;
for ( int64 k = i + 1; k <= j; k++ ) {
if ( static_cast< const _derived_ * >( this )->Compare( base[k], base[m] ) > 0 ) {
m = k;
}
}
SwapValues( base[m], base[j] );
}
level--;
}
}
}
};
/*
================================================
Default quick-sort comparison function that can
be used to sort scalars from small to large.
================================================
*/
template< typename _type_ >
class idSort_QuickDefault : public idSort_Quick< _type_, idSort_QuickDefault< _type_ > > {
public:
int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
};
/*
================================================
Specialization for floating point values to avoid an float-to-int
conversion for every comparison.
================================================
*/
template<>
class idSort_QuickDefault< float > : public idSort_Quick< float, idSort_QuickDefault< float > > {
public:
int Compare( const float & a, const float & b ) const {
if ( a < b ) {
return -1;
}
if ( a > b ) {
return 1;
}
return 0;
}
};
/*
================================================
idSort_Heap is a sort template class that implements the
heap-sort algorithm on an array of objects of the specified data type.
================================================
*/
template< typename _type_, typename _derived_ >
class idSort_Heap : public idSort< _type_ > {
public:
virtual void Sort( _type_ * base, unsigned int num ) const {
// get all elements in heap order
#if 1
// O( n )
for ( unsigned int i = num / 2; i > 0; i-- ) {
// sift down
unsigned int parent = i - 1;
for ( unsigned int child = parent * 2 + 1; child < num; child = parent * 2 + 1 ) {
if ( child + 1 < num && static_cast< const _derived_ * >( this )->Compare( base[child + 1], base[child] ) > 0 ) {
child++;
}
if ( static_cast< const _derived_ * >( this )->Compare( base[child], base[parent] ) <= 0 ) {
break;
}
SwapValues( base[parent], base[child] );
parent = child;
}
}
#else
// O(n log n)
for ( unsigned int i = 1; i < num; i++ ) {
// sift up
for ( unsigned int child = i; child > 0; ) {
unsigned int parent = ( child - 1 ) / 2;
if ( static_cast< const _derived_ * >( this )->Compare( base[parent], base[child] ) > 0 ) {
break;
}
SwapValues( base[child], base[parent] );
child = parent;
}
}
#endif
// get sorted elements while maintaining heap order
for ( unsigned int i = num - 1; i > 0; i-- ) {
SwapValues( base[0], base[i] );
// sift down
unsigned int parent = 0;
for ( unsigned int child = parent * 2 + 1; child < i; child = parent * 2 + 1 ) {
if ( child + 1 < i && static_cast< const _derived_ * >( this )->Compare( base[child + 1], base[child] ) > 0 ) {
child++;
}
if ( static_cast< const _derived_ * >( this )->Compare( base[child], base[parent] ) <= 0 ) {
break;
}
SwapValues( base[parent], base[child] );
parent = child;
}
}
}
};
/*
================================================
Default heap-sort comparison function that can
be used to sort scalars from small to large.
================================================
*/
template< typename _type_ >
class idSort_HeapDefault : public idSort_Heap< _type_, idSort_HeapDefault< _type_ > > {
public:
int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
};
/*
================================================
idSort_Insertion is a sort template class that implements the
insertion-sort algorithm on an array of objects of the specified data type.
================================================
*/
template< typename _type_, typename _derived_ >
class idSort_Insertion : public idSort< _type_ > {
public:
virtual void Sort( _type_ * base, unsigned int num ) const {
_type_ * lo = base;
_type_ * hi = base + ( num - 1 );
while( hi > lo ) {
_type_ * max = lo;
for ( _type_ * p = lo + 1; p <= hi; p++ ) {
if ( static_cast< const _derived_ * >( this )->Compare( (*p), (*max) ) > 0 ) {
max = p;
}
}
SwapValues( *max, *hi );
hi--;
}
}
};
/*
================================================
Default insertion-sort comparison function that can
be used to sort scalars from small to large.
================================================
*/
template< typename _type_ >
class idSort_InsertionDefault : public idSort_Insertion< _type_, idSort_InsertionDefault< _type_ > > {
public:
int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
};
#endif // !__SORT_H__

View File

@@ -0,0 +1,86 @@
/*
===========================================================================
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 __STACK_H__
#define __STACK_H__
/*
===============================================================================
Stack template
===============================================================================
*/
#define idStack( type, next ) idStackTemplate<type, (int)&(((type*)NULL)->next)>
template< class type, int nextOffset >
class idStackTemplate {
public:
idStackTemplate();
void Add( type *element );
type * Get();
private:
type * top;
type * bottom;
};
#define STACK_NEXT_PTR( element ) (*(type**)(((byte*)element)+nextOffset))
template< class type, int nextOffset >
idStackTemplate<type,nextOffset>::idStackTemplate() {
top = bottom = NULL;
}
template< class type, int nextOffset >
void idStackTemplate<type,nextOffset>::Add( type *element ) {
STACK_NEXT_PTR(element) = top;
top = element;
if ( !bottom ) {
bottom = element;
}
}
template< class type, int nextOffset >
type *idStackTemplate<type,nextOffset>::Get() {
type *element;
element = top;
if ( element ) {
top = STACK_NEXT_PTR(top);
if ( bottom == element ) {
bottom = NULL;
}
STACK_NEXT_PTR(element) = NULL;
}
return element;
}
#endif /* !__STACK_H__ */

View File

@@ -0,0 +1,656 @@
/*
===========================================================================
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 __STATICLIST_H__
#define __STATICLIST_H__
#include "List.h"
/*
===============================================================================
Static list template
A non-growing, memset-able list using no memory allocation.
===============================================================================
*/
template<class type,int size>
class idStaticList {
public:
idStaticList();
idStaticList( const idStaticList<type,size> &other );
~idStaticList<type,size>();
void Clear(); // marks the list as empty. does not deallocate or intialize data.
int Num() const; // returns number of elements in list
int Max() const; // returns the maximum number of elements in the list
void SetNum( int newnum ); // set number of elements in list
// sets the number of elements in list and initializes any newly allocated elements to the given value
void SetNum( int newNum, const type & initValue );
size_t Allocated() const; // returns total size of allocated memory
size_t Size() const; // returns total size of allocated memory including size of list type
size_t MemoryUsed() const; // returns size of the used elements in the list
const type & operator[]( int index ) const;
type & operator[]( int index );
type * Ptr(); // returns a pointer to the list
const type * Ptr() const; // returns a pointer to the list
type * Alloc(); // returns reference to a new data element at the end of the list. returns NULL when full.
int Append( const type & obj ); // append element
int Append( const idStaticList<type,size> &other ); // append list
int AddUnique( const type & obj ); // add unique element
int Insert( const type & obj, int index = 0 ); // insert the element at the given index
int FindIndex( const type & obj ) const; // find the index for the given element
type * Find( type const & obj ) const; // find pointer to the given element
int FindNull() const; // find the index for the first NULL pointer in the list
int IndexOf( const type *obj ) const; // returns the index for the pointer to an element in the list
bool RemoveIndex( int index ); // remove the element at the given index
bool RemoveIndexFast( int index ); // remove the element at the given index
bool Remove( const type & obj ); // remove the element
void Swap( idStaticList<type,size> &other ); // swap the contents of the lists
void DeleteContents( bool clear ); // delete the contents of the list
void Sort( const idSort<type> & sort = idSort_QuickDefault<type>() );
private:
int num;
type list[ size ];
private:
// resizes list to the given number of elements
void Resize( int newsize );
};
/*
================
idStaticList<type,size>::idStaticList()
================
*/
template<class type,int size>
ID_INLINE idStaticList<type,size>::idStaticList() {
num = 0;
}
/*
================
idStaticList<type,size>::idStaticList( const idStaticList<type,size> &other )
================
*/
template<class type,int size>
ID_INLINE idStaticList<type,size>::idStaticList( const idStaticList<type,size> &other ) {
*this = other;
}
/*
================
idStaticList<type,size>::~idStaticList<type,size>
================
*/
template<class type,int size>
ID_INLINE idStaticList<type,size>::~idStaticList() {
}
/*
================
idStaticList<type,size>::Clear
Sets the number of elements in the list to 0. Assumes that type automatically handles freeing up memory.
================
*/
template<class type,int size>
ID_INLINE void idStaticList<type,size>::Clear() {
num = 0;
}
/*
========================
idList<_type_,_tag_>::Sort
Performs a QuickSort on the list using the supplied sort algorithm.
Note: The data is merely moved around the list, so any pointers to data within the list may
no longer be valid.
========================
*/
template< class type,int size >
ID_INLINE void idStaticList<type,size>::Sort( const idSort<type> & sort ) {
if ( list == NULL ) {
return;
}
sort.Sort( Ptr(), Num() );
}
/*
================
idStaticList<type,size>::DeleteContents
Calls the destructor of all elements in the list. Conditionally frees up memory used by the list.
Note that this only works on lists containing pointers to objects and will cause a compiler error
if called with non-pointers. Since the list was not responsible for allocating the object, it has
no information on whether the object still exists or not, so care must be taken to ensure that
the pointers are still valid when this function is called. Function will set all pointers in the
list to NULL.
================
*/
template<class type,int size>
ID_INLINE void idStaticList<type,size>::DeleteContents( bool clear ) {
int i;
for( i = 0; i < num; i++ ) {
delete list[ i ];
list[ i ] = NULL;
}
if ( clear ) {
Clear();
} else {
memset( list, 0, sizeof( list ) );
}
}
/*
================
idStaticList<type,size>::Num
Returns the number of elements currently contained in the list.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::Num() const {
return num;
}
/*
================
idStaticList<type,size>::Num
Returns the maximum number of elements in the list.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::Max() const {
return size;
}
/*
================
idStaticList<type>::Allocated
================
*/
template<class type,int size>
ID_INLINE size_t idStaticList<type,size>::Allocated() const {
return size * sizeof( type );
}
/*
================
idStaticList<type>::Size
================
*/
template<class type,int size>
ID_INLINE size_t idStaticList<type,size>::Size() const {
return sizeof( idStaticList<type,size> ) + Allocated();
}
/*
================
idStaticList<type,size>::Num
================
*/
template<class type,int size>
ID_INLINE size_t idStaticList<type,size>::MemoryUsed() const {
return num * sizeof( list[ 0 ] );
}
/*
================
idStaticList<type,size>::SetNum
Set number of elements in list.
================
*/
template<class type,int size>
ID_INLINE void idStaticList<type,size>::SetNum( int newnum ) {
assert( newnum >= 0 );
assert( newnum <= size );
num = newnum;
}
/*
========================
idStaticList<_type_,_tag_>::SetNum
========================
*/
template< class type,int size >
ID_INLINE void idStaticList<type,size>::SetNum( int newNum, const type &initValue ) {
assert( newNum >= 0 );
newNum = Min( newNum, size );
assert( newNum <= size );
for ( int i = num; i < newNum; i++ ) {
list[i] = initValue;
}
num = newNum;
}
/*
================
idStaticList<type,size>::operator[] const
Access operator. Index must be within range or an assert will be issued in debug builds.
Release builds do no range checking.
================
*/
template<class type,int size>
ID_INLINE const type &idStaticList<type,size>::operator[]( int index ) const {
assert( index >= 0 );
assert( index < num );
return list[ index ];
}
/*
================
idStaticList<type,size>::operator[]
Access operator. Index must be within range or an assert will be issued in debug builds.
Release builds do no range checking.
================
*/
template<class type,int size>
ID_INLINE type &idStaticList<type,size>::operator[]( int index ) {
assert( index >= 0 );
assert( index < num );
return list[ index ];
}
/*
================
idStaticList<type,size>::Ptr
Returns a pointer to the begining of the array. Useful for iterating through the list in loops.
Note: may return NULL if the list is empty.
FIXME: Create an iterator template for this kind of thing.
================
*/
template<class type,int size>
ID_INLINE type *idStaticList<type,size>::Ptr() {
return &list[ 0 ];
}
/*
================
idStaticList<type,size>::Ptr
Returns a pointer to the begining of the array. Useful for iterating through the list in loops.
Note: may return NULL if the list is empty.
FIXME: Create an iterator template for this kind of thing.
================
*/
template<class type,int size>
ID_INLINE const type *idStaticList<type,size>::Ptr() const {
return &list[ 0 ];
}
/*
================
idStaticList<type,size>::Alloc
Returns a pointer to a new data element at the end of the list.
================
*/
template<class type,int size>
ID_INLINE type *idStaticList<type,size>::Alloc() {
if ( num >= size ) {
return NULL;
}
return &list[ num++ ];
}
/*
================
idStaticList<type,size>::Append
Increases the size of the list by one element and copies the supplied data into it.
Returns the index of the new element, or -1 when list is full.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::Append( type const & obj ) {
assert( num < size );
if ( num < size ) {
list[ num ] = obj;
num++;
return num - 1;
}
return -1;
}
/*
================
idStaticList<type,size>::Insert
Increases the size of the list by at leat one element if necessary
and inserts the supplied data into it.
Returns the index of the new element, or -1 when list is full.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::Insert( type const & obj, int index ) {
int i;
assert( num < size );
if ( num >= size ) {
return -1;
}
assert( index >= 0 );
if ( index < 0 ) {
index = 0;
} else if ( index > num ) {
index = num;
}
for( i = num; i > index; --i ) {
list[i] = list[i-1];
}
num++;
list[index] = obj;
return index;
}
/*
================
idStaticList<type,size>::Append
adds the other list to this one
Returns the size of the new combined list
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::Append( const idStaticList<type,size> &other ) {
int i;
int n = other.Num();
if ( num + n > size ) {
n = size - num;
}
for( i = 0; i < n; i++ ) {
list[i + num] = other.list[i];
}
num += n;
return Num();
}
/*
================
idStaticList<type,size>::AddUnique
Adds the data to the list if it doesn't already exist. Returns the index of the data in the list.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::AddUnique( type const & obj ) {
int index;
index = FindIndex( obj );
if ( index < 0 ) {
index = Append( obj );
}
return index;
}
/*
================
idStaticList<type,size>::FindIndex
Searches for the specified data in the list and returns it's index. Returns -1 if the data is not found.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::FindIndex( type const & obj ) const {
int i;
for( i = 0; i < num; i++ ) {
if ( list[ i ] == obj ) {
return i;
}
}
// Not found
return -1;
}
/*
================
idStaticList<type,size>::Find
Searches for the specified data in the list and returns it's address. Returns NULL if the data is not found.
================
*/
template<class type,int size>
ID_INLINE type *idStaticList<type,size>::Find( type const & obj ) const {
int i;
i = FindIndex( obj );
if ( i >= 0 ) {
return (type *) &list[ i ];
}
return NULL;
}
/*
================
idStaticList<type,size>::FindNull
Searches for a NULL pointer in the list. Returns -1 if NULL is not found.
NOTE: This function can only be called on lists containing pointers. Calling it
on non-pointer lists will cause a compiler error.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::FindNull() const {
int i;
for( i = 0; i < num; i++ ) {
if ( list[ i ] == NULL ) {
return i;
}
}
// Not found
return -1;
}
/*
================
idStaticList<type,size>::IndexOf
Takes a pointer to an element in the list and returns the index of the element.
This is NOT a guarantee that the object is really in the list.
Function will assert in debug builds if pointer is outside the bounds of the list,
but remains silent in release builds.
================
*/
template<class type,int size>
ID_INLINE int idStaticList<type,size>::IndexOf( type const *objptr ) const {
int index;
index = objptr - list;
assert( index >= 0 );
assert( index < num );
return index;
}
/*
================
idStaticList<type,size>::RemoveIndex
Removes the element at the specified index and moves all data following the element down to fill in the gap.
The number of elements in the list is reduced by one. Returns false if the index is outside the bounds of the list.
Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list.
================
*/
template<class type,int size>
ID_INLINE bool idStaticList<type,size>::RemoveIndex( int index ) {
int i;
assert( index >= 0 );
assert( index < num );
if ( ( index < 0 ) || ( index >= num ) ) {
return false;
}
num--;
for( i = index; i < num; i++ ) {
list[ i ] = list[ i + 1 ];
}
return true;
}
/*
========================
idList<_type_,_tag_>::RemoveIndexFast
Removes the element at the specified index and moves the last element into its spot, rather
than moving the whole array down by one. Of course, this doesn't maintain the order of
elements! The number of elements in the list is reduced by one.
return: bool - false if the data is not found in the list.
NOTE: The element is not destroyed, so any memory used by it may not be freed until the
destruction of the list.
========================
*/
template< typename _type_,int size >
ID_INLINE bool idStaticList<_type_,size>::RemoveIndexFast( int index ) {
if ( ( index < 0 ) || ( index >= num ) ) {
return false;
}
num--;
if ( index != num ) {
list[ index ] = list[ num ];
}
return true;
}
/*
================
idStaticList<type,size>::Remove
Removes the element if it is found within the list and moves all data following the element down to fill in the gap.
The number of elements in the list is reduced by one. Returns false if the data is not found in the list. Note that
the element is not destroyed, so any memory used by it may not be freed until the destruction of the list.
================
*/
template<class type,int size>
ID_INLINE bool idStaticList<type,size>::Remove( type const & obj ) {
int index;
index = FindIndex( obj );
if ( index >= 0 ) {
return RemoveIndex( index );
}
return false;
}
/*
================
idStaticList<type,size>::Swap
Swaps the contents of two lists
================
*/
template<class type,int size>
ID_INLINE void idStaticList<type,size>::Swap( idStaticList<type,size> &other ) {
idStaticList<type,size> temp = *this;
*this = other;
other = temp;
}
// debug tool to find uses of idlist that are dynamically growing
// Ideally, most lists on shipping titles will explicitly set their size correctly
// instead of relying on allocate-on-add
void BreakOnListGrowth();
void BreakOnListDefault();
/*
========================
idList<_type_,_tag_>::Resize
Allocates memory for the amount of elements requested while keeping the contents intact.
Contents are copied using their = operator so that data is correctly instantiated.
========================
*/
template< class type,int size >
ID_INLINE void idStaticList<type,size>::Resize( int newsize ) {
assert( newsize >= 0 );
// free up the list if no data is being reserved
if ( newsize <= 0 ) {
Clear();
return;
}
if ( newsize == size ) {
// not changing the size, so just exit
return;
}
assert( newsize < size );
return;
}
#endif /* !__STATICLIST_H__ */

View File

@@ -0,0 +1,204 @@
/*
===========================================================================
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 __STRLIST_H__
#define __STRLIST_H__
/*
===============================================================================
idStrList
===============================================================================
*/
typedef idList<idStr> idStrList;
typedef idList<idStr*> idStrPtrList;
typedef idStr *idStrPtr;
///*
//================
//idListSortCompare<idStrPtr>
//
//Compares two pointers to strings. Used to sort a list of string pointers alphabetically in idList<idStr>::Sort.
//================
//*/
//template<>
//ID_INLINE int idListSortCompare<idStrPtr, memTag_t _tag_ >( const idStrPtr *a, const idStrPtr *b ) {
// return ( *a )->Icmp( **b );
//}
///*
//================
//idStrList::Sort
//
//Sorts the list of strings alphabetically. Creates a list of pointers to the actual strings and sorts the
//pointer list. Then copies the strings into another list using the ordered list of pointers.
//================
//*/
//template<>
//ID_INLINE void idStrList::Sort( cmp_t *compare ) {
// int i;
//
// if ( !num ) {
// return;
// }
//
// idList<idStr> other;
// idList<idStrPtr> pointerList;
//
// pointerList.SetNum( num );
// for( i = 0; i < num; i++ ) {
// pointerList[ i ] = &( *this )[ i ];
// }
//
// pointerList.Sort();
//
// other.SetNum( num );
// other.SetGranularity( granularity );
// for( i = 0; i < other.Num(); i++ ) {
// other[ i ] = *pointerList[ i ];
// }
//
// this->Swap( other );
//}
///*
//================
//idStrList::SortSubSection
//
//Sorts a subsection of the list of strings alphabetically.
//================
//*/
//template<>
//ID_INLINE void idStrList::SortSubSection( int startIndex, int endIndex, cmp_t *compare ) {
// int i, s;
//
// if ( !num ) {
// return;
// }
// if ( startIndex < 0 ) {
// startIndex = 0;
// }
// if ( endIndex >= num ) {
// endIndex = num - 1;
// }
// if ( startIndex >= endIndex ) {
// return;
// }
//
// idList<idStr> other;
// idList<idStrPtr> pointerList;
//
// s = endIndex - startIndex + 1;
// other.SetNum( s );
// pointerList.SetNum( s );
// for( i = 0; i < s; i++ ) {
// other[ i ] = ( *this )[ startIndex + i ];
// pointerList[ i ] = &other[ i ];
// }
//
// pointerList.Sort();
//
// for( i = 0; i < s; i++ ) {
// (*this)[ startIndex + i ] = *pointerList[ i ];
// }
//}
/*
================
idStrList::Size
================
*/
template<>
ID_INLINE size_t idStrList::Size() const {
size_t s;
int i;
s = sizeof( *this );
for( i = 0; i < Num(); i++ ) {
s += ( *this )[ i ].Size();
}
return s;
}
/*
===============================================================================
idStrList path sorting
===============================================================================
*/
//
///*
//================
//idListSortComparePaths
//
//Compares two pointers to strings. Used to sort a list of string pointers alphabetically in idList<idStr>::Sort.
//================
//*/
//template<class idStrPtr>
//ID_INLINE int idListSortComparePaths( const idStrPtr *a, const idStrPtr *b ) {
// return ( *a )->IcmpPath( **b );
//}
///*
//================
//idStrListSortPaths
//
//Sorts the list of path strings alphabetically and makes sure folders come first.
//================
//*/
//ID_INLINE void idStrListSortPaths( idStrList &list ) {
// int i;
//
// if ( !list.Num() ) {
// return;
// }
//
// idList<idStr> other;
// idList<idStrPtr> pointerList;
//
// pointerList.SetNum( list.Num() );
// for( i = 0; i < list.Num(); i++ ) {
// pointerList[ i ] = &list[ i ];
// }
//
// pointerList.Sort( idListSortComparePaths<idStrPtr> );
//
// other.SetNum( list.Num() );
// other.SetGranularity( list.GetGranularity() );
// for( i = 0; i < other.Num(); i++ ) {
// other[ i ] = *pointerList[ i ];
// }
//
// list.Swap( other );
//}
#endif /* !__STRLIST_H__ */

View File

@@ -0,0 +1,228 @@
/*
===========================================================================
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 __STRPOOL_H__
#define __STRPOOL_H__
/*
===============================================================================
idStrPool
===============================================================================
*/
class idStrPool;
class idPoolStr : public idStr {
friend class idStrPool;
public:
idPoolStr() { numUsers = 0; }
~idPoolStr() { assert( numUsers == 0 ); }
// returns total size of allocated memory
size_t Allocated() const { return idStr::Allocated(); }
// returns total size of allocated memory including size of string pool type
size_t Size() const { return sizeof( *this ) + Allocated(); }
// returns a pointer to the pool this string was allocated from
const idStrPool * GetPool() const { return pool; }
private:
idStrPool * pool;
mutable int numUsers;
};
class idStrPool {
public:
idStrPool() { caseSensitive = true; }
void SetCaseSensitive( bool caseSensitive );
int Num() const { return pool.Num(); }
size_t Allocated() const;
size_t Size() const;
const idPoolStr * operator[]( int index ) const { return pool[index]; }
const idPoolStr * AllocString( const char *string );
void FreeString( const idPoolStr *poolStr );
const idPoolStr * CopyString( const idPoolStr *poolStr );
void Clear();
private:
bool caseSensitive;
idList<idPoolStr *> pool;
idHashIndex poolHash;
};
/*
================
idStrPool::SetCaseSensitive
================
*/
ID_INLINE void idStrPool::SetCaseSensitive( bool caseSensitive ) {
this->caseSensitive = caseSensitive;
}
/*
================
idStrPool::AllocString
================
*/
ID_INLINE const idPoolStr *idStrPool::AllocString( const char *string ) {
int i, hash;
idPoolStr *poolStr;
hash = poolHash.GenerateKey( string, caseSensitive );
if ( caseSensitive ) {
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
if ( pool[i]->Cmp( string ) == 0 ) {
pool[i]->numUsers++;
return pool[i];
}
}
} else {
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
if ( pool[i]->Icmp( string ) == 0 ) {
pool[i]->numUsers++;
return pool[i];
}
}
}
poolStr = new (TAG_IDLIB_STRING) idPoolStr;
*static_cast<idStr *>(poolStr) = string;
poolStr->pool = this;
poolStr->numUsers = 1;
poolHash.Add( hash, pool.Append( poolStr ) );
return poolStr;
}
/*
================
idStrPool::FreeString
================
*/
ID_INLINE void idStrPool::FreeString( const idPoolStr *poolStr ) {
int i, hash;
assert( poolStr->numUsers >= 1 );
assert( poolStr->pool == this );
poolStr->numUsers--;
if ( poolStr->numUsers <= 0 ) {
hash = poolHash.GenerateKey( poolStr->c_str(), caseSensitive );
if ( caseSensitive ) {
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
if ( pool[i]->Cmp( poolStr->c_str() ) == 0 ) {
break;
}
}
} else {
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
if ( pool[i]->Icmp( poolStr->c_str() ) == 0 ) {
break;
}
}
}
assert( i != -1 );
assert( pool[i] == poolStr );
delete pool[i];
pool.RemoveIndex( i );
poolHash.RemoveIndex( hash, i );
}
}
/*
================
idStrPool::CopyString
================
*/
ID_INLINE const idPoolStr *idStrPool::CopyString( const idPoolStr *poolStr ) {
assert( poolStr->numUsers >= 1 );
if ( poolStr->pool == this ) {
// the string is from this pool so just increase the user count
poolStr->numUsers++;
return poolStr;
} else {
// the string is from another pool so it needs to be re-allocated from this pool.
return AllocString( poolStr->c_str() );
}
}
/*
================
idStrPool::Clear
================
*/
ID_INLINE void idStrPool::Clear() {
int i;
for ( i = 0; i < pool.Num(); i++ ) {
pool[i]->numUsers = 0;
}
pool.DeleteContents( true );
poolHash.Free();
}
/*
================
idStrPool::Allocated
================
*/
ID_INLINE size_t idStrPool::Allocated() const {
int i;
size_t size;
size = pool.Allocated() + poolHash.Allocated();
for ( i = 0; i < pool.Num(); i++ ) {
size += pool[i]->Allocated();
}
return size;
}
/*
================
idStrPool::Size
================
*/
ID_INLINE size_t idStrPool::Size() const {
int i;
size_t size;
size = pool.Size() + poolHash.Size();
for ( i = 0; i < pool.Num(); i++ ) {
size += pool[i]->Size();
}
return size;
}
#endif /* !__STRPOOL_H__ */

View File

@@ -0,0 +1,270 @@
/*
===========================================================================
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 __VECTORSET_H__
#define __VECTORSET_H__
/*
===============================================================================
Vector Set
Creates a set of vectors without duplicates.
===============================================================================
*/
template< class type, int dimension >
class idVectorSet : public idList<type> {
public:
idVectorSet();
idVectorSet( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
// returns total size of allocated memory
size_t Allocated() const { return idList<type>::Allocated() + hash.Allocated(); }
// returns total size of allocated memory including size of type
size_t Size() const { return sizeof( *this ) + Allocated(); }
void Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
void ResizeIndex( const int newSize );
void Clear();
int FindVector( const type &v, const float epsilon );
private:
idHashIndex hash;
type mins;
type maxs;
int boxHashSize;
float boxInvSize[dimension];
float boxHalfSize[dimension];
};
template< class type, int dimension >
ID_INLINE idVectorSet<type,dimension>::idVectorSet() {
hash.Clear( idMath::IPow( boxHashSize, dimension ), 128 );
boxHashSize = 16;
memset( boxInvSize, 0, dimension * sizeof( boxInvSize[0] ) );
memset( boxHalfSize, 0, dimension * sizeof( boxHalfSize[0] ) );
}
template< class type, int dimension >
ID_INLINE idVectorSet<type,dimension>::idVectorSet( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
Init( mins, maxs, boxHashSize, initialSize );
}
template< class type, int dimension >
ID_INLINE void idVectorSet<type,dimension>::Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
int i;
float boxSize;
idList<type>::AssureSize( initialSize );
idList<type>::SetNum( 0, false );
hash.Clear( idMath::IPow( boxHashSize, dimension ), initialSize );
this->mins = mins;
this->maxs = maxs;
this->boxHashSize = boxHashSize;
for ( i = 0; i < dimension; i++ ) {
boxSize = ( maxs[i] - mins[i] ) / (float) boxHashSize;
boxInvSize[i] = 1.0f / boxSize;
boxHalfSize[i] = boxSize * 0.5f;
}
}
template< class type, int dimension >
ID_INLINE void idVectorSet<type,dimension>::ResizeIndex( const int newSize ) {
idList<type>::Resize( newSize );
hash.ResizeIndex( newSize );
}
template< class type, int dimension >
ID_INLINE void idVectorSet<type,dimension>::Clear() {
idList<type>::Clear();
hash.Clear();
}
template< class type, int dimension >
ID_INLINE int idVectorSet<type,dimension>::FindVector( const type &v, const float epsilon ) {
int i, j, k, hashKey, partialHashKey[dimension];
for ( i = 0; i < dimension; i++ ) {
assert( epsilon <= boxHalfSize[i] );
partialHashKey[i] = (int) ( ( v[i] - mins[i] - boxHalfSize[i] ) * boxInvSize[i] );
}
for ( i = 0; i < ( 1 << dimension ); i++ ) {
hashKey = 0;
for ( j = 0; j < dimension; j++ ) {
hashKey *= boxHashSize;
hashKey += partialHashKey[j] + ( ( i >> j ) & 1 );
}
for ( j = hash.First( hashKey ); j >= 0; j = hash.Next( j ) ) {
const type &lv = (*this)[j];
for ( k = 0; k < dimension; k++ ) {
if ( idMath::Fabs( lv[k] - v[k] ) > epsilon ) {
break;
}
}
if ( k >= dimension ) {
return j;
}
}
}
hashKey = 0;
for ( i = 0; i < dimension; i++ ) {
hashKey *= boxHashSize;
hashKey += (int) ( ( v[i] - mins[i] ) * boxInvSize[i] );
}
hash.Add( hashKey, idList<type>::Num() );
Append( v );
return idList<type>::Num()-1;
}
/*
===============================================================================
Vector Subset
Creates a subset without duplicates from an existing list with vectors.
===============================================================================
*/
template< class type, int dimension >
class idVectorSubset {
public:
idVectorSubset();
idVectorSubset( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
// returns total size of allocated memory
size_t Allocated() const { return idList<type>::Allocated() + hash.Allocated(); }
// returns total size of allocated memory including size of type
size_t Size() const { return sizeof( *this ) + Allocated(); }
void Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
void Clear();
// returns either vectorNum or an index to a previously found vector
int FindVector( const type *vectorList, const int vectorNum, const float epsilon );
private:
idHashIndex hash;
type mins;
type maxs;
int boxHashSize;
float boxInvSize[dimension];
float boxHalfSize[dimension];
};
template< class type, int dimension >
ID_INLINE idVectorSubset<type,dimension>::idVectorSubset() {
hash.Clear( idMath::IPow( boxHashSize, dimension ), 128 );
boxHashSize = 16;
memset( boxInvSize, 0, dimension * sizeof( boxInvSize[0] ) );
memset( boxHalfSize, 0, dimension * sizeof( boxHalfSize[0] ) );
}
template< class type, int dimension >
ID_INLINE idVectorSubset<type,dimension>::idVectorSubset( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
Init( mins, maxs, boxHashSize, initialSize );
}
template< class type, int dimension >
ID_INLINE void idVectorSubset<type,dimension>::Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
int i;
float boxSize;
hash.Clear( idMath::IPow( boxHashSize, dimension ), initialSize );
this->mins = mins;
this->maxs = maxs;
this->boxHashSize = boxHashSize;
for ( i = 0; i < dimension; i++ ) {
boxSize = ( maxs[i] - mins[i] ) / (float) boxHashSize;
boxInvSize[i] = 1.0f / boxSize;
boxHalfSize[i] = boxSize * 0.5f;
}
}
template< class type, int dimension >
ID_INLINE void idVectorSubset<type,dimension>::Clear() {
idList<type>::Clear();
hash.Clear();
}
template< class type, int dimension >
ID_INLINE int idVectorSubset<type,dimension>::FindVector( const type *vectorList, const int vectorNum, const float epsilon ) {
int i, j, k, hashKey, partialHashKey[dimension];
const type &v = vectorList[vectorNum];
for ( i = 0; i < dimension; i++ ) {
assert( epsilon <= boxHalfSize[i] );
partialHashKey[i] = (int) ( ( v[i] - mins[i] - boxHalfSize[i] ) * boxInvSize[i] );
}
for ( i = 0; i < ( 1 << dimension ); i++ ) {
hashKey = 0;
for ( j = 0; j < dimension; j++ ) {
hashKey *= boxHashSize;
hashKey += partialHashKey[j] + ( ( i >> j ) & 1 );
}
for ( j = hash.First( hashKey ); j >= 0; j = hash.Next( j ) ) {
const type &lv = vectorList[j];
for ( k = 0; k < dimension; k++ ) {
if ( idMath::Fabs( lv[k] - v[k] ) > epsilon ) {
break;
}
}
if ( k >= dimension ) {
return j;
}
}
}
hashKey = 0;
for ( i = 0; i < dimension; i++ ) {
hashKey *= boxHashSize;
hashKey += (int) ( ( v[i] - mins[i] ) * boxInvSize[i] );
}
hash.Add( hashKey, vectorNum );
return vectorNum;
}
#endif /* !__VECTORSET_H__ */

View 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;
}

View 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__ */

View 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__ */

View 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;
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__

View 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;
}

View 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__ */

View 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();
}

View 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__ */

View 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;
}

View 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__ */

View 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();
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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 &centerOfMass, 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__ */

File diff suppressed because it is too large Load Diff

View 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 &center ) 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__ */

View 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 &center ) const {
int i;
float radius, r;
idVec2 dir;
radius = 0.0f;
for ( i = 0; i < numPoints; i++ ) {
dir = p[i] - center;
r = dir * dir;
if ( r > radius ) {
radius = r;
}
}
return idMath::Sqrt( radius );
}
/*
============
idWinding2D::GetBounds
============
*/
void idWinding2D::GetBounds( idVec2 bounds[2] ) const {
int i;
if ( !numPoints ) {
bounds[0].x = bounds[0].y = idMath::INFINITY;
bounds[1].x = bounds[1].y = -idMath::INFINITY;
return;
}
bounds[0] = bounds[1] = p[0];
for ( i = 1; i < numPoints; i++ ) {
if ( p[i].x < bounds[0].x ) {
bounds[0].x = p[i].x;
} else if ( p[i].x > bounds[1].x ) {
bounds[1].x = p[i].x;
}
if ( p[i].y < bounds[0].y ) {
bounds[0].y = p[i].y;
} else if ( p[i].y > bounds[1].y ) {
bounds[1].y = p[i].y;
}
}
}
/*
=============
idWinding2D::IsTiny
=============
*/
#define EDGE_LENGTH 0.2f
bool idWinding2D::IsTiny() 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;
}

View 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 &center ) 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__ */

167
neo/idlib/hashing/CRC32.cpp Normal file
View File

@@ -0,0 +1,167 @@
#pragma hdrstop
#include "../precompiled.h"
/*
CRC-32
Copyright (C) 1995-1998 Mark Adler
*/
#define CRC32_INIT_VALUE 0xffffffffL
#define CRC32_XOR_VALUE 0xffffffffL
#ifdef CREATE_CRC_TABLE
static unsigned long crctable[256];
/*
Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0.
Polynomials over GF(2) are represented in binary, one bit per coefficient,
with the lowest powers in the most significant bit. Then adding polynomials
is just exclusive-or, and multiplying a polynomial by x is a right shift by
one. If we call the above polynomial p, and represent a byte as the
polynomial q, also with the lowest power in the most significant bit (so the
byte 0xb1 is the polynomial x^7+x^3+x^1+x^0), then the CRC is (q*x^32) mod p,
where a mod b means the remainder after dividing a by b.
This calculation is done using the shift-register method of multiplying and
taking the remainder. The register is initialized to zero, and for each
incoming bit, x^32 is added mod p to the register if the bit is a one (where
x^32 mod p is p+x^32 = x^26+...+x^0), and the register is multiplied mod p by
x (which is shifting right by one and adding x^32 mod p if the bit shifted
out is a one). We start with the highest power (least significant bit) of
q and repeat for all eight bits of q.
The table is simply the CRC of all possible eight bit values. This is all
the information needed to generate CRC's on data a byte at a time for all
combinations of CRC register values and incoming bytes.
*/
void make_crc_table( void ) {
int i, j;
unsigned long c, poly;
/* terms of polynomial defining this crc (except x^32): */
static const byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
/* make exclusive-or pattern from polynomial (0xedb88320L) */
poly = 0L;
for ( i = 0; i < sizeof( p ) / sizeof( byte ); i++ ) {
poly |= 1L << ( 31 - p[i] );
}
for ( i = 0; i < 256; i++ ) {
c = (unsigned long)i;
for ( j = 0; j < 8; j++ ) {
c = ( c & 1 ) ? poly ^ ( c >> 1 ) : ( c >> 1 );
}
crctable[i] = c;
}
}
#else
/*
Table of CRC-32's of all single-byte values (made by make_crc_table)
*/
static unsigned long crctable[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};
#endif
void CRC32_InitChecksum( unsigned long &crcvalue ) {
crcvalue = CRC32_INIT_VALUE;
}
void CRC32_Update( unsigned long &crcvalue, const byte data ) {
crcvalue = crctable[ ( crcvalue ^ data ) & 0xff ] ^ ( crcvalue >> 8 );
}
void CRC32_UpdateChecksum( unsigned long &crcvalue, const void *data, int length ) {
unsigned long crc;
const unsigned char *buf = (const unsigned char *) data;
crc = crcvalue;
while( length-- ) {
crc = crctable[ ( crc ^ ( *buf++ ) ) & 0xff ] ^ ( crc >> 8 );
}
crcvalue = crc;
}
void CRC32_FinishChecksum( unsigned long &crcvalue ) {
crcvalue ^= CRC32_XOR_VALUE;
}
unsigned long CRC32_BlockChecksum( const void *data, int length ) {
unsigned long crc;
CRC32_InitChecksum( crc );
CRC32_UpdateChecksum( crc, data, length );
CRC32_FinishChecksum( crc );
return crc;
}

18
neo/idlib/hashing/CRC32.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __CRC32_H__
#define __CRC32_H__
/*
===============================================================================
Calculates a checksum for a block of data
using the CRC-32.
===============================================================================
*/
void CRC32_InitChecksum( unsigned long &crcvalue );
void CRC32_UpdateChecksum( unsigned long &crcvalue, const void *data, int length );
void CRC32_FinishChecksum( unsigned long &crcvalue );
unsigned long CRC32_BlockChecksum( const void *data, int length );
#endif /* !__CRC32_H__ */

259
neo/idlib/hashing/MD4.cpp Normal file
View File

@@ -0,0 +1,259 @@
#pragma hdrstop
#include "../precompiled.h"
/*
RSA Data Security, Inc., MD4 message-digest algorithm. (RFC1320)
*/
/*
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD4 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD4 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;
/* MD4 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD4_CTX;
/* Constants for MD4Transform routine. */
#define S11 3
#define S12 7
#define S13 11
#define S14 19
#define S21 3
#define S22 5
#define S23 9
#define S24 13
#define S31 3
#define S32 9
#define S33 11
#define S34 15
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G and H are basic MD4 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
static void Encode( unsigned char *output, UINT4 *input, unsigned int len ) {
unsigned int i, j;
for ( i = 0, j = 0; j < len; i++, j += 4 ) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
static void Decode( UINT4 *output, const unsigned char *input, unsigned int len ) {
unsigned int i, j;
for ( i = 0, j = 0; j < len; i++, j += 4 ) {
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
}
/* MD4 basic transformation. Transforms state based on block. */
static void MD4_Transform( UINT4 state[4], const unsigned char block[64] ) {
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11); /* 1 */
FF (d, a, b, c, x[ 1], S12); /* 2 */
FF (c, d, a, b, x[ 2], S13); /* 3 */
FF (b, c, d, a, x[ 3], S14); /* 4 */
FF (a, b, c, d, x[ 4], S11); /* 5 */
FF (d, a, b, c, x[ 5], S12); /* 6 */
FF (c, d, a, b, x[ 6], S13); /* 7 */
FF (b, c, d, a, x[ 7], S14); /* 8 */
FF (a, b, c, d, x[ 8], S11); /* 9 */
FF (d, a, b, c, x[ 9], S12); /* 10 */
FF (c, d, a, b, x[10], S13); /* 11 */
FF (b, c, d, a, x[11], S14); /* 12 */
FF (a, b, c, d, x[12], S11); /* 13 */
FF (d, a, b, c, x[13], S12); /* 14 */
FF (c, d, a, b, x[14], S13); /* 15 */
FF (b, c, d, a, x[15], S14); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 0], S21); /* 17 */
GG (d, a, b, c, x[ 4], S22); /* 18 */
GG (c, d, a, b, x[ 8], S23); /* 19 */
GG (b, c, d, a, x[12], S24); /* 20 */
GG (a, b, c, d, x[ 1], S21); /* 21 */
GG (d, a, b, c, x[ 5], S22); /* 22 */
GG (c, d, a, b, x[ 9], S23); /* 23 */
GG (b, c, d, a, x[13], S24); /* 24 */
GG (a, b, c, d, x[ 2], S21); /* 25 */
GG (d, a, b, c, x[ 6], S22); /* 26 */
GG (c, d, a, b, x[10], S23); /* 27 */
GG (b, c, d, a, x[14], S24); /* 28 */
GG (a, b, c, d, x[ 3], S21); /* 29 */
GG (d, a, b, c, x[ 7], S22); /* 30 */
GG (c, d, a, b, x[11], S23); /* 31 */
GG (b, c, d, a, x[15], S24); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 0], S31); /* 33 */
HH (d, a, b, c, x[ 8], S32); /* 34 */
HH (c, d, a, b, x[ 4], S33); /* 35 */
HH (b, c, d, a, x[12], S34); /* 36 */
HH (a, b, c, d, x[ 2], S31); /* 37 */
HH (d, a, b, c, x[10], S32); /* 38 */
HH (c, d, a, b, x[ 6], S33); /* 39 */
HH (b, c, d, a, x[14], S34); /* 40 */
HH (a, b, c, d, x[ 1], S31); /* 41 */
HH (d, a, b, c, x[ 9], S32); /* 42 */
HH (c, d, a, b, x[ 5], S33); /* 43 */
HH (b, c, d, a, x[13], S34); /* 44 */
HH (a, b, c, d, x[ 3], S31); /* 45 */
HH (d, a, b, c, x[11], S32); /* 46 */
HH (c, d, a, b, x[ 7], S33); /* 47 */
HH (b, c, d, a, x[15], S34); /* 48 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.*/
memset ((POINTER)x, 0, sizeof (x));
}
/* MD4 initialization. Begins an MD4 operation, writing a new context. */
void MD4_Init( MD4_CTX *context ) {
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
void MD4_Update( MD4_CTX *context, const unsigned char *input, unsigned int inputLen ) {
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.*/
if ( inputLen >= partLen ) {
memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD4_Transform (context->state, context->buffer);
for ( i = partLen; i + 63 < inputLen; i += 64 ) {
MD4_Transform (context->state, &input[i]);
}
index = 0;
} else {
i = 0;
}
/* Buffer remaining input */
memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
}
/* MD4 finalization. Ends an MD4 message-digest operation, writing the message digest and zeroizing the context. */
void MD4_Final( MD4_CTX *context, unsigned char digest[16] ) {
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode( bits, context->count, 8 );
/* Pad out to 56 mod 64.*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD4_Update (context, PADDING, padLen);
/* Append length (before padding) */
MD4_Update( context, bits, 8 );
/* Store state in digest */
Encode( digest, context->state, 16 );
/* Zeroize sensitive information.*/
memset ((POINTER)context, 0, sizeof (*context));
}
/*
===============
MD4_BlockChecksum
===============
*/
unsigned long MD4_BlockChecksum( const void *data, int length ) {
unsigned long digest[4];
unsigned long val;
MD4_CTX ctx;
MD4_Init( &ctx );
MD4_Update( &ctx, (unsigned char *)data, length );
MD4_Final( &ctx, (unsigned char *)digest );
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
return val;
}

15
neo/idlib/hashing/MD4.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef __MD4_H__
#define __MD4_H__
/*
===============================================================================
Calculates a checksum for a block of data
using the MD4 message-digest algorithm.
===============================================================================
*/
unsigned long MD4_BlockChecksum( const void *data, int length );
#endif /* !__MD4_H__ */

304
neo/idlib/hashing/MD5.cpp Normal file
View File

@@ -0,0 +1,304 @@
/*
===========================================================================
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"
/*
================================================================================================
Contains the MD5BlockChecksum implementation.
================================================================================================
*/
// POINTER defines a generic pointer type
typedef unsigned char *POINTER;
// UINT2 defines a two byte word
typedef unsigned short int UINT2;
// UINT4 defines a four byte word
typedef unsigned int UINT4;
//------------------------
// The four core functions - F1 is optimized somewhat
// JDC: I wouldn't have condoned the change in something as sensitive as a hash function,
// but it looks ok and a random test function checked it out.
//------------------------
// #define F1(x, y, z) (x & y | ~x & z)
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
// This is the central step in the MD5 algorithm.
#define MD5STEP(f, w, x, y, z, data, s) ( w += f(x, y, z) + (data), w = w<<s | w>>(32-s), w += x )
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
========================
Encode
Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4.
========================
*/
static void Encode( unsigned char *output, UINT4 *input, unsigned int len ) {
unsigned int i, j;
for ( i = 0, j = 0; j < len; i++, j += 4 ) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/*
========================
Decode
Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4.
========================
*/
static void Decode( UINT4 *output, const unsigned char *input, unsigned int len ) {
unsigned int i, j;
for ( i = 0, j = 0; j < len; i++, j += 4 ) {
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
}
/*
========================
MD5_Transform
The core of the MD5 algorithm, this alters an existing MD5 hash to reflect the addition of 16
longwords of new data. MD5Update blocks the data and converts bytes into longwords for this
routine.
========================
*/
void MD5_Transform( unsigned int state[4], const unsigned char block[64] ) {
unsigned int a, b, c, d, x[16];
a = state[0];
b = state[1];
c = state[2];
d = state[3];
Decode( x, block, 64 );
MD5STEP( F1, a, b, c, d, x[ 0] + 0xd76aa478, 7 );
MD5STEP( F1, d, a, b, c, x[ 1] + 0xe8c7b756, 12 );
MD5STEP( F1, c, d, a, b, x[ 2] + 0x242070db, 17 );
MD5STEP( F1, b, c, d, a, x[ 3] + 0xc1bdceee, 22 );
MD5STEP( F1, a, b, c, d, x[ 4] + 0xf57c0faf, 7 );
MD5STEP( F1, d, a, b, c, x[ 5] + 0x4787c62a, 12 );
MD5STEP( F1, c, d, a, b, x[ 6] + 0xa8304613, 17 );
MD5STEP( F1, b, c, d, a, x[ 7] + 0xfd469501, 22 );
MD5STEP( F1, a, b, c, d, x[ 8] + 0x698098d8, 7 );
MD5STEP( F1, d, a, b, c, x[ 9] + 0x8b44f7af, 12 );
MD5STEP( F1, c, d, a, b, x[10] + 0xffff5bb1, 17 );
MD5STEP( F1, b, c, d, a, x[11] + 0x895cd7be, 22 );
MD5STEP( F1, a, b, c, d, x[12] + 0x6b901122, 7 );
MD5STEP( F1, d, a, b, c, x[13] + 0xfd987193, 12 );
MD5STEP( F1, c, d, a, b, x[14] + 0xa679438e, 17 );
MD5STEP( F1, b, c, d, a, x[15] + 0x49b40821, 22 );
MD5STEP( F2, a, b, c, d, x[ 1] + 0xf61e2562, 5 );
MD5STEP( F2, d, a, b, c, x[ 6] + 0xc040b340, 9 );
MD5STEP( F2, c, d, a, b, x[11] + 0x265e5a51, 14 );
MD5STEP( F2, b, c, d, a, x[ 0] + 0xe9b6c7aa, 20 );
MD5STEP( F2, a, b, c, d, x[ 5] + 0xd62f105d, 5 );
MD5STEP( F2, d, a, b, c, x[10] + 0x02441453, 9 );
MD5STEP( F2, c, d, a, b, x[15] + 0xd8a1e681, 14 );
MD5STEP( F2, b, c, d, a, x[ 4] + 0xe7d3fbc8, 20 );
MD5STEP( F2, a, b, c, d, x[ 9] + 0x21e1cde6, 5 );
MD5STEP( F2, d, a, b, c, x[14] + 0xc33707d6, 9 );
MD5STEP( F2, c, d, a, b, x[ 3] + 0xf4d50d87, 14 );
MD5STEP( F2, b, c, d, a, x[ 8] + 0x455a14ed, 20 );
MD5STEP( F2, a, b, c, d, x[13] + 0xa9e3e905, 5 );
MD5STEP( F2, d, a, b, c, x[ 2] + 0xfcefa3f8, 9 );
MD5STEP( F2, c, d, a, b, x[ 7] + 0x676f02d9, 14 );
MD5STEP( F2, b, c, d, a, x[12] + 0x8d2a4c8a, 20 );
MD5STEP( F3, a, b, c, d, x[ 5] + 0xfffa3942, 4 );
MD5STEP( F3, d, a, b, c, x[ 8] + 0x8771f681, 11 );
MD5STEP( F3, c, d, a, b, x[11] + 0x6d9d6122, 16 );
MD5STEP( F3, b, c, d, a, x[14] + 0xfde5380c, 23 );
MD5STEP( F3, a, b, c, d, x[ 1] + 0xa4beea44, 4 );
MD5STEP( F3, d, a, b, c, x[ 4] + 0x4bdecfa9, 11 );
MD5STEP( F3, c, d, a, b, x[ 7] + 0xf6bb4b60, 16 );
MD5STEP( F3, b, c, d, a, x[10] + 0xbebfbc70, 23 );
MD5STEP( F3, a, b, c, d, x[13] + 0x289b7ec6, 4 );
MD5STEP( F3, d, a, b, c, x[ 0] + 0xeaa127fa, 11 );
MD5STEP( F3, c, d, a, b, x[ 3] + 0xd4ef3085, 16 );
MD5STEP( F3, b, c, d, a, x[ 6] + 0x04881d05, 23 );
MD5STEP( F3, a, b, c, d, x[ 9] + 0xd9d4d039, 4 );
MD5STEP( F3, d, a, b, c, x[12] + 0xe6db99e5, 11 );
MD5STEP( F3, c, d, a, b, x[15] + 0x1fa27cf8, 16 );
MD5STEP( F3, b, c, d, a, x[ 2] + 0xc4ac5665, 23 );
MD5STEP( F4, a, b, c, d, x[ 0] + 0xf4292244, 6 );
MD5STEP( F4, d, a, b, c, x[ 7] + 0x432aff97, 10 );
MD5STEP( F4, c, d, a, b, x[14] + 0xab9423a7, 15 );
MD5STEP( F4, b, c, d, a, x[ 5] + 0xfc93a039, 21 );
MD5STEP( F4, a, b, c, d, x[12] + 0x655b59c3, 6 );
MD5STEP( F4, d, a, b, c, x[ 3] + 0x8f0ccc92, 10 );
MD5STEP( F4, c, d, a, b, x[10] + 0xffeff47d, 15 );
MD5STEP( F4, b, c, d, a, x[ 1] + 0x85845dd1, 21 );
MD5STEP( F4, a, b, c, d, x[ 8] + 0x6fa87e4f, 6 );
MD5STEP( F4, d, a, b, c, x[15] + 0xfe2ce6e0, 10 );
MD5STEP( F4, c, d, a, b, x[ 6] + 0xa3014314, 15 );
MD5STEP( F4, b, c, d, a, x[13] + 0x4e0811a1, 21 );
MD5STEP( F4, a, b, c, d, x[ 4] + 0xf7537e82, 6 );
MD5STEP( F4, d, a, b, c, x[11] + 0xbd3af235, 10 );
MD5STEP( F4, c, d, a, b, x[ 2] + 0x2ad7d2bb, 15 );
MD5STEP( F4, b, c, d, a, x[ 9] + 0xeb86d391, 21 );
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset( (POINTER)x, 0, sizeof( x ) );
}
/*
========================
MD5_Init
MD5 initialization. Begins an MD5 operation, writing a new context.
========================
*/
void MD5_Init( MD5_CTX *ctx ) {
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xefcdab89;
ctx->state[2] = 0x98badcfe;
ctx->state[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
========================
MD5_Update
MD5 block update operation. Continues an MD5 message-digest operation, processing another
message block, and updating the context.
========================
*/
void MD5_Update( MD5_CTX *context, unsigned char const *input, size_t inputLen ) {
unsigned int i, index, partLen;
// Compute number of bytes mod 64
index = (unsigned int)((context->bits[0] >> 3) & 0x3F);
// Update number of bits
if ((context->bits[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3)) {
context->bits[1]++;
}
context->bits[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
// Transform as many times as possible.
if ( inputLen >= partLen ) {
memcpy( (POINTER)&context->in[index], (POINTER)input, partLen );
MD5_Transform( context->state, context->in );
for ( i = partLen; i + 63 < inputLen; i += 64 ) {
MD5_Transform( context->state, &input[i] );
}
index = 0;
} else {
i = 0;
}
// Buffer remaining input
memcpy( (POINTER)&context->in[index], (POINTER)&input[i], inputLen-i );
}
/*
========================
MD5_Final
MD5 finalization. Ends an MD5 message-digest operation, writing the message digest and
zero-izing the context.
========================
*/
void MD5_Final( MD5_CTX *context, unsigned char digest[16] ) {
unsigned char bits[8];
unsigned int index, padLen;
// Save number of bits
Encode( bits, context->bits, 8 );
// Pad out to 56 mod 64.
index = (unsigned int)((context->bits[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5_Update( context, PADDING, padLen );
// Append length (before padding)
MD5_Update( context, bits, 8 );
// Store state in digest
Encode( digest, context->state, 16 );
// Zeroize sensitive information.
memset( (POINTER)context, 0, sizeof( *context ) );
}
/*
========================
MD5_BlockChecksum
========================
*/
unsigned int MD5_BlockChecksum( const void *data, size_t length ) {
unsigned char digest[16];
unsigned int val;
MD5_CTX ctx;
MD5_Init( &ctx );
MD5_Update( &ctx, (unsigned char *)data, length );
MD5_Final( &ctx, (unsigned char *)digest );
// Handle it manually to be endian-safe since we don't have access to idSwap.
val = ( digest[3] << 24 | digest[2] << 16 | digest[1] << 8 | digest[0] ) ^
( digest[7] << 24 | digest[6] << 16 | digest[5] << 8 | digest[4] ) ^
( digest[11] << 24 | digest[10] << 16 | digest[9] << 8 | digest[8] ) ^
( digest[15] << 24 | digest[14] << 16 | digest[13] << 8 | digest[12] );
return val;
}

24
neo/idlib/hashing/MD5.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef __MD5_H__
#define __MD5_H__
/*
===============================================================================
Calculates a checksum for a block of data
using the MD5 message-digest algorithm.
===============================================================================
*/
struct MD5_CTX {
unsigned int state[4];
unsigned int bits[2];
unsigned char in[64];
};
void MD5_Init( MD5_CTX *ctx );
void MD5_Update( MD5_CTX *context, unsigned char const *input, size_t inputLen );
void MD5_Final( MD5_CTX *context, unsigned char digest[16] );
unsigned int MD5_BlockChecksum( const void *data, size_t length );
#endif /* !__MD5_H__ */

240
neo/idlib/math/Angles.cpp Normal file
View File

@@ -0,0 +1,240 @@
/*
===========================================================================
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 <float.h>
idAngles ang_zero( 0.0f, 0.0f, 0.0f );
/*
=================
idAngles::Normalize360
returns angles normalized to the range [0 <= angle < 360]
=================
*/
idAngles& idAngles::Normalize360() {
int i;
for ( i = 0; i < 3; i++ ) {
if ( ( (*this)[i] >= 360.0f ) || ( (*this)[i] < 0.0f ) ) {
(*this)[i] -= floor( (*this)[i] / 360.0f ) * 360.0f;
if ( (*this)[i] >= 360.0f ) {
(*this)[i] -= 360.0f;
}
if ( (*this)[i] < 0.0f ) {
(*this)[i] += 360.0f;
}
}
}
return *this;
}
/*
=================
idAngles::Normalize180
returns angles normalized to the range [-180 < angle <= 180]
=================
*/
idAngles& idAngles::Normalize180() {
Normalize360();
if ( pitch > 180.0f ) {
pitch -= 360.0f;
}
if ( yaw > 180.0f ) {
yaw -= 360.0f;
}
if ( roll > 180.0f ) {
roll -= 360.0f;
}
return *this;
}
/*
=================
idAngles::ToVectors
=================
*/
void idAngles::ToVectors( idVec3 *forward, idVec3 *right, idVec3 *up ) const {
float sr, sp, sy, cr, cp, cy;
idMath::SinCos( DEG2RAD( yaw ), sy, cy );
idMath::SinCos( DEG2RAD( pitch ), sp, cp );
idMath::SinCos( DEG2RAD( roll ), sr, cr );
if ( forward ) {
forward->Set( cp * cy, cp * sy, -sp );
}
if ( right ) {
right->Set( -sr * sp * cy + cr * sy, -sr * sp * sy + -cr * cy, -sr * cp );
}
if ( up ) {
up->Set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp );
}
}
/*
=================
idAngles::ToForward
=================
*/
idVec3 idAngles::ToForward() const {
float sp, sy, cp, cy;
idMath::SinCos( DEG2RAD( yaw ), sy, cy );
idMath::SinCos( DEG2RAD( pitch ), sp, cp );
return idVec3( cp * cy, cp * sy, -sp );
}
/*
=================
idAngles::ToQuat
=================
*/
idQuat idAngles::ToQuat() const {
float sx, cx, sy, cy, sz, cz;
float sxcy, cxcy, sxsy, cxsy;
idMath::SinCos( DEG2RAD( yaw ) * 0.5f, sz, cz );
idMath::SinCos( DEG2RAD( pitch ) * 0.5f, sy, cy );
idMath::SinCos( DEG2RAD( roll ) * 0.5f, sx, cx );
sxcy = sx * cy;
cxcy = cx * cy;
sxsy = sx * sy;
cxsy = cx * sy;
return idQuat( cxsy*sz - sxcy*cz, -cxsy*cz - sxcy*sz, sxsy*cz - cxcy*sz, cxcy*cz + sxsy*sz );
}
/*
=================
idAngles::ToRotation
=================
*/
idRotation idAngles::ToRotation() const {
idVec3 vec;
float angle, w;
float sx, cx, sy, cy, sz, cz;
float sxcy, cxcy, sxsy, cxsy;
if ( pitch == 0.0f ) {
if ( yaw == 0.0f ) {
return idRotation( vec3_origin, idVec3( -1.0f, 0.0f, 0.0f ), roll );
}
if ( roll == 0.0f ) {
return idRotation( vec3_origin, idVec3( 0.0f, 0.0f, -1.0f ), yaw );
}
} else if ( yaw == 0.0f && roll == 0.0f ) {
return idRotation( vec3_origin, idVec3( 0.0f, -1.0f, 0.0f ), pitch );
}
idMath::SinCos( DEG2RAD( yaw ) * 0.5f, sz, cz );
idMath::SinCos( DEG2RAD( pitch ) * 0.5f, sy, cy );
idMath::SinCos( DEG2RAD( roll ) * 0.5f, sx, cx );
sxcy = sx * cy;
cxcy = cx * cy;
sxsy = sx * sy;
cxsy = cx * sy;
vec.x = cxsy * sz - sxcy * cz;
vec.y = -cxsy * cz - sxcy * sz;
vec.z = sxsy * cz - cxcy * sz;
w = cxcy * cz + sxsy * sz;
angle = idMath::ACos( w );
if ( angle == 0.0f ) {
vec.Set( 0.0f, 0.0f, 1.0f );
} else {
//vec *= (1.0f / sin( angle ));
vec.Normalize();
vec.FixDegenerateNormal();
angle *= 2.0f * idMath::M_RAD2DEG;
}
return idRotation( vec3_origin, vec, angle );
}
/*
=================
idAngles::ToMat3
=================
*/
idMat3 idAngles::ToMat3() const {
idMat3 mat;
float sr, sp, sy, cr, cp, cy;
idMath::SinCos( DEG2RAD( yaw ), sy, cy );
idMath::SinCos( DEG2RAD( pitch ), sp, cp );
idMath::SinCos( DEG2RAD( roll ), sr, cr );
mat[ 0 ].Set( cp * cy, cp * sy, -sp );
mat[ 1 ].Set( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp );
mat[ 2 ].Set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp );
return mat;
}
/*
=================
idAngles::ToMat4
=================
*/
idMat4 idAngles::ToMat4() const {
return ToMat3().ToMat4();
}
/*
=================
idAngles::ToAngularVelocity
=================
*/
idVec3 idAngles::ToAngularVelocity() const {
idRotation rotation = idAngles::ToRotation();
return rotation.GetVec() * DEG2RAD( rotation.GetAngle() );
}
/*
=============
idAngles::ToString
=============
*/
const char *idAngles::ToString( int precision ) const {
return idStr::FloatArrayToString( ToFloatPtr(), GetDimension(), precision );
}

262
neo/idlib/math/Angles.h Normal file
View File

@@ -0,0 +1,262 @@
/*
===========================================================================
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 __MATH_ANGLES_H__
#define __MATH_ANGLES_H__
/*
===============================================================================
Euler angles
===============================================================================
*/
// angle indexes
#define PITCH 0 // up / down
#define YAW 1 // left / right
#define ROLL 2 // fall over
class idVec3;
class idQuat;
class idRotation;
class idMat3;
class idMat4;
class idAngles {
public:
float pitch;
float yaw;
float roll;
idAngles();
idAngles( float pitch, float yaw, float roll );
explicit idAngles( const idVec3 &v );
void Set( float pitch, float yaw, float roll );
idAngles & Zero();
float operator[]( int index ) const;
float & operator[]( int index );
idAngles operator-() const; // negate angles, in general not the inverse rotation
idAngles & operator=( const idAngles &a );
idAngles operator+( const idAngles &a ) const;
idAngles & operator+=( const idAngles &a );
idAngles operator-( const idAngles &a ) const;
idAngles & operator-=( const idAngles &a );
idAngles operator*( const float a ) const;
idAngles & operator*=( const float a );
idAngles operator/( const float a ) const;
idAngles & operator/=( const float a );
friend idAngles operator*( const float a, const idAngles &b );
bool Compare( const idAngles &a ) const; // exact compare, no epsilon
bool Compare( const idAngles &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idAngles &a ) const; // exact compare, no epsilon
bool operator!=( const idAngles &a ) const; // exact compare, no epsilon
idAngles & Normalize360(); // normalizes 'this'
idAngles & Normalize180(); // normalizes 'this'
void Clamp( const idAngles &min, const idAngles &max );
int GetDimension() const;
void ToVectors( idVec3 *forward, idVec3 *right = NULL, idVec3 *up = NULL ) const;
idVec3 ToForward() const;
idQuat ToQuat() const;
idRotation ToRotation() const;
idMat3 ToMat3() const;
idMat4 ToMat4() const;
idVec3 ToAngularVelocity() const;
const float * ToFloatPtr() const;
float * ToFloatPtr();
const char * ToString( int precision = 2 ) const;
};
extern idAngles ang_zero;
ID_INLINE idAngles::idAngles() {
}
ID_INLINE idAngles::idAngles( float pitch, float yaw, float roll ) {
this->pitch = pitch;
this->yaw = yaw;
this->roll = roll;
}
ID_INLINE idAngles::idAngles( const idVec3 &v ) {
this->pitch = v[0];
this->yaw = v[1];
this->roll = v[2];
}
ID_INLINE void idAngles::Set( float pitch, float yaw, float roll ) {
this->pitch = pitch;
this->yaw = yaw;
this->roll = roll;
}
ID_INLINE idAngles &idAngles::Zero() {
pitch = yaw = roll = 0.0f;
return *this;
}
ID_INLINE float idAngles::operator[]( int index ) const {
assert( ( index >= 0 ) && ( index < 3 ) );
return ( &pitch )[ index ];
}
ID_INLINE float &idAngles::operator[]( int index ) {
assert( ( index >= 0 ) && ( index < 3 ) );
return ( &pitch )[ index ];
}
ID_INLINE idAngles idAngles::operator-() const {
return idAngles( -pitch, -yaw, -roll );
}
ID_INLINE idAngles &idAngles::operator=( const idAngles &a ) {
pitch = a.pitch;
yaw = a.yaw;
roll = a.roll;
return *this;
}
ID_INLINE idAngles idAngles::operator+( const idAngles &a ) const {
return idAngles( pitch + a.pitch, yaw + a.yaw, roll + a.roll );
}
ID_INLINE idAngles& idAngles::operator+=( const idAngles &a ) {
pitch += a.pitch;
yaw += a.yaw;
roll += a.roll;
return *this;
}
ID_INLINE idAngles idAngles::operator-( const idAngles &a ) const {
return idAngles( pitch - a.pitch, yaw - a.yaw, roll - a.roll );
}
ID_INLINE idAngles& idAngles::operator-=( const idAngles &a ) {
pitch -= a.pitch;
yaw -= a.yaw;
roll -= a.roll;
return *this;
}
ID_INLINE idAngles idAngles::operator*( const float a ) const {
return idAngles( pitch * a, yaw * a, roll * a );
}
ID_INLINE idAngles& idAngles::operator*=( float a ) {
pitch *= a;
yaw *= a;
roll *= a;
return *this;
}
ID_INLINE idAngles idAngles::operator/( const float a ) const {
float inva = 1.0f / a;
return idAngles( pitch * inva, yaw * inva, roll * inva );
}
ID_INLINE idAngles& idAngles::operator/=( float a ) {
float inva = 1.0f / a;
pitch *= inva;
yaw *= inva;
roll *= inva;
return *this;
}
ID_INLINE idAngles operator*( const float a, const idAngles &b ) {
return idAngles( a * b.pitch, a * b.yaw, a * b.roll );
}
ID_INLINE bool idAngles::Compare( const idAngles &a ) const {
return ( ( a.pitch == pitch ) && ( a.yaw == yaw ) && ( a.roll == roll ) );
}
ID_INLINE bool idAngles::Compare( const idAngles &a, const float epsilon ) const {
if ( idMath::Fabs( pitch - a.pitch ) > epsilon ) {
return false;
}
if ( idMath::Fabs( yaw - a.yaw ) > epsilon ) {
return false;
}
if ( idMath::Fabs( roll - a.roll ) > epsilon ) {
return false;
}
return true;
}
ID_INLINE bool idAngles::operator==( const idAngles &a ) const {
return Compare( a );
}
ID_INLINE bool idAngles::operator!=( const idAngles &a ) const {
return !Compare( a );
}
ID_INLINE void idAngles::Clamp( const idAngles &min, const idAngles &max ) {
if ( pitch < min.pitch ) {
pitch = min.pitch;
} else if ( pitch > max.pitch ) {
pitch = max.pitch;
}
if ( yaw < min.yaw ) {
yaw = min.yaw;
} else if ( yaw > max.yaw ) {
yaw = max.yaw;
}
if ( roll < min.roll ) {
roll = min.roll;
} else if ( roll > max.roll ) {
roll = max.roll;
}
}
ID_INLINE int idAngles::GetDimension() const {
return 3;
}
ID_INLINE const float *idAngles::ToFloatPtr() const {
return &pitch;
}
ID_INLINE float *idAngles::ToFloatPtr() {
return &pitch;
}
#endif /* !__MATH_ANGLES_H__ */

View File

@@ -0,0 +1,41 @@
/*
===========================================================================
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"
idComplex complex_origin( 0.0f, 0.0f );
/*
=============
idComplex::ToString
=============
*/
const char *idComplex::ToString( int precision ) const {
return idStr::FloatArrayToString( ToFloatPtr(), GetDimension(), precision );
}

348
neo/idlib/math/Complex.h Normal file
View File

@@ -0,0 +1,348 @@
/*
===========================================================================
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 __MATH_COMPLEX_H__
#define __MATH_COMPLEX_H__
/*
===============================================================================
Complex number
===============================================================================
*/
class idComplex {
public:
float r; // real part
float i; // imaginary part
idComplex();
idComplex( const float r, const float i );
void Set( const float r, const float i );
void Zero();
float operator[]( int index ) const;
float & operator[]( int index );
idComplex operator-() const;
idComplex & operator=( const idComplex &a );
idComplex operator*( const idComplex &a ) const;
idComplex operator/( const idComplex &a ) const;
idComplex operator+( const idComplex &a ) const;
idComplex operator-( const idComplex &a ) const;
idComplex & operator*=( const idComplex &a );
idComplex & operator/=( const idComplex &a );
idComplex & operator+=( const idComplex &a );
idComplex & operator-=( const idComplex &a );
idComplex operator*( const float a ) const;
idComplex operator/( const float a ) const;
idComplex operator+( const float a ) const;
idComplex operator-( const float a ) const;
idComplex & operator*=( const float a );
idComplex & operator/=( const float a );
idComplex & operator+=( const float a );
idComplex & operator-=( const float a );
friend idComplex operator*( const float a, const idComplex &b );
friend idComplex operator/( const float a, const idComplex &b );
friend idComplex operator+( const float a, const idComplex &b );
friend idComplex operator-( const float a, const idComplex &b );
bool Compare( const idComplex &a ) const; // exact compare, no epsilon
bool Compare( const idComplex &a, const float epsilon ) const; // compare with epsilon
bool operator==( const idComplex &a ) const; // exact compare, no epsilon
bool operator!=( const idComplex &a ) const; // exact compare, no epsilon
idComplex Reciprocal() const;
idComplex Sqrt() const;
float Abs() const;
int GetDimension() const;
const float * ToFloatPtr() const;
float * ToFloatPtr();
const char * ToString( int precision = 2 ) const;
};
extern idComplex complex_origin;
#define complex_zero complex_origin
ID_INLINE idComplex::idComplex() {
}
ID_INLINE idComplex::idComplex( const float r, const float i ) {
this->r = r;
this->i = i;
}
ID_INLINE void idComplex::Set( const float r, const float i ) {
this->r = r;
this->i = i;
}
ID_INLINE void idComplex::Zero() {
r = i = 0.0f;
}
ID_INLINE float idComplex::operator[]( int index ) const {
assert( index >= 0 && index < 2 );
return ( &r )[ index ];
}
ID_INLINE float& idComplex::operator[]( int index ) {
assert( index >= 0 && index < 2 );
return ( &r )[ index ];
}
ID_INLINE idComplex idComplex::operator-() const {
return idComplex( -r, -i );
}
ID_INLINE idComplex &idComplex::operator=( const idComplex &a ) {
r = a.r;
i = a.i;
return *this;
}
ID_INLINE idComplex idComplex::operator*( const idComplex &a ) const {
return idComplex( r * a.r - i * a.i, i * a.r + r * a.i );
}
ID_INLINE idComplex idComplex::operator/( const idComplex &a ) const {
float s, t;
if ( idMath::Fabs( a.r ) >= idMath::Fabs( a.i ) ) {
s = a.i / a.r;
t = 1.0f / ( a.r + s * a.i );
return idComplex( ( r + s * i ) * t, ( i - s * r ) * t );
} else {
s = a.r / a.i;
t = 1.0f / ( s * a.r + a.i );
return idComplex( ( r * s + i ) * t, ( i * s - r ) * t );
}
}
ID_INLINE idComplex idComplex::operator+( const idComplex &a ) const {
return idComplex( r + a.r, i + a.i );
}
ID_INLINE idComplex idComplex::operator-( const idComplex &a ) const {
return idComplex( r - a.r, i - a.i );
}
ID_INLINE idComplex &idComplex::operator*=( const idComplex &a ) {
*this = idComplex( r * a.r - i * a.i, i * a.r + r * a.i );
return *this;
}
ID_INLINE idComplex &idComplex::operator/=( const idComplex &a ) {
float s, t;
if ( idMath::Fabs( a.r ) >= idMath::Fabs( a.i ) ) {
s = a.i / a.r;
t = 1.0f / ( a.r + s * a.i );
*this = idComplex( ( r + s * i ) * t, ( i - s * r ) * t );
} else {
s = a.r / a.i;
t = 1.0f / ( s * a.r + a.i );
*this = idComplex( ( r * s + i ) * t, ( i * s - r ) * t );
}
return *this;
}
ID_INLINE idComplex &idComplex::operator+=( const idComplex &a ) {
r += a.r;
i += a.i;
return *this;
}
ID_INLINE idComplex &idComplex::operator-=( const idComplex &a ) {
r -= a.r;
i -= a.i;
return *this;
}
ID_INLINE idComplex idComplex::operator*( const float a ) const {
return idComplex( r * a, i * a );
}
ID_INLINE idComplex idComplex::operator/( const float a ) const {
float s = 1.0f / a;
return idComplex( r * s, i * s );
}
ID_INLINE idComplex idComplex::operator+( const float a ) const {
return idComplex( r + a, i );
}
ID_INLINE idComplex idComplex::operator-( const float a ) const {
return idComplex( r - a, i );
}
ID_INLINE idComplex &idComplex::operator*=( const float a ) {
r *= a;
i *= a;
return *this;
}
ID_INLINE idComplex &idComplex::operator/=( const float a ) {
float s = 1.0f / a;
r *= s;
i *= s;
return *this;
}
ID_INLINE idComplex &idComplex::operator+=( const float a ) {
r += a;
return *this;
}
ID_INLINE idComplex &idComplex::operator-=( const float a ) {
r -= a;
return *this;
}
ID_INLINE idComplex operator*( const float a, const idComplex &b ) {
return idComplex( a * b.r, a * b.i );
}
ID_INLINE idComplex operator/( const float a, const idComplex &b ) {
float s, t;
if ( idMath::Fabs( b.r ) >= idMath::Fabs( b.i ) ) {
s = b.i / b.r;
t = a / ( b.r + s * b.i );
return idComplex( t, - s * t );
} else {
s = b.r / b.i;
t = a / ( s * b.r + b.i );
return idComplex( s * t, - t );
}
}
ID_INLINE idComplex operator+( const float a, const idComplex &b ) {
return idComplex( a + b.r, b.i );
}
ID_INLINE idComplex operator-( const float a, const idComplex &b ) {
return idComplex( a - b.r, -b.i );
}
ID_INLINE idComplex idComplex::Reciprocal() const {
float s, t;
if ( idMath::Fabs( r ) >= idMath::Fabs( i ) ) {
s = i / r;
t = 1.0f / ( r + s * i );
return idComplex( t, - s * t );
} else {
s = r / i;
t = 1.0f / ( s * r + i );
return idComplex( s * t, - t );
}
}
ID_INLINE idComplex idComplex::Sqrt() const {
float x, y, w;
if ( r == 0.0f && i == 0.0f ) {
return idComplex( 0.0f, 0.0f );
}
x = idMath::Fabs( r );
y = idMath::Fabs( i );
if ( x >= y ) {
w = y / x;
w = idMath::Sqrt( x ) * idMath::Sqrt( 0.5f * ( 1.0f + idMath::Sqrt( 1.0f + w * w ) ) );
} else {
w = x / y;
w = idMath::Sqrt( y ) * idMath::Sqrt( 0.5f * ( w + idMath::Sqrt( 1.0f + w * w ) ) );
}
if ( w == 0.0f ) {
return idComplex( 0.0f, 0.0f );
}
if ( r >= 0.0f ) {
return idComplex( w, 0.5f * i / w );
} else {
return idComplex( 0.5f * y / w, ( i >= 0.0f ) ? w : -w );
}
}
ID_INLINE float idComplex::Abs() const {
float x, y, t;
x = idMath::Fabs( r );
y = idMath::Fabs( i );
if ( x == 0.0f ) {
return y;
} else if ( y == 0.0f ) {
return x;
} else if ( x > y ) {
t = y / x;
return x * idMath::Sqrt( 1.0f + t * t );
} else {
t = x / y;
return y * idMath::Sqrt( 1.0f + t * t );
}
}
ID_INLINE bool idComplex::Compare( const idComplex &a ) const {
return ( ( r == a.r ) && ( i == a.i ) );
}
ID_INLINE bool idComplex::Compare( const idComplex &a, const float epsilon ) const {
if ( idMath::Fabs( r - a.r ) > epsilon ) {
return false;
}
if ( idMath::Fabs( i - a.i ) > epsilon ) {
return false;
}
return true;
}
ID_INLINE bool idComplex::operator==( const idComplex &a ) const {
return Compare( a );
}
ID_INLINE bool idComplex::operator!=( const idComplex &a ) const {
return !Compare( a );
}
ID_INLINE int idComplex::GetDimension() const {
return 2;
}
ID_INLINE const float *idComplex::ToFloatPtr() const {
return &r;
}
ID_INLINE float *idComplex::ToFloatPtr() {
return &r;
}
#endif /* !__MATH_COMPLEX_H__ */

2542
neo/idlib/math/Curve.h Normal file

File diff suppressed because it is too large Load Diff

View 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 __MATH_EXTRAPOLATE_H__
#define __MATH_EXTRAPOLATE_H__
/*
==============================================================================================
Extrapolation
==============================================================================================
*/
typedef enum {
EXTRAPOLATION_NONE = 0x01, // no extrapolation, covered distance = duration * 0.001 * ( baseSpeed )
EXTRAPOLATION_LINEAR = 0x02, // linear extrapolation, covered distance = duration * 0.001 * ( baseSpeed + speed )
EXTRAPOLATION_ACCELLINEAR = 0x04, // linear acceleration, covered distance = duration * 0.001 * ( baseSpeed + 0.5 * speed )
EXTRAPOLATION_DECELLINEAR = 0x08, // linear deceleration, covered distance = duration * 0.001 * ( baseSpeed + 0.5 * speed )
EXTRAPOLATION_ACCELSINE = 0x10, // sinusoidal acceleration, covered distance = duration * 0.001 * ( baseSpeed + sqrt( 0.5 ) * speed )
EXTRAPOLATION_DECELSINE = 0x20, // sinusoidal deceleration, covered distance = duration * 0.001 * ( baseSpeed + sqrt( 0.5 ) * speed )
EXTRAPOLATION_NOSTOP = 0x40 // do not stop at startTime + duration
} extrapolation_t;
template< class type >
class idExtrapolate {
public:
idExtrapolate();
void Init( const int startTime, const int duration, const type &startValue, const type &baseSpeed, const type &speed, const extrapolation_t extrapolationType );
type GetCurrentValue( int time ) const;
type GetCurrentSpeed( int time ) const;
bool IsDone( int time ) const { return ( !( extrapolationType & EXTRAPOLATION_NOSTOP ) && time >= startTime + duration ); }
void SetStartTime( int time ) { startTime = time; }
int GetStartTime() const { return startTime; }
int GetEndTime() const { return ( !( extrapolationType & EXTRAPOLATION_NOSTOP ) && duration > 0 ) ? startTime + duration : 0; }
int GetDuration() const { return duration; }
void SetStartValue( const type &value ) { startValue = value; }
const type & GetStartValue() const { return startValue; }
const type & GetBaseSpeed() const { return baseSpeed; }
const type & GetSpeed() const { return speed; }
extrapolation_t GetExtrapolationType() const { return extrapolationType; }
private:
extrapolation_t extrapolationType;
int startTime;
int duration;
type startValue;
type baseSpeed;
type speed;
};
/*
====================
idExtrapolate::idExtrapolate
====================
*/
template< class type >
ID_INLINE idExtrapolate<type>::idExtrapolate() {
extrapolationType = EXTRAPOLATION_NONE;
startTime = duration = 0.0f;
memset( &startValue, 0, sizeof( startValue ) );
memset( &baseSpeed, 0, sizeof( baseSpeed ) );
memset( &speed, 0, sizeof( speed ) );
}
/*
====================
idExtrapolate::Init
====================
*/
template< class type >
ID_INLINE void idExtrapolate<type>::Init( const int startTime, const int duration, const type &startValue, const type &baseSpeed, const type &speed, const extrapolation_t extrapolationType ) {
this->extrapolationType = extrapolationType;
this->startTime = startTime;
this->duration = duration;
this->startValue = startValue;
this->baseSpeed = baseSpeed;
this->speed = speed;
}
/*
====================
idExtrapolate::GetCurrentValue
====================
*/
template< class type >
ID_INLINE type idExtrapolate<type>::GetCurrentValue( int time ) const {
if ( time < startTime ) {
return startValue;
}
if ( !( extrapolationType & EXTRAPOLATION_NOSTOP ) && ( time > startTime + duration ) ) {
time = startTime + duration;
}
switch ( extrapolationType & ~EXTRAPOLATION_NOSTOP ) {
case EXTRAPOLATION_NONE: {
const float deltaTime = ( time - startTime ) * 0.001f;
return startValue + deltaTime * baseSpeed;
}
case EXTRAPOLATION_LINEAR: {
const float deltaTime = ( time - startTime ) * 0.001f;
return startValue + deltaTime * ( baseSpeed + speed );
}
case EXTRAPOLATION_ACCELLINEAR: {
if ( duration == 0 ) {
return startValue;
} else {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = ( 0.5f * deltaTime * deltaTime ) * ( (float)duration * 0.001f );
return startValue + deltaTime * baseSpeed + s * speed;
}
}
case EXTRAPOLATION_DECELLINEAR: {
if ( duration == 0 ) {
return startValue;
} else {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = ( deltaTime - ( 0.5f * deltaTime * deltaTime ) ) * ( (float)duration * 0.001f );
return startValue + deltaTime * baseSpeed + s * speed;
}
}
case EXTRAPOLATION_ACCELSINE: {
if ( duration == 0 ) {
return startValue;
} else {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = ( 1.0f - idMath::Cos( deltaTime * idMath::HALF_PI ) ) * (float)duration * 0.001f * idMath::SQRT_1OVER2;
return startValue + deltaTime * baseSpeed + s * speed;
}
}
case EXTRAPOLATION_DECELSINE: {
if ( duration == 0 ) {
return startValue;
} else {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = idMath::Sin( deltaTime * idMath::HALF_PI ) * (float)duration * 0.001f * idMath::SQRT_1OVER2;
return startValue + deltaTime * baseSpeed + s * speed;
}
}
}
return startValue;
}
/*
====================
idExtrapolate::GetCurrentSpeed
====================
*/
template< class type >
ID_INLINE type idExtrapolate<type>::GetCurrentSpeed( int time ) const {
if ( time < startTime || duration == 0 ) {
return ( startValue - startValue ); //-V501
}
if ( !( extrapolationType & EXTRAPOLATION_NOSTOP ) && ( time > startTime + duration ) ) {
return ( startValue - startValue ); //-V501
}
switch( extrapolationType & ~EXTRAPOLATION_NOSTOP ) {
case EXTRAPOLATION_NONE: {
return baseSpeed;
}
case EXTRAPOLATION_LINEAR: {
return baseSpeed + speed;
}
case EXTRAPOLATION_ACCELLINEAR: {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = deltaTime;
return baseSpeed + s * speed;
}
case EXTRAPOLATION_DECELLINEAR: {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = 1.0f - deltaTime;
return baseSpeed + s * speed;
}
case EXTRAPOLATION_ACCELSINE: {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = idMath::Sin( deltaTime * idMath::HALF_PI );
return baseSpeed + s * speed;
}
case EXTRAPOLATION_DECELSINE: {
const float deltaTime = ( time - startTime ) / (float)duration;
const float s = idMath::Cos( deltaTime * idMath::HALF_PI );
return baseSpeed + s * speed;
}
default: {
return baseSpeed;
}
}
}
#endif /* !__MATH_EXTRAPOLATE_H__ */

View File

@@ -0,0 +1,400 @@
/*
===========================================================================
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 __MATH_INTERPOLATE_H__
#define __MATH_INTERPOLATE_H__
/*
==============================================================================================
Linear interpolation.
==============================================================================================
*/
template< class type >
class idInterpolate {
public:
idInterpolate();
void Init( const int startTime, const int duration, const type &startValue, const type &endValue );
void SetStartTime( int time ) { this->startTime = time; }
void SetDuration( int duration ) { this->duration = duration; }
void SetStartValue( const type &startValue ) { this->startValue = startValue; }
void SetEndValue( const type &endValue ) { this->endValue = endValue; }
type GetCurrentValue( int time ) const;
bool IsDone( int time ) const { return ( time >= startTime + duration ); }
int GetStartTime() const { return startTime; }
int GetEndTime() const { return startTime + duration; }
int GetDuration() const { return duration; }
const type & GetStartValue() const { return startValue; }
const type & GetEndValue() const { return endValue; }
private:
int startTime;
int duration;
type startValue;
type endValue;
};
/*
====================
idInterpolate::idInterpolate
====================
*/
template< class type >
ID_INLINE idInterpolate<type>::idInterpolate() {
startTime = duration = 0;
memset( &startValue, 0, sizeof( startValue ) );
memset( &endValue, 0, sizeof( endValue ) );
}
/*
====================
idInterpolate::Init
====================
*/
template< class type >
ID_INLINE void idInterpolate<type>::Init( const int startTime, const int duration, const type &startValue, const type &endValue ) {
this->startTime = startTime;
this->duration = duration;
this->startValue = startValue;
this->endValue = endValue;
}
/*
====================
idInterpolate::GetCurrentValue
====================
*/
template< class type >
ID_INLINE type idInterpolate<type>::GetCurrentValue( int time ) const {
if ( time <= startTime ) {
return startValue;
} else if ( time >= startTime + duration ) {
return endValue;
} else {
const float deltaTime = time - startTime;
const float f = deltaTime / (float)duration;
const type range = ( endValue - startValue );
return startValue + ( range * f );
}
}
/*
==============================================================================================
Continuous interpolation with linear acceleration and deceleration phase.
The velocity is continuous but the acceleration is not.
==============================================================================================
*/
template< class type >
class idInterpolateAccelDecelLinear {
public:
idInterpolateAccelDecelLinear();
void Init( const int startTime, const int accelTime, const int decelTime, const int duration, const type &startValue, const type &endValue );
void SetStartTime( int time ) { startTime = time; Invalidate(); }
void SetStartValue( const type &startValue ) { this->startValue = startValue; Invalidate(); }
void SetEndValue( const type &endValue ) { this->endValue = endValue; Invalidate(); }
type GetCurrentValue( int time ) const;
type GetCurrentSpeed( int time ) const;
bool IsDone( int time ) const { return ( time >= startTime + accelTime + linearTime + decelTime ); }
int GetStartTime() const { return startTime; }
int GetEndTime() const { return startTime + accelTime + linearTime + decelTime; }
int GetDuration() const { return accelTime + linearTime + decelTime; }
int GetAcceleration() const { return accelTime; }
int GetDeceleration() const { return decelTime; }
const type & GetStartValue() const { return startValue; }
const type & GetEndValue() const { return endValue; }
private:
int startTime;
int accelTime;
int linearTime;
int decelTime;
type startValue;
type endValue;
mutable idExtrapolate<type> extrapolate;
void Invalidate();
void SetPhase( int time ) const;
};
/*
====================
idInterpolateAccelDecelLinear::idInterpolateAccelDecelLinear
====================
*/
template< class type >
ID_INLINE idInterpolateAccelDecelLinear<type>::idInterpolateAccelDecelLinear() {
startTime = accelTime = linearTime = decelTime = 0;
memset( &startValue, 0, sizeof( startValue ) );
endValue = startValue;
}
/*
====================
idInterpolateAccelDecelLinear::Init
====================
*/
template< class type >
ID_INLINE void idInterpolateAccelDecelLinear<type>::Init( const int startTime, const int accelTime, const int decelTime, const int duration, const type &startValue, const type &endValue ) {
this->startTime = startTime;
this->accelTime = accelTime;
this->decelTime = decelTime;
this->startValue = startValue;
this->endValue = endValue;
if ( duration <= 0 ) {
return;
}
if ( this->accelTime + this->decelTime > duration ) {
this->accelTime = this->accelTime * duration / ( this->accelTime + this->decelTime );
this->decelTime = duration - this->accelTime;
}
this->linearTime = duration - this->accelTime - this->decelTime;
const type speed = ( endValue - startValue ) * ( 1000.0f / ( (float) this->linearTime + ( this->accelTime + this->decelTime ) * 0.5f ) );
if ( this->accelTime ) {
extrapolate.Init( startTime, this->accelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_ACCELLINEAR ); //-V501
} else if ( this->linearTime ) {
extrapolate.Init( startTime, this->linearTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_LINEAR ); //-V501
} else {
extrapolate.Init( startTime, this->decelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_DECELLINEAR ); //-V501
}
}
/*
====================
idInterpolateAccelDecelLinear::Invalidate
====================
*/
template< class type >
ID_INLINE void idInterpolateAccelDecelLinear<type>::Invalidate() {
extrapolate.Init( 0, 0, extrapolate.GetStartValue(), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_NONE );
}
/*
====================
idInterpolateAccelDecelLinear::SetPhase
====================
*/
template< class type >
ID_INLINE void idInterpolateAccelDecelLinear<type>::SetPhase( int time ) const {
const float deltaTime = time - startTime;
if ( deltaTime < accelTime ) {
if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_ACCELLINEAR ) {
extrapolate.Init( startTime, accelTime, startValue, extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_ACCELLINEAR );
}
} else if ( deltaTime < accelTime + linearTime ) {
if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_LINEAR ) {
extrapolate.Init( startTime + accelTime, linearTime, startValue + extrapolate.GetSpeed() * ( accelTime * 0.001f * 0.5f ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_LINEAR );
}
} else {
if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_DECELLINEAR ) {
extrapolate.Init( startTime + accelTime + linearTime, decelTime, endValue - ( extrapolate.GetSpeed() * ( decelTime * 0.001f * 0.5f ) ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_DECELLINEAR );
}
}
}
/*
====================
idInterpolateAccelDecelLinear::GetCurrentValue
====================
*/
template< class type >
ID_INLINE type idInterpolateAccelDecelLinear<type>::GetCurrentValue( int time ) const {
SetPhase( time );
return extrapolate.GetCurrentValue( time );
}
/*
====================
idInterpolateAccelDecelLinear::GetCurrentSpeed
====================
*/
template< class type >
ID_INLINE type idInterpolateAccelDecelLinear<type>::GetCurrentSpeed( int time ) const {
SetPhase( time );
return extrapolate.GetCurrentSpeed( time );
}
/*
==============================================================================================
Continuous interpolation with sinusoidal acceleration and deceleration phase.
Both the velocity and acceleration are continuous.
==============================================================================================
*/
template< class type >
class idInterpolateAccelDecelSine {
public:
idInterpolateAccelDecelSine();
void Init( const int startTime, const int accelTime, const int decelTime, const int duration, const type &startValue, const type &endValue );
void SetStartTime( int time ) { startTime = time; Invalidate(); }
void SetStartValue( const type &startValue ) { this->startValue = startValue; Invalidate(); }
void SetEndValue( const type &endValue ) { this->endValue = endValue; Invalidate(); }
type GetCurrentValue( int time ) const;
type GetCurrentSpeed( int time ) const;
bool IsDone( int time ) const { return ( time >= startTime + accelTime + linearTime + decelTime ); }
int GetStartTime() const { return startTime; }
int GetEndTime() const { return startTime + accelTime + linearTime + decelTime; }
int GetDuration() const { return accelTime + linearTime + decelTime; }
int GetAcceleration() const { return accelTime; }
int GetDeceleration() const { return decelTime; }
const type & GetStartValue() const { return startValue; }
const type & GetEndValue() const { return endValue; }
private:
int startTime;
int accelTime;
int linearTime;
int decelTime;
type startValue;
type endValue;
mutable idExtrapolate<type> extrapolate;
void Invalidate();
void SetPhase( int time ) const;
};
/*
====================
idInterpolateAccelDecelSine::idInterpolateAccelDecelSine
====================
*/
template< class type >
ID_INLINE idInterpolateAccelDecelSine<type>::idInterpolateAccelDecelSine() {
startTime = accelTime = linearTime = decelTime = 0;
memset( &startValue, 0, sizeof( startValue ) );
memset( &endValue, 0, sizeof( endValue ) );
}
/*
====================
idInterpolateAccelDecelSine::Init
====================
*/
template< class type >
ID_INLINE void idInterpolateAccelDecelSine<type>::Init( const int startTime, const int accelTime, const int decelTime, const int duration, const type &startValue, const type &endValue ) {
this->startTime = startTime;
this->accelTime = accelTime;
this->decelTime = decelTime;
this->startValue = startValue;
this->endValue = endValue;
if ( duration <= 0 ) {
return;
}
if ( this->accelTime + this->decelTime > duration ) {
this->accelTime = this->accelTime * duration / ( this->accelTime + this->decelTime );
this->decelTime = duration - this->accelTime;
}
this->linearTime = duration - this->accelTime - this->decelTime;
const type speed = ( endValue - startValue ) * ( 1000.0f / ( (float) this->linearTime + ( this->accelTime + this->decelTime ) * idMath::SQRT_1OVER2 ) );
if ( this->accelTime ) {
extrapolate.Init( startTime, this->accelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_ACCELSINE ); //-V501
} else if ( this->linearTime ) {
extrapolate.Init( startTime, this->linearTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_LINEAR ); //-V501
} else {
extrapolate.Init( startTime, this->decelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_DECELSINE ); //-V501
}
}
/*
====================
idInterpolateAccelDecelSine::Invalidate
====================
*/
template< class type >
ID_INLINE void idInterpolateAccelDecelSine<type>::Invalidate() {
extrapolate.Init( 0, 0, extrapolate.GetStartValue(), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_NONE );
}
/*
====================
idInterpolateAccelDecelSine::SetPhase
====================
*/
template< class type >
ID_INLINE void idInterpolateAccelDecelSine<type>::SetPhase( int time ) const {
const float deltaTime = time - startTime;
if ( deltaTime < accelTime ) {
if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_ACCELSINE ) {
extrapolate.Init( startTime, accelTime, startValue, extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_ACCELSINE );
}
} else if ( deltaTime < accelTime + linearTime ) {
if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_LINEAR ) {
extrapolate.Init( startTime + accelTime, linearTime, startValue + extrapolate.GetSpeed() * ( accelTime * 0.001f * idMath::SQRT_1OVER2 ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_LINEAR );
}
} else {
if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_DECELSINE ) {
extrapolate.Init( startTime + accelTime + linearTime, decelTime, endValue - ( extrapolate.GetSpeed() * ( decelTime * 0.001f * idMath::SQRT_1OVER2 ) ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_DECELSINE );
}
}
}
/*
====================
idInterpolateAccelDecelSine::GetCurrentValue
====================
*/
template< class type >
ID_INLINE type idInterpolateAccelDecelSine<type>::GetCurrentValue( int time ) const {
SetPhase( time );
return extrapolate.GetCurrentValue( time );
}
/*
====================
idInterpolateAccelDecelSine::GetCurrentSpeed
====================
*/
template< class type >
ID_INLINE type idInterpolateAccelDecelSine<type>::GetCurrentSpeed( int time ) const {
SetPhase( time );
return extrapolate.GetCurrentSpeed( time );
}
#endif /* !__MATH_INTERPOLATE_H__ */

2949
neo/idlib/math/Lcp.cpp Normal file

File diff suppressed because it is too large Load Diff

79
neo/idlib/math/Lcp.h Normal file
View File

@@ -0,0 +1,79 @@
/*
===========================================================================
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 __MATH_LCP_H__
#define __MATH_LCP_H__
/*
================================================
The *LCP* class, idLCP, is a Box-Constrained Mixed Linear Complementarity Problem solver.
'A' is a matrix of dimension n*n and 'x', 'b', 'lo', 'hi' are vectors of dimension n.
Solve: Ax = b + t, where t is a vector of dimension n, with complementarity condition:
(x[i] - lo[i]) * (x[i] - hi[i]) * t[i] = 0
such that for each 0 <= i < n one of the following holds:
lo[i] < x[i] < hi[i], t[i] == 0
x[i] == lo[i], t[i] >= 0
x[i] == hi[i], t[i] <= 0
Partly-bounded or unbounded variables can have lo[i] and/or hi[i] set to negative/positive
idMath::INFITITY, respectively.
If boxIndex != NULL and boxIndex[i] != -1, then
lo[i] = - fabs( lo[i] * x[boxIndex[i]] )
hi[i] = fabs( hi[i] * x[boxIndex[i]] )
boxIndex[boxIndex[i]] must be -1
Before calculating any of the bounded x[i] with boxIndex[i] != -1, the solver calculates all
unbounded x[i] and all x[i] with boxIndex[i] == -1.
================================================
*/
class idLCP {
public:
static idLCP * AllocSquare(); // 'A' must be a square matrix
static idLCP * AllocSymmetric(); // 'A' must be a symmetric matrix
virtual ~idLCP();
virtual bool Solve( const idMatX &A, idVecX &x, const idVecX &b, const idVecX &lo,
const idVecX &hi, const int *boxIndex = NULL ) = 0;
virtual void SetMaxIterations( int max );
virtual int GetMaxIterations();
static void Test_f( const idCmdArgs &args );
protected:
int maxIterations;
};
#endif // !__MATH_LCP_H__

5350
neo/idlib/math/MatX.cpp Normal file

File diff suppressed because it is too large Load Diff

1571
neo/idlib/math/MatX.h Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More