mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2026-03-20 17:11:16 +01:00
Initial commit
This commit is contained in:
233
neo/idlib/Base64.cpp
Normal file
233
neo/idlib/Base64.cpp
Normal 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
111
neo/idlib/Base64.h
Normal 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
511
neo/idlib/BitMsg.cpp
Normal 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
958
neo/idlib/BitMsg.h
Normal 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
173
neo/idlib/Callback.h
Normal 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
202
neo/idlib/CmdArgs.cpp
Normal 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
73
neo/idlib/CmdArgs.h
Normal 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
59
neo/idlib/CommandLink.cpp
Normal 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
83
neo/idlib/DataQueue.h
Normal 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
943
neo/idlib/Dict.cpp
Normal 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
348
neo/idlib/Dict.h
Normal 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
86
neo/idlib/Heap.cpp
Normal 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
1079
neo/idlib/Heap.h
Normal file
File diff suppressed because it is too large
Load Diff
600
neo/idlib/LangDict.cpp
Normal file
600
neo/idlib/LangDict.cpp
Normal 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
150
neo/idlib/LangDict.h
Normal 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
1918
neo/idlib/Lexer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
311
neo/idlib/Lexer.h
Normal file
311
neo/idlib/Lexer.h
Normal 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
608
neo/idlib/Lib.cpp
Normal 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
322
neo/idlib/Lib.h
Normal 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
972
neo/idlib/MapFile.cpp
Normal 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
237
neo/idlib/MapFile.h
Normal 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__ */
|
||||
1297
neo/idlib/ParallelJobList.cpp
Normal file
1297
neo/idlib/ParallelJobList.cpp
Normal file
File diff suppressed because it is too large
Load Diff
177
neo/idlib/ParallelJobList.h
Normal file
177
neo/idlib/ParallelJobList.h
Normal 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__
|
||||
67
neo/idlib/ParallelJobList_JobHeaders.h
Normal file
67
neo/idlib/ParallelJobList_JobHeaders.h
Normal 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
3288
neo/idlib/Parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
284
neo/idlib/Parser.h
Normal file
284
neo/idlib/Parser.h
Normal 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
171
neo/idlib/RectAllocator.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
47
neo/idlib/SoftwareCache.cpp
Normal file
47
neo/idlib/SoftwareCache.cpp
Normal 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
513
neo/idlib/SoftwareCache.h
Normal 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
2090
neo/idlib/Str.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1215
neo/idlib/Str.h
Normal file
1215
neo/idlib/Str.h
Normal file
File diff suppressed because it is too large
Load Diff
125
neo/idlib/StrStatic.h
Normal file
125
neo/idlib/StrStatic.h
Normal 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
223
neo/idlib/Swap.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#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
283
neo/idlib/Thread.cpp
Normal 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
465
neo/idlib/Thread.h
Normal 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
160
neo/idlib/Timer.cpp
Normal 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
223
neo/idlib/Timer.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#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
179
neo/idlib/Token.cpp
Normal 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
165
neo/idlib/Token.h
Normal 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
425
neo/idlib/bv/Bounds.cpp
Normal 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 ¢er ) 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
428
neo/idlib/bv/Bounds.h
Normal 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 ¢er ) 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
849
neo/idlib/bv/Box.cpp
Normal 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
297
neo/idlib/bv/Box.h
Normal 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 ¢er, 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 ¢er, 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
155
neo/idlib/bv/Sphere.cpp
Normal 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
275
neo/idlib/bv/Sphere.h
Normal 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__ */
|
||||
115
neo/idlib/containers/Array.h
Normal file
115
neo/idlib/containers/Array.h
Normal 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__
|
||||
573
neo/idlib/containers/BTree.h
Normal file
573
neo/idlib/containers/BTree.h
Normal 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__ */
|
||||
138
neo/idlib/containers/BinSearch.h
Normal file
138
neo/idlib/containers/BinSearch.h
Normal 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__ */
|
||||
155
neo/idlib/containers/HashIndex.cpp
Normal file
155
neo/idlib/containers/HashIndex.cpp
Normal 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);
|
||||
}
|
||||
422
neo/idlib/containers/HashIndex.h
Normal file
422
neo/idlib/containers/HashIndex.h
Normal 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__ */
|
||||
897
neo/idlib/containers/HashTable.h
Normal file
897
neo/idlib/containers/HashTable.h
Normal 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__ */
|
||||
362
neo/idlib/containers/Hierarchy.h
Normal file
362
neo/idlib/containers/Hierarchy.h
Normal 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__ */
|
||||
343
neo/idlib/containers/LinkList.h
Normal file
343
neo/idlib/containers/LinkList.h
Normal 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
1037
neo/idlib/containers/List.h
Normal file
File diff suppressed because it is too large
Load Diff
81
neo/idlib/containers/PlaneSet.h
Normal file
81
neo/idlib/containers/PlaneSet.h
Normal 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__ */
|
||||
211
neo/idlib/containers/Queue.h
Normal file
211
neo/idlib/containers/Queue.h
Normal 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
338
neo/idlib/containers/Sort.h
Normal 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__
|
||||
86
neo/idlib/containers/Stack.h
Normal file
86
neo/idlib/containers/Stack.h
Normal 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__ */
|
||||
656
neo/idlib/containers/StaticList.h
Normal file
656
neo/idlib/containers/StaticList.h
Normal 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__ */
|
||||
204
neo/idlib/containers/StrList.h
Normal file
204
neo/idlib/containers/StrList.h
Normal 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__ */
|
||||
228
neo/idlib/containers/StrPool.h
Normal file
228
neo/idlib/containers/StrPool.h
Normal 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__ */
|
||||
270
neo/idlib/containers/VectorSet.h
Normal file
270
neo/idlib/containers/VectorSet.h
Normal 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__ */
|
||||
76
neo/idlib/geometry/DrawVert.cpp
Normal file
76
neo/idlib/geometry/DrawVert.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
============
|
||||
idShadowVert::CreateShadowCache
|
||||
============
|
||||
*/
|
||||
int idShadowVert::CreateShadowCache( idShadowVert * vertexCache, const idDrawVert *verts, const int numVerts ) {
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
vertexCache[i*2+0].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[i*2+0].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[i*2+0].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[i*2+0].xyzw[3] = 1.0f;
|
||||
|
||||
vertexCache[i*2+1].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[i*2+1].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[i*2+1].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[i*2+1].xyzw[3] = 0.0f;
|
||||
}
|
||||
return numVerts * 2;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
idShadowVertSkinned::CreateShadowCache
|
||||
===================
|
||||
*/
|
||||
int idShadowVertSkinned::CreateShadowCache( idShadowVertSkinned * vertexCache, const idDrawVert *verts, const int numVerts ) {
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
vertexCache[0].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[0].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[0].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[0].xyzw[3] = 1.0f;
|
||||
*(unsigned int *)vertexCache[0].color = *(unsigned int *)verts[i].color;
|
||||
*(unsigned int *)vertexCache[0].color2 = *(unsigned int *)verts[i].color2;
|
||||
|
||||
vertexCache[1].xyzw[0] = verts[i].xyz[0];
|
||||
vertexCache[1].xyzw[1] = verts[i].xyz[1];
|
||||
vertexCache[1].xyzw[2] = verts[i].xyz[2];
|
||||
vertexCache[1].xyzw[3] = 0.0f;
|
||||
*(unsigned int *)vertexCache[1].color = *(unsigned int *)verts[i].color;
|
||||
*(unsigned int *)vertexCache[1].color2 = *(unsigned int *)verts[i].color2;
|
||||
|
||||
vertexCache += 2;
|
||||
}
|
||||
return numVerts * 2;
|
||||
}
|
||||
739
neo/idlib/geometry/DrawVert.h
Normal file
739
neo/idlib/geometry/DrawVert.h
Normal file
@@ -0,0 +1,739 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DRAWVERT_H__
|
||||
#define __DRAWVERT_H__
|
||||
|
||||
// The hardware converts a byte to a float by division with 255 and in the
|
||||
// vertex programs we convert the floating-point value in the range [0, 1]
|
||||
// to the range [-1, 1] by multiplying with 2 and subtracting 1.
|
||||
#define VERTEX_BYTE_TO_FLOAT( x ) ( (x) * ( 2.0f / 255.0f ) - 1.0f )
|
||||
#define VERTEX_FLOAT_TO_BYTE( x ) idMath::Ftob( ( (x) + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f )
|
||||
|
||||
// The hardware converts a byte to a float by division with 255 and in the
|
||||
// fragment programs we convert the floating-point value in the range [0, 1]
|
||||
// to the range [-1, 1] by multiplying with 2 and subtracting 1.
|
||||
// This is the conventional OpenGL mapping which specifies an exact
|
||||
// representation for -1 and +1 but not 0. The DirectX 10 mapping is
|
||||
// in the comments which specifies a non-linear mapping with an exact
|
||||
// representation of -1, 0 and +1 but -1 is represented twice.
|
||||
#define NORMALMAP_BYTE_TO_FLOAT( x ) VERTEX_BYTE_TO_FLOAT( x ) //( (x) - 128.0f ) * ( 1.0f / 127.0f )
|
||||
#define NORMALMAP_FLOAT_TO_BYTE( x ) VERTEX_FLOAT_TO_BYTE( x ) //idMath::Ftob( 128.0f + 127.0f * (x) + 0.5f )
|
||||
|
||||
/*
|
||||
================================================
|
||||
halfFloat_t
|
||||
================================================
|
||||
*/
|
||||
typedef unsigned short halfFloat_t;
|
||||
|
||||
// GPU half-float bit patterns
|
||||
#define HF_MANTISSA(x) (x&1023)
|
||||
#define HF_EXP(x) ((x&32767)>>10)
|
||||
#define HF_SIGN(x) ((x&32768)?-1:1)
|
||||
|
||||
/*
|
||||
========================
|
||||
F16toF32
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float F16toF32( halfFloat_t x ) {
|
||||
int e = HF_EXP( x );
|
||||
int m = HF_MANTISSA( x );
|
||||
int s = HF_SIGN( x );
|
||||
|
||||
if ( 0 < e && e < 31 ) {
|
||||
return s * powf( 2.0f, ( e - 15.0f ) ) * ( 1 + m / 1024.0f );
|
||||
} else if ( m == 0 ) {
|
||||
return s * 0.0f;
|
||||
}
|
||||
return s * powf( 2.0f, -14.0f ) * ( m / 1024.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
F32toF16
|
||||
========================
|
||||
*/
|
||||
ID_INLINE halfFloat_t F32toF16( float a ) {
|
||||
unsigned int f = *(unsigned *)( &a );
|
||||
unsigned int signbit = ( f & 0x80000000 ) >> 16;
|
||||
int exponent = ( ( f & 0x7F800000 ) >> 23 ) - 112;
|
||||
unsigned int mantissa = ( f & 0x007FFFFF );
|
||||
|
||||
if ( exponent <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
if ( exponent > 30 ) {
|
||||
return (halfFloat_t)( signbit | 0x7BFF );
|
||||
}
|
||||
|
||||
return (halfFloat_t)( signbit | ( exponent << 10 ) | ( mantissa >> 13 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Draw Vertex.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idDrawVert {
|
||||
public:
|
||||
idVec3 xyz; // 12 bytes
|
||||
halfFloat_t st[2]; // 4 bytes
|
||||
byte normal[4]; // 4 bytes
|
||||
byte tangent[4]; // 4 bytes -- [3] is texture polarity sign
|
||||
byte color[4]; // 4 bytes
|
||||
byte color2[4]; // 4 bytes -- weights for skinning
|
||||
|
||||
float operator[]( const int index ) const;
|
||||
float & operator[]( const int index );
|
||||
|
||||
void Clear();
|
||||
|
||||
const idVec3 GetNormal() const;
|
||||
const idVec3 GetNormalRaw() const; // not re-normalized for renderbump
|
||||
|
||||
// must be normalized already!
|
||||
void SetNormal( float x, float y, float z );
|
||||
void SetNormal( const idVec3 & n );
|
||||
|
||||
const idVec3 GetTangent() const;
|
||||
const idVec3 GetTangentRaw() const; // not re-normalized for renderbump
|
||||
|
||||
// must be normalized already!
|
||||
void SetTangent( float x, float y, float z );
|
||||
void SetTangent( const idVec3 & t );
|
||||
|
||||
// derived from normal, tangent, and tangent flag
|
||||
const idVec3 GetBiTangent() const;
|
||||
const idVec3 GetBiTangentRaw() const; // not re-normalized for renderbump
|
||||
|
||||
void SetBiTangent( float x, float y, float z );
|
||||
ID_INLINE void SetBiTangent( const idVec3 & t );
|
||||
|
||||
float GetBiTangentSign() const;
|
||||
byte GetBiTangentSignBit() const;
|
||||
|
||||
void SetTexCoordNative( const halfFloat_t s, const halfFloat_t t );
|
||||
void SetTexCoord( const idVec2 & st );
|
||||
void SetTexCoord( float s, float t );
|
||||
void SetTexCoordS( float s );
|
||||
void SetTexCoordT( float t );
|
||||
const idVec2 GetTexCoord() const;
|
||||
const halfFloat_t GetTexCoordNativeS() const;
|
||||
const halfFloat_t GetTexCoordNativeT() const;
|
||||
|
||||
// either 1.0f or -1.0f
|
||||
ID_INLINE void SetBiTangentSign( float sign );
|
||||
ID_INLINE void SetBiTangentSignBit( byte bit );
|
||||
|
||||
void Lerp( const idDrawVert &a, const idDrawVert &b, const float f );
|
||||
void LerpAll( const idDrawVert &a, const idDrawVert &b, const float f );
|
||||
|
||||
void SetColor( dword color );
|
||||
void SetNativeOrderColor( dword color );
|
||||
dword GetColor() const;
|
||||
|
||||
void SetColor2( dword color );
|
||||
void SetNativeOrderColor2( dword color );
|
||||
void ClearColor2();
|
||||
dword GetColor2() const;
|
||||
|
||||
static idDrawVert GetSkinnedDrawVert( const idDrawVert & vert, const idJointMat * joints );
|
||||
static idVec3 GetSkinnedDrawVertPosition( const idDrawVert & vert, const idJointMat * joints );
|
||||
};
|
||||
|
||||
#define DRAWVERT_SIZE 32
|
||||
#define DRAWVERT_XYZ_OFFSET (0*4)
|
||||
#define DRAWVERT_ST_OFFSET (3*4)
|
||||
#define DRAWVERT_NORMAL_OFFSET (4*4)
|
||||
#define DRAWVERT_TANGENT_OFFSET (5*4)
|
||||
#define DRAWVERT_COLOR_OFFSET (6*4)
|
||||
#define DRAWVERT_COLOR2_OFFSET (7*4)
|
||||
|
||||
assert_offsetof( idDrawVert, xyz, DRAWVERT_XYZ_OFFSET );
|
||||
assert_offsetof( idDrawVert, normal, DRAWVERT_NORMAL_OFFSET );
|
||||
assert_offsetof( idDrawVert, tangent, DRAWVERT_TANGENT_OFFSET );
|
||||
|
||||
/*
|
||||
========================
|
||||
VertexFloatToByte
|
||||
|
||||
Assumes input is in the range [-1, 1]
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void VertexFloatToByte( const float & x, const float & y, const float & z, byte * bval ) {
|
||||
assert_4_byte_aligned( bval ); // for __stvebx
|
||||
|
||||
|
||||
const __m128 vector_float_one = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const __m128 vector_float_half = { 0.5f, 0.5f, 0.5f, 0.5f };
|
||||
const __m128 vector_float_255_over_2 = { 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f };
|
||||
|
||||
const __m128 xyz = _mm_unpacklo_ps( _mm_unpacklo_ps( _mm_load_ss( &x ), _mm_load_ss( &z ) ), _mm_load_ss( &y ) );
|
||||
const __m128 xyzScaled = _mm_madd_ps( _mm_add_ps( xyz, vector_float_one ), vector_float_255_over_2, vector_float_half );
|
||||
const __m128i xyzInt = _mm_cvtps_epi32( xyzScaled );
|
||||
const __m128i xyzShort = _mm_packs_epi32( xyzInt, xyzInt );
|
||||
const __m128i xyzChar = _mm_packus_epi16( xyzShort, xyzShort );
|
||||
const __m128i xyz16 = _mm_unpacklo_epi8( xyzChar, _mm_setzero_si128() );
|
||||
|
||||
bval[0] = (byte)_mm_extract_epi16( xyz16, 0 ); // cannot use _mm_extract_epi8 because it is an SSE4 instruction
|
||||
bval[1] = (byte)_mm_extract_epi16( xyz16, 1 );
|
||||
bval[2] = (byte)_mm_extract_epi16( xyz16, 2 );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::operator[]
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float idDrawVert::operator[]( const int index ) const {
|
||||
assert( index >= 0 && index < 5 );
|
||||
return ((float *)(&xyz))[index];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::operator[]
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float &idDrawVert::operator[]( const int index ) {
|
||||
assert( index >= 0 && index < 5 );
|
||||
return ((float *)(&xyz))[index];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::Clear
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::Clear() {
|
||||
*reinterpret_cast<dword *>(&this->xyz.x) = 0;
|
||||
*reinterpret_cast<dword *>(&this->xyz.y) = 0;
|
||||
*reinterpret_cast<dword *>(&this->xyz.z) = 0;
|
||||
*reinterpret_cast<dword *>(this->st) = 0;
|
||||
*reinterpret_cast<dword *>(this->normal) = 0x00FF8080; // x=0, y=0, z=1
|
||||
*reinterpret_cast<dword *>(this->tangent) = 0xFF8080FF; // x=1, y=0, z=0
|
||||
*reinterpret_cast<dword *>(this->color) = 0;
|
||||
*reinterpret_cast<dword *>(this->color2) = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetNormal
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetNormal() const {
|
||||
idVec3 n( VERTEX_BYTE_TO_FLOAT( normal[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[2] ) );
|
||||
n.Normalize(); // after the normal has been compressed & uncompressed, it may not be normalized anymore
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetNormalRaw
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetNormalRaw() const {
|
||||
idVec3 n( VERTEX_BYTE_TO_FLOAT( normal[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( normal[2] ) );
|
||||
// don't re-normalize just like we do in the vertex programs
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNormal
|
||||
must be normalized already!
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNormal( const idVec3 & n ) {
|
||||
VertexFloatToByte( n.x, n.y, n.z, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNormal
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNormal( float x, float y, float z ) {
|
||||
VertexFloatToByte( x, y, z, normal );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
&idDrawVert::GetTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetTangent() const {
|
||||
idVec3 t( VERTEX_BYTE_TO_FLOAT( tangent[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[2] ) );
|
||||
t.Normalize();
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
&idDrawVert::GetTangentRaw
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetTangentRaw() const {
|
||||
idVec3 t( VERTEX_BYTE_TO_FLOAT( tangent[0] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[1] ),
|
||||
VERTEX_BYTE_TO_FLOAT( tangent[2] ) );
|
||||
// don't re-normalize just like we do in the vertex programs
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTangent( float x, float y, float z ) {
|
||||
VertexFloatToByte( x, y, z, tangent );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTangent( const idVec3 & t ) {
|
||||
VertexFloatToByte( t.x, t.y, t.z, tangent );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetBiTangent() const {
|
||||
// derive from the normal, tangent, and bitangent direction flag
|
||||
idVec3 bitangent;
|
||||
bitangent.Cross( GetNormal(), GetTangent() );
|
||||
bitangent *= GetBiTangentSign();
|
||||
return bitangent;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangentRaw
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec3 idDrawVert::GetBiTangentRaw() const {
|
||||
// derive from the normal, tangent, and bitangent direction flag
|
||||
// don't re-normalize just like we do in the vertex programs
|
||||
idVec3 bitangent;
|
||||
bitangent.Cross( GetNormalRaw(), GetTangentRaw() );
|
||||
bitangent *= GetBiTangentSign();
|
||||
return bitangent;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangent( float x, float y, float z ) {
|
||||
SetBiTangent( idVec3( x, y, z ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangent
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangent( const idVec3 &t ) {
|
||||
idVec3 bitangent;
|
||||
bitangent.Cross( GetNormal(), GetTangent() );
|
||||
SetBiTangentSign( bitangent * t );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangentSign
|
||||
========================
|
||||
*/
|
||||
ID_INLINE float idDrawVert::GetBiTangentSign() const {
|
||||
return ( tangent[3] < 128 ) ? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetBiTangentSignBit
|
||||
========================
|
||||
*/
|
||||
ID_INLINE byte idDrawVert::GetBiTangentSignBit() const {
|
||||
return ( tangent[3] < 128 ) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangentSign
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangentSign( float sign ) {
|
||||
tangent[3] = ( sign < 0.0f ) ? 0 : 255;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetBiTangentSignBit
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetBiTangentSignBit( byte sign ) {
|
||||
tangent[3] = sign ? 0 : 255;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::Lerp
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::Lerp( const idDrawVert &a, const idDrawVert &b, const float f ) {
|
||||
xyz = a.xyz + f * ( b.xyz - a.xyz );
|
||||
SetTexCoord( ::Lerp( a.GetTexCoord(), b.GetTexCoord(), f ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::LerpAll
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::LerpAll( const idDrawVert &a, const idDrawVert &b, const float f ) {
|
||||
xyz = ::Lerp( a.xyz, b.xyz, f );
|
||||
SetTexCoord( ::Lerp( a.GetTexCoord(), b.GetTexCoord(), f ) );
|
||||
|
||||
idVec3 normal = ::Lerp( a.GetNormal(), b.GetNormal(), f );
|
||||
idVec3 tangent = ::Lerp( a.GetTangent(), b.GetTangent(), f );
|
||||
idVec3 bitangent = ::Lerp( a.GetBiTangent(), b.GetBiTangent(), f );
|
||||
normal.Normalize();
|
||||
tangent.Normalize();
|
||||
bitangent.Normalize();
|
||||
SetNormal( normal );
|
||||
SetTangent( tangent );
|
||||
SetBiTangent( bitangent );
|
||||
|
||||
color[0] = (byte)( a.color[0] + f * ( b.color[0] - a.color[0] ) );
|
||||
color[1] = (byte)( a.color[1] + f * ( b.color[1] - a.color[1] ) );
|
||||
color[2] = (byte)( a.color[2] + f * ( b.color[2] - a.color[2] ) );
|
||||
color[3] = (byte)( a.color[3] + f * ( b.color[3] - a.color[3] ) );
|
||||
|
||||
color2[0] = (byte)( a.color2[0] + f * ( b.color2[0] - a.color2[0] ) );
|
||||
color2[1] = (byte)( a.color2[1] + f * ( b.color2[1] - a.color2[1] ) );
|
||||
color2[2] = (byte)( a.color2[2] + f * ( b.color2[2] - a.color2[2] ) );
|
||||
color2[3] = (byte)( a.color2[3] + f * ( b.color2[3] - a.color2[3] ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNativeOrderColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNativeOrderColor( dword color ) {
|
||||
*reinterpret_cast<dword *>(this->color) = color;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetColor( dword color ) {
|
||||
*reinterpret_cast<dword *>(this->color) = color;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE dword idDrawVert::GetColor() const {
|
||||
return *reinterpret_cast<const dword *>(this->color);
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoordNative
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoordNative( const halfFloat_t s, const halfFloat_t t ) {
|
||||
st[0] = s;
|
||||
st[1] = t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoord
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoord( const idVec2 & st ) {
|
||||
SetTexCoordS( st.x );
|
||||
SetTexCoordT( st.y );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoord
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoord( float s, float t ) {
|
||||
SetTexCoordS( s );
|
||||
SetTexCoordT( t );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoordS
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoordS( float s ) {
|
||||
st[0] = F32toF16( s );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetTexCoordT
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetTexCoordT( float t ) {
|
||||
st[1] = F32toF16( t );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoord
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const idVec2 idDrawVert::GetTexCoord() const {
|
||||
return idVec2( F16toF32( st[0] ), F16toF32( st[1] ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordNativeS
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const halfFloat_t idDrawVert::GetTexCoordNativeS() const {
|
||||
return st[0];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordNativeT
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const halfFloat_t idDrawVert::GetTexCoordNativeT() const {
|
||||
return st[1];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetNativeOrderColor2
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetNativeOrderColor2( dword color2 ) {
|
||||
*reinterpret_cast<dword *>(this->color2) = color2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::SetColor
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::SetColor2( dword color2 ) {
|
||||
*reinterpret_cast<dword *>(this->color2) = color2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::ClearColor2
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idDrawVert::ClearColor2() {
|
||||
*reinterpret_cast<dword *>(this->color2) = 0x80808080;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetColor2
|
||||
========================
|
||||
*/
|
||||
ID_INLINE dword idDrawVert::GetColor2() const {
|
||||
return *reinterpret_cast<const dword *>(this->color2);
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
WriteDrawVerts16
|
||||
|
||||
Use 16-byte in-order SIMD writes because the destVerts may live in write-combined memory
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void WriteDrawVerts16( idDrawVert * destVerts, const idDrawVert * localVerts, int numVerts ) {
|
||||
assert_sizeof( idDrawVert, 32 );
|
||||
assert_16_byte_aligned( destVerts );
|
||||
assert_16_byte_aligned( localVerts );
|
||||
|
||||
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
__m128i v0 = _mm_load_si128( (const __m128i *)( (byte *)( localVerts + i ) + 0 ) );
|
||||
__m128i v1 = _mm_load_si128( (const __m128i *)( (byte *)( localVerts + i ) + 16 ) );
|
||||
_mm_stream_si128( (__m128i *)( (byte *)( destVerts + i ) + 0 ), v0 );
|
||||
_mm_stream_si128( (__m128i *)( (byte *)( destVerts + i ) + 16 ), v1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idDrawVert::GetSkinnedDrawVert
|
||||
=====================
|
||||
*/
|
||||
ID_INLINE idDrawVert idDrawVert::GetSkinnedDrawVert( const idDrawVert & vert, const idJointMat * joints ) {
|
||||
if ( joints == NULL ) {
|
||||
return vert;
|
||||
}
|
||||
|
||||
const idJointMat & j0 = joints[vert.color[0]];
|
||||
const idJointMat & j1 = joints[vert.color[1]];
|
||||
const idJointMat & j2 = joints[vert.color[2]];
|
||||
const idJointMat & j3 = joints[vert.color[3]];
|
||||
|
||||
const float w0 = vert.color2[0] * ( 1.0f / 255.0f );
|
||||
const float w1 = vert.color2[1] * ( 1.0f / 255.0f );
|
||||
const float w2 = vert.color2[2] * ( 1.0f / 255.0f );
|
||||
const float w3 = vert.color2[3] * ( 1.0f / 255.0f );
|
||||
|
||||
idJointMat accum;
|
||||
idJointMat::Mul( accum, j0, w0 );
|
||||
idJointMat::Mad( accum, j1, w1 );
|
||||
idJointMat::Mad( accum, j2, w2 );
|
||||
idJointMat::Mad( accum, j3, w3 );
|
||||
|
||||
idDrawVert outVert;
|
||||
outVert.xyz = accum * idVec4( vert.xyz.x, vert.xyz.y, vert.xyz.z, 1.0f );
|
||||
outVert.SetTexCoordNative( vert.GetTexCoordNativeS(), vert.GetTexCoordNativeT() );
|
||||
outVert.SetNormal( accum * vert.GetNormal() );
|
||||
outVert.SetTangent( accum * vert.GetTangent() );
|
||||
outVert.tangent[3] = vert.tangent[3];
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
outVert.color[i] = vert.color[i];
|
||||
outVert.color2[i] = vert.color2[i];
|
||||
}
|
||||
return outVert;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idDrawVert::GetSkinnedDrawVertPosition
|
||||
=====================
|
||||
*/
|
||||
ID_INLINE idVec3 idDrawVert::GetSkinnedDrawVertPosition( const idDrawVert & vert, const idJointMat * joints ) {
|
||||
if ( joints == NULL ) {
|
||||
return vert.xyz;
|
||||
}
|
||||
|
||||
const idJointMat & j0 = joints[vert.color[0]];
|
||||
const idJointMat & j1 = joints[vert.color[1]];
|
||||
const idJointMat & j2 = joints[vert.color[2]];
|
||||
const idJointMat & j3 = joints[vert.color[3]];
|
||||
|
||||
const float w0 = vert.color2[0] * ( 1.0f / 255.0f );
|
||||
const float w1 = vert.color2[1] * ( 1.0f / 255.0f );
|
||||
const float w2 = vert.color2[2] * ( 1.0f / 255.0f );
|
||||
const float w3 = vert.color2[3] * ( 1.0f / 255.0f );
|
||||
|
||||
idJointMat accum;
|
||||
idJointMat::Mul( accum, j0, w0 );
|
||||
idJointMat::Mad( accum, j1, w1 );
|
||||
idJointMat::Mad( accum, j2, w2 );
|
||||
idJointMat::Mad( accum, j3, w3 );
|
||||
|
||||
return accum * idVec4( vert.xyz.x, vert.xyz.y, vert.xyz.z, 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
Shadow Vertex
|
||||
===============================================================================
|
||||
*/
|
||||
class idShadowVert {
|
||||
public:
|
||||
idVec4 xyzw;
|
||||
|
||||
void Clear();
|
||||
static int CreateShadowCache( idShadowVert * vertexCache, const idDrawVert *verts, const int numVerts );
|
||||
};
|
||||
|
||||
#define SHADOWVERT_XYZW_OFFSET (0)
|
||||
|
||||
assert_offsetof( idShadowVert, xyzw, SHADOWVERT_XYZW_OFFSET );
|
||||
|
||||
ID_INLINE void idShadowVert::Clear() {
|
||||
xyzw.Zero();
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
Skinned Shadow Vertex
|
||||
===============================================================================
|
||||
*/
|
||||
class idShadowVertSkinned {
|
||||
public:
|
||||
idVec4 xyzw;
|
||||
byte color[4];
|
||||
byte color2[4];
|
||||
byte pad[8]; // pad to multiple of 32-byte for glDrawElementsBaseVertex
|
||||
|
||||
void Clear();
|
||||
static int CreateShadowCache( idShadowVertSkinned * vertexCache, const idDrawVert *verts, const int numVerts );
|
||||
};
|
||||
|
||||
#define SHADOWVERTSKINNED_XYZW_OFFSET (0)
|
||||
#define SHADOWVERTSKINNED_COLOR_OFFSET (16)
|
||||
#define SHADOWVERTSKINNED_COLOR2_OFFSET (20)
|
||||
|
||||
assert_offsetof( idShadowVertSkinned, xyzw, SHADOWVERTSKINNED_XYZW_OFFSET );
|
||||
assert_offsetof( idShadowVertSkinned, color, SHADOWVERTSKINNED_COLOR_OFFSET );
|
||||
assert_offsetof( idShadowVertSkinned, color2, SHADOWVERTSKINNED_COLOR2_OFFSET );
|
||||
|
||||
ID_INLINE void idShadowVertSkinned::Clear() {
|
||||
xyzw.Zero();
|
||||
}
|
||||
|
||||
#endif /* !__DRAWVERT_H__ */
|
||||
200
neo/idlib/geometry/DrawVert_intrinsics.h
Normal file
200
neo/idlib/geometry/DrawVert_intrinsics.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DRAWVERT_INTRINSICS_H__
|
||||
#define __DRAWVERT_INTRINSICS_H__
|
||||
|
||||
|
||||
static const __m128i vector_int_f32_sign_mask = _mm_set1_epi32( 1U << IEEE_FLT_SIGN_BIT );
|
||||
static const __m128i vector_int_f32_exponent_mask = _mm_set1_epi32( ( ( 1U << IEEE_FLT_EXPONENT_BITS ) - 1 ) << IEEE_FLT_MANTISSA_BITS );
|
||||
static const __m128i vector_int_f32_mantissa_mask = _mm_set1_epi32( ( 1U << IEEE_FLT_MANTISSA_BITS ) - 1 );
|
||||
static const __m128i vector_int_f16_min_exponent = _mm_set1_epi32( 0 );
|
||||
static const __m128i vector_int_f16_max_exponent = _mm_set1_epi32( ( 30 << IEEE_FLT16_MANTISSA_BITS ) );
|
||||
static const __m128i vector_int_f16_min_mantissa = _mm_set1_epi32( 0 );
|
||||
static const __m128i vector_int_f16_max_mantissa = _mm_set1_epi32( ( ( 1 << IEEE_FLT16_MANTISSA_BITS ) - 1 ) );
|
||||
static const __m128i vector_int_f32_to_f16_exponent_bias = _mm_set1_epi32( ( IEEE_FLT_EXPONENT_BIAS - IEEE_FLT16_EXPONENT_BIAS ) << IEEE_FLT16_MANTISSA_BITS );
|
||||
static const int f32_to_f16_sign_shift = IEEE_FLT_SIGN_BIT - IEEE_FLT16_SIGN_BIT;
|
||||
static const int f32_to_f16_exponent_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
static const int f32_to_f16_mantissa_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
|
||||
static const __m128i vector_int_zero = _mm_setzero_si128();
|
||||
static const __m128i vector_int_one = _mm_set_epi32( 1, 1, 1, 1 );
|
||||
|
||||
static const __m128 vector_float_mask_clear_last = __m128c( _mm_set_epi32( 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ) );
|
||||
static const __m128 vector_float_last_one = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
static const __m128 vector_float_1_over_255 = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f };
|
||||
static const __m128 vector_float_1_over_4 = { 1.0f / 4.0f, 1.0f / 4.0f, 1.0f / 4.0f, 1.0f / 4.0f };
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
FastF32toF16
|
||||
====================
|
||||
*/
|
||||
|
||||
ID_INLINE_EXTERN __m128i FastF32toF16( __m128i f32_bits ) {
|
||||
__m128i f16_sign = _mm_srli_epi32( _mm_and_si128( f32_bits, vector_int_f32_sign_mask ), f32_to_f16_sign_shift );
|
||||
__m128i f16_exponent = _mm_srli_epi32( _mm_and_si128( f32_bits, vector_int_f32_exponent_mask ), f32_to_f16_exponent_shift );
|
||||
__m128i f16_mantissa = _mm_srli_epi32( _mm_and_si128( f32_bits, vector_int_f32_mantissa_mask ), f32_to_f16_mantissa_shift );
|
||||
|
||||
f16_exponent = _mm_sub_epi32( f16_exponent, vector_int_f32_to_f16_exponent_bias );
|
||||
|
||||
const __m128i underflow = _mm_cmplt_epi32( f16_exponent, vector_int_f16_min_exponent );
|
||||
const __m128i overflow = _mm_cmpgt_epi32( f16_exponent, vector_int_f16_max_exponent );
|
||||
|
||||
f16_exponent = _mm_sel_si128( f16_exponent, vector_int_f16_min_exponent, underflow );
|
||||
f16_exponent = _mm_sel_si128( f16_exponent, vector_int_f16_max_exponent, overflow );
|
||||
f16_mantissa = _mm_sel_si128( f16_mantissa, vector_int_f16_min_mantissa, underflow );
|
||||
f16_mantissa = _mm_sel_si128( f16_mantissa, vector_int_f16_max_mantissa, overflow );
|
||||
|
||||
__m128i flt16 = _mm_or_si128( _mm_or_si128( f16_sign, f16_exponent ), f16_mantissa );
|
||||
|
||||
return _mm_packs_epi32( flt16, flt16 );
|
||||
}
|
||||
|
||||
|
||||
ID_INLINE_EXTERN halfFloat_t Scalar_FastF32toF16( float f32 ) {
|
||||
const int f32_sign_mask = 1U << IEEE_FLT_SIGN_BIT;
|
||||
const int f32_exponent_mask = ( ( 1U << IEEE_FLT_EXPONENT_BITS ) - 1 ) << IEEE_FLT_MANTISSA_BITS;
|
||||
const int f32_mantissa_mask = ( 1U << IEEE_FLT_MANTISSA_BITS ) - 1;
|
||||
const int f16_min_exponent = 0;
|
||||
const int f16_max_exponent = ( 30 << IEEE_FLT16_MANTISSA_BITS );
|
||||
const int f16_min_mantissa = 0;
|
||||
const int f16_max_mantissa = ( ( 1 << IEEE_FLT16_MANTISSA_BITS ) - 1 );
|
||||
const int f32_to_f16_sign_shift = IEEE_FLT_SIGN_BIT - IEEE_FLT16_SIGN_BIT;
|
||||
const int f32_to_f16_exponent_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
const int f32_to_f16_mantissa_shift = IEEE_FLT_MANTISSA_BITS - IEEE_FLT16_MANTISSA_BITS;
|
||||
const int f32_to_f16_exponent_bias = ( IEEE_FLT_EXPONENT_BIAS - IEEE_FLT16_EXPONENT_BIAS ) << IEEE_FLT16_MANTISSA_BITS;
|
||||
|
||||
int f32_bits = *(unsigned int *)&f32;
|
||||
|
||||
int f16_sign = ( (unsigned int )( f32_bits & f32_sign_mask ) >> f32_to_f16_sign_shift );
|
||||
int f16_exponent = ( (unsigned int )( f32_bits & f32_exponent_mask ) >> f32_to_f16_exponent_shift );
|
||||
int f16_mantissa = ( (unsigned int )( f32_bits & f32_mantissa_mask ) >> f32_to_f16_mantissa_shift );
|
||||
|
||||
f16_exponent -= f32_to_f16_exponent_bias;
|
||||
|
||||
const bool underflow = ( f16_exponent < f16_min_exponent );
|
||||
const bool overflow = ( f16_exponent > f16_max_exponent );
|
||||
|
||||
f16_exponent = underflow ? f16_min_exponent : f16_exponent;
|
||||
f16_exponent = overflow ? f16_max_exponent : f16_exponent;
|
||||
f16_mantissa = underflow ? f16_min_mantissa : f16_mantissa;
|
||||
f16_mantissa = overflow ? f16_max_mantissa : f16_mantissa;
|
||||
|
||||
return (halfFloat_t)( f16_sign | f16_exponent | f16_mantissa );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
LoadSkinnedDrawVertPosition
|
||||
====================
|
||||
*/
|
||||
|
||||
ID_INLINE_EXTERN __m128 LoadSkinnedDrawVertPosition( const idDrawVert & base, const idJointMat * joints ) {
|
||||
const idJointMat & j0 = joints[base.color[0]];
|
||||
const idJointMat & j1 = joints[base.color[1]];
|
||||
const idJointMat & j2 = joints[base.color[2]];
|
||||
const idJointMat & j3 = joints[base.color[3]];
|
||||
|
||||
__m128i weights_b = _mm_cvtsi32_si128( *(const unsigned int *)base.color2 );
|
||||
__m128i weights_s = _mm_unpacklo_epi8( weights_b, vector_int_zero );
|
||||
__m128i weights_i = _mm_unpacklo_epi16( weights_s, vector_int_zero );
|
||||
|
||||
__m128 weights = _mm_cvtepi32_ps( weights_i );
|
||||
weights = _mm_mul_ps( weights, vector_float_1_over_255 );
|
||||
|
||||
__m128 w0 = _mm_splat_ps( weights, 0 );
|
||||
__m128 w1 = _mm_splat_ps( weights, 1 );
|
||||
__m128 w2 = _mm_splat_ps( weights, 2 );
|
||||
__m128 w3 = _mm_splat_ps( weights, 3 );
|
||||
|
||||
__m128 matX = _mm_mul_ps( _mm_load_ps( j0.ToFloatPtr() + 0 * 4 ), w0 );
|
||||
__m128 matY = _mm_mul_ps( _mm_load_ps( j0.ToFloatPtr() + 1 * 4 ), w0 );
|
||||
__m128 matZ = _mm_mul_ps( _mm_load_ps( j0.ToFloatPtr() + 2 * 4 ), w0 );
|
||||
|
||||
matX = _mm_madd_ps( _mm_load_ps( j1.ToFloatPtr() + 0 * 4 ), w1, matX );
|
||||
matY = _mm_madd_ps( _mm_load_ps( j1.ToFloatPtr() + 1 * 4 ), w1, matY );
|
||||
matZ = _mm_madd_ps( _mm_load_ps( j1.ToFloatPtr() + 2 * 4 ), w1, matZ );
|
||||
|
||||
matX = _mm_madd_ps( _mm_load_ps( j2.ToFloatPtr() + 0 * 4 ), w2, matX );
|
||||
matY = _mm_madd_ps( _mm_load_ps( j2.ToFloatPtr() + 1 * 4 ), w2, matY );
|
||||
matZ = _mm_madd_ps( _mm_load_ps( j2.ToFloatPtr() + 2 * 4 ), w2, matZ );
|
||||
|
||||
matX = _mm_madd_ps( _mm_load_ps( j3.ToFloatPtr() + 0 * 4 ), w3, matX );
|
||||
matY = _mm_madd_ps( _mm_load_ps( j3.ToFloatPtr() + 1 * 4 ), w3, matY );
|
||||
matZ = _mm_madd_ps( _mm_load_ps( j3.ToFloatPtr() + 2 * 4 ), w3, matZ );
|
||||
|
||||
__m128 v = _mm_load_ps( base.xyz.ToFloatPtr() );
|
||||
v = _mm_and_ps( v, vector_float_mask_clear_last );
|
||||
v = _mm_or_ps( v, vector_float_last_one );
|
||||
|
||||
__m128 t0 = _mm_mul_ps( matX, v );
|
||||
__m128 t1 = _mm_mul_ps( matY, v );
|
||||
__m128 t2 = _mm_mul_ps( matZ, v );
|
||||
__m128 t3 = vector_float_1_over_4;
|
||||
|
||||
__m128 s0 = _mm_unpacklo_ps( t0, t2 ); // x0, z0, x1, z1
|
||||
__m128 s1 = _mm_unpackhi_ps( t0, t2 ); // x2, z2, x3, z3
|
||||
__m128 s2 = _mm_unpacklo_ps( t1, t3 ); // y0, w0, y1, w1
|
||||
__m128 s3 = _mm_unpackhi_ps( t1, t3 ); // y2, w2, y3, w3
|
||||
|
||||
__m128 r0 = _mm_unpacklo_ps( s0, s2 ); // x0, y0, z0, w0
|
||||
__m128 r1 = _mm_unpackhi_ps( s0, s2 ); // x1, y1, z1, w1
|
||||
__m128 r2 = _mm_unpacklo_ps( s1, s3 ); // x2, y2, z2, w2
|
||||
__m128 r3 = _mm_unpackhi_ps( s1, s3 ); // x3, y3, z3, w3
|
||||
|
||||
r0 = _mm_add_ps( r0, r1 );
|
||||
r2 = _mm_add_ps( r2, r3 );
|
||||
r0 = _mm_add_ps( r0, r2 );
|
||||
|
||||
return r0;
|
||||
}
|
||||
|
||||
|
||||
ID_INLINE_EXTERN idVec3 Scalar_LoadSkinnedDrawVertPosition( const idDrawVert & vert, const idJointMat * joints ) {
|
||||
const idJointMat & j0 = joints[vert.color[0]];
|
||||
const idJointMat & j1 = joints[vert.color[1]];
|
||||
const idJointMat & j2 = joints[vert.color[2]];
|
||||
const idJointMat & j3 = joints[vert.color[3]];
|
||||
|
||||
const float w0 = vert.color2[0] * ( 1.0f / 255.0f );
|
||||
const float w1 = vert.color2[1] * ( 1.0f / 255.0f );
|
||||
const float w2 = vert.color2[2] * ( 1.0f / 255.0f );
|
||||
const float w3 = vert.color2[3] * ( 1.0f / 255.0f );
|
||||
|
||||
idJointMat accum;
|
||||
idJointMat::Mul( accum, j0, w0 );
|
||||
idJointMat::Mad( accum, j1, w1 );
|
||||
idJointMat::Mad( accum, j2, w2 );
|
||||
idJointMat::Mad( accum, j3, w3 );
|
||||
|
||||
return accum * idVec4( vert.xyz.x, vert.xyz.y, vert.xyz.z, 1.0f );
|
||||
}
|
||||
|
||||
#endif /* !__DRAWVERT_INTRINSICS_H__ */
|
||||
87
neo/idlib/geometry/JointTransform.cpp
Normal file
87
neo/idlib/geometry/JointTransform.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
=============
|
||||
idJointMat::ToJointQuat
|
||||
=============
|
||||
*/
|
||||
idJointQuat idJointMat::ToJointQuat() const {
|
||||
idJointQuat jq;
|
||||
float trace;
|
||||
float s;
|
||||
float t;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
|
||||
static int next[3] = { 1, 2, 0 };
|
||||
|
||||
trace = mat[0 * 4 + 0] + mat[1 * 4 + 1] + mat[2 * 4 + 2];
|
||||
|
||||
if ( trace > 0.0f ) {
|
||||
|
||||
t = trace + 1.0f;
|
||||
s = idMath::InvSqrt( t ) * 0.5f;
|
||||
|
||||
jq.q[3] = s * t;
|
||||
jq.q[0] = ( mat[1 * 4 + 2] - mat[2 * 4 + 1] ) * s;
|
||||
jq.q[1] = ( mat[2 * 4 + 0] - mat[0 * 4 + 2] ) * s;
|
||||
jq.q[2] = ( mat[0 * 4 + 1] - mat[1 * 4 + 0] ) * s;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
if ( mat[1 * 4 + 1] > mat[0 * 4 + 0] ) {
|
||||
i = 1;
|
||||
}
|
||||
if ( mat[2 * 4 + 2] > mat[i * 4 + i] ) {
|
||||
i = 2;
|
||||
}
|
||||
j = next[i];
|
||||
k = next[j];
|
||||
|
||||
t = ( mat[i * 4 + i] - ( mat[j * 4 + j] + mat[k * 4 + k] ) ) + 1.0f;
|
||||
s = idMath::InvSqrt( t ) * 0.5f;
|
||||
|
||||
jq.q[i] = s * t;
|
||||
jq.q[3] = ( mat[j * 4 + k] - mat[k * 4 + j] ) * s;
|
||||
jq.q[j] = ( mat[i * 4 + j] + mat[j * 4 + i] ) * s;
|
||||
jq.q[k] = ( mat[i * 4 + k] + mat[k * 4 + i] ) * s;
|
||||
}
|
||||
|
||||
jq.t[0] = mat[0 * 4 + 3];
|
||||
jq.t[1] = mat[1 * 4 + 3];
|
||||
jq.t[2] = mat[2 * 4 + 3];
|
||||
jq.w = 0.0f;
|
||||
|
||||
return jq;
|
||||
}
|
||||
544
neo/idlib/geometry/JointTransform.h
Normal file
544
neo/idlib/geometry/JointTransform.h
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JOINTTRANSFORM_H__
|
||||
#define __JOINTTRANSFORM_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Joint Quaternion
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idJointQuat {
|
||||
public:
|
||||
const float * ToFloatPtr() const { return q.ToFloatPtr(); }
|
||||
float * ToFloatPtr() { return q.ToFloatPtr(); }
|
||||
|
||||
idQuat q;
|
||||
idVec3 t;
|
||||
float w;
|
||||
};
|
||||
|
||||
// offsets for SIMD code
|
||||
#define JOINTQUAT_SIZE (8*4) // sizeof( idJointQuat )
|
||||
#define JOINTQUAT_SIZE_SHIFT 5 // log2( sizeof( idJointQuat ) )
|
||||
#define JOINTQUAT_Q_OFFSET (0*4) // offsetof( idJointQuat, q )
|
||||
#define JOINTQUAT_T_OFFSET (4*4) // offsetof( idJointQuat, t )
|
||||
|
||||
assert_sizeof( idJointQuat, JOINTQUAT_SIZE );
|
||||
assert_sizeof( idJointQuat, (1<<JOINTQUAT_SIZE_SHIFT) );
|
||||
assert_offsetof( idJointQuat, q, JOINTQUAT_Q_OFFSET );
|
||||
assert_offsetof( idJointQuat, t, JOINTQUAT_T_OFFSET );
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Joint Matrix
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================================================
|
||||
idJointMat has the following structure:
|
||||
|
||||
idMat3 m;
|
||||
idVec3 t;
|
||||
|
||||
m[0][0], m[1][0], m[2][0], t[0]
|
||||
m[0][1], m[1][1], m[2][1], t[1]
|
||||
m[0][2], m[1][2], m[2][2], t[2]
|
||||
|
||||
================================================
|
||||
*/
|
||||
class idJointMat {
|
||||
public:
|
||||
|
||||
void SetRotation( const idMat3 &m );
|
||||
idMat3 GetRotation() const;
|
||||
void SetTranslation( const idVec3 &t );
|
||||
idVec3 GetTranslation() const;
|
||||
|
||||
idVec3 operator*( const idVec3 &v ) const; // only rotate
|
||||
idVec3 operator*( const idVec4 &v ) const; // rotate and translate
|
||||
|
||||
idJointMat & operator*=( const idJointMat &a ); // transform
|
||||
idJointMat & operator/=( const idJointMat &a ); // untransform
|
||||
|
||||
bool Compare( const idJointMat &a ) const; // exact compare, no epsilon
|
||||
bool Compare( const idJointMat &a, const float epsilon ) const; // compare with epsilon
|
||||
bool operator==( const idJointMat &a ) const; // exact compare, no epsilon
|
||||
bool operator!=( const idJointMat &a ) const; // exact compare, no epsilon
|
||||
|
||||
void Identity();
|
||||
void Invert();
|
||||
|
||||
void FromMat4( const idMat4 & m );
|
||||
|
||||
idMat3 ToMat3() const;
|
||||
idMat4 ToMat4() const;
|
||||
idVec3 ToVec3() const;
|
||||
const float * ToFloatPtr() const { return mat; }
|
||||
float * ToFloatPtr() { return mat; }
|
||||
idJointQuat ToJointQuat() const;
|
||||
|
||||
void Transform( idVec3 &result, const idVec3 &v ) const;
|
||||
void Rotate( idVec3 &result, const idVec3 &v ) const;
|
||||
|
||||
static void Mul( idJointMat &result, const idJointMat &mat, const float s );
|
||||
static void Mad( idJointMat &result, const idJointMat &mat, const float s );
|
||||
static void Multiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 );
|
||||
static void InverseMultiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 );
|
||||
|
||||
float mat[3*4];
|
||||
};
|
||||
|
||||
// offsets for SIMD code
|
||||
#define JOINTMAT_SIZE (4*3*4) // sizeof( idJointMat )
|
||||
assert_sizeof( idJointMat, JOINTMAT_SIZE );
|
||||
|
||||
#define JOINTMAT_TYPESIZE ( 4 * 3 )
|
||||
/*
|
||||
========================
|
||||
idJointMat::SetRotation
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::SetRotation( const idMat3 &m ) {
|
||||
// NOTE: idMat3 is transposed because it is column-major
|
||||
mat[0 * 4 + 0] = m[0][0];
|
||||
mat[0 * 4 + 1] = m[1][0];
|
||||
mat[0 * 4 + 2] = m[2][0];
|
||||
mat[1 * 4 + 0] = m[0][1];
|
||||
mat[1 * 4 + 1] = m[1][1];
|
||||
mat[1 * 4 + 2] = m[2][1];
|
||||
mat[2 * 4 + 0] = m[0][2];
|
||||
mat[2 * 4 + 1] = m[1][2];
|
||||
mat[2 * 4 + 2] = m[2][2];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::GetRotation
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idMat3 idJointMat::GetRotation() const {
|
||||
idMat3 m;
|
||||
m[0][0] = mat[0 * 4 + 0];
|
||||
m[1][0] = mat[0 * 4 + 1];
|
||||
m[2][0] = mat[0 * 4 + 2];
|
||||
m[0][1] = mat[1 * 4 + 0];
|
||||
m[1][1] = mat[1 * 4 + 1];
|
||||
m[2][1] = mat[1 * 4 + 2];
|
||||
m[0][2] = mat[2 * 4 + 0];
|
||||
m[1][2] = mat[2 * 4 + 1];
|
||||
m[2][2] = mat[2 * 4 + 2];
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::SetTranslation
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::SetTranslation( const idVec3 &t ) {
|
||||
mat[0 * 4 + 3] = t[0];
|
||||
mat[1 * 4 + 3] = t[1];
|
||||
mat[2 * 4 + 3] = t[2];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::GetTranslation
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idVec3 idJointMat::GetTranslation() const {
|
||||
idVec3 t;
|
||||
t[0] = mat[0 * 4 + 3];
|
||||
t[1] = mat[1 * 4 + 3];
|
||||
t[2] = mat[2 * 4 + 3];
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator*
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idVec3 idJointMat::operator*( const idVec3 &v ) const {
|
||||
return idVec3( mat[0 * 4 + 0] * v[0] + mat[0 * 4 + 1] * v[1] + mat[0 * 4 + 2] * v[2],
|
||||
mat[1 * 4 + 0] * v[0] + mat[1 * 4 + 1] * v[1] + mat[1 * 4 + 2] * v[2],
|
||||
mat[2 * 4 + 0] * v[0] + mat[2 * 4 + 1] * v[1] + mat[2 * 4 + 2] * v[2] );
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 idJointMat::operator*( const idVec4 &v ) const {
|
||||
return idVec3( mat[0 * 4 + 0] * v[0] + mat[0 * 4 + 1] * v[1] + mat[0 * 4 + 2] * v[2] + mat[0 * 4 + 3] * v[3],
|
||||
mat[1 * 4 + 0] * v[0] + mat[1 * 4 + 1] * v[1] + mat[1 * 4 + 2] * v[2] + mat[1 * 4 + 3] * v[3],
|
||||
mat[2 * 4 + 0] * v[0] + mat[2 * 4 + 1] * v[1] + mat[2 * 4 + 2] * v[2] + mat[2 * 4 + 3] * v[3] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator*=
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idJointMat & idJointMat::operator*=( const idJointMat &a ) {
|
||||
float tmp[3];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 0] * a.mat[0 * 4 + 0] + mat[1 * 4 + 0] * a.mat[0 * 4 + 1] + mat[2 * 4 + 0] * a.mat[0 * 4 + 2];
|
||||
tmp[1] = mat[0 * 4 + 0] * a.mat[1 * 4 + 0] + mat[1 * 4 + 0] * a.mat[1 * 4 + 1] + mat[2 * 4 + 0] * a.mat[1 * 4 + 2];
|
||||
tmp[2] = mat[0 * 4 + 0] * a.mat[2 * 4 + 0] + mat[1 * 4 + 0] * a.mat[2 * 4 + 1] + mat[2 * 4 + 0] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 0] = tmp[0];
|
||||
mat[1 * 4 + 0] = tmp[1];
|
||||
mat[2 * 4 + 0] = tmp[2];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 1] * a.mat[0 * 4 + 0] + mat[1 * 4 + 1] * a.mat[0 * 4 + 1] + mat[2 * 4 + 1] * a.mat[0 * 4 + 2];
|
||||
tmp[1] = mat[0 * 4 + 1] * a.mat[1 * 4 + 0] + mat[1 * 4 + 1] * a.mat[1 * 4 + 1] + mat[2 * 4 + 1] * a.mat[1 * 4 + 2];
|
||||
tmp[2] = mat[0 * 4 + 1] * a.mat[2 * 4 + 0] + mat[1 * 4 + 1] * a.mat[2 * 4 + 1] + mat[2 * 4 + 1] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 1] = tmp[0];
|
||||
mat[1 * 4 + 1] = tmp[1];
|
||||
mat[2 * 4 + 1] = tmp[2];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 2] * a.mat[0 * 4 + 0] + mat[1 * 4 + 2] * a.mat[0 * 4 + 1] + mat[2 * 4 + 2] * a.mat[0 * 4 + 2];
|
||||
tmp[1] = mat[0 * 4 + 2] * a.mat[1 * 4 + 0] + mat[1 * 4 + 2] * a.mat[1 * 4 + 1] + mat[2 * 4 + 2] * a.mat[1 * 4 + 2];
|
||||
tmp[2] = mat[0 * 4 + 2] * a.mat[2 * 4 + 0] + mat[1 * 4 + 2] * a.mat[2 * 4 + 1] + mat[2 * 4 + 2] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 2] = tmp[0];
|
||||
mat[1 * 4 + 2] = tmp[1];
|
||||
mat[2 * 4 + 2] = tmp[2];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 3] * a.mat[0 * 4 + 0] + mat[1 * 4 + 3] * a.mat[0 * 4 + 1] + mat[2 * 4 + 3] * a.mat[0 * 4 + 2];
|
||||
tmp[1] = mat[0 * 4 + 3] * a.mat[1 * 4 + 0] + mat[1 * 4 + 3] * a.mat[1 * 4 + 1] + mat[2 * 4 + 3] * a.mat[1 * 4 + 2];
|
||||
tmp[2] = mat[0 * 4 + 3] * a.mat[2 * 4 + 0] + mat[1 * 4 + 3] * a.mat[2 * 4 + 1] + mat[2 * 4 + 3] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 3] = tmp[0];
|
||||
mat[1 * 4 + 3] = tmp[1];
|
||||
mat[2 * 4 + 3] = tmp[2];
|
||||
|
||||
mat[0 * 4 + 3] += a.mat[0 * 4 + 3];
|
||||
mat[1 * 4 + 3] += a.mat[1 * 4 + 3];
|
||||
mat[2 * 4 + 3] += a.mat[2 * 4 + 3];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator/=
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idJointMat &idJointMat::operator/=( const idJointMat &a ) {
|
||||
float tmp[3];
|
||||
|
||||
mat[0 * 4 + 3] -= a.mat[0 * 4 + 3];
|
||||
mat[1 * 4 + 3] -= a.mat[1 * 4 + 3];
|
||||
mat[2 * 4 + 3] -= a.mat[2 * 4 + 3];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 0] * a.mat[0 * 4 + 0] + mat[1 * 4 + 0] * a.mat[1 * 4 + 0] + mat[2 * 4 + 0] * a.mat[2 * 4 + 0];
|
||||
tmp[1] = mat[0 * 4 + 0] * a.mat[0 * 4 + 1] + mat[1 * 4 + 0] * a.mat[1 * 4 + 1] + mat[2 * 4 + 0] * a.mat[2 * 4 + 1];
|
||||
tmp[2] = mat[0 * 4 + 0] * a.mat[0 * 4 + 2] + mat[1 * 4 + 0] * a.mat[1 * 4 + 2] + mat[2 * 4 + 0] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 0] = tmp[0];
|
||||
mat[1 * 4 + 0] = tmp[1];
|
||||
mat[2 * 4 + 0] = tmp[2];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 1] * a.mat[0 * 4 + 0] + mat[1 * 4 + 1] * a.mat[1 * 4 + 0] + mat[2 * 4 + 1] * a.mat[2 * 4 + 0];
|
||||
tmp[1] = mat[0 * 4 + 1] * a.mat[0 * 4 + 1] + mat[1 * 4 + 1] * a.mat[1 * 4 + 1] + mat[2 * 4 + 1] * a.mat[2 * 4 + 1];
|
||||
tmp[2] = mat[0 * 4 + 1] * a.mat[0 * 4 + 2] + mat[1 * 4 + 1] * a.mat[1 * 4 + 2] + mat[2 * 4 + 1] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 1] = tmp[0];
|
||||
mat[1 * 4 + 1] = tmp[1];
|
||||
mat[2 * 4 + 1] = tmp[2];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 2] * a.mat[0 * 4 + 0] + mat[1 * 4 + 2] * a.mat[1 * 4 + 0] + mat[2 * 4 + 2] * a.mat[2 * 4 + 0];
|
||||
tmp[1] = mat[0 * 4 + 2] * a.mat[0 * 4 + 1] + mat[1 * 4 + 2] * a.mat[1 * 4 + 1] + mat[2 * 4 + 2] * a.mat[2 * 4 + 1];
|
||||
tmp[2] = mat[0 * 4 + 2] * a.mat[0 * 4 + 2] + mat[1 * 4 + 2] * a.mat[1 * 4 + 2] + mat[2 * 4 + 2] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 2] = tmp[0];
|
||||
mat[1 * 4 + 2] = tmp[1];
|
||||
mat[2 * 4 + 2] = tmp[2];
|
||||
|
||||
tmp[0] = mat[0 * 4 + 3] * a.mat[0 * 4 + 0] + mat[1 * 4 + 3] * a.mat[1 * 4 + 0] + mat[2 * 4 + 3] * a.mat[2 * 4 + 0];
|
||||
tmp[1] = mat[0 * 4 + 3] * a.mat[0 * 4 + 1] + mat[1 * 4 + 3] * a.mat[1 * 4 + 1] + mat[2 * 4 + 3] * a.mat[2 * 4 + 1];
|
||||
tmp[2] = mat[0 * 4 + 3] * a.mat[0 * 4 + 2] + mat[1 * 4 + 3] * a.mat[1 * 4 + 2] + mat[2 * 4 + 3] * a.mat[2 * 4 + 2];
|
||||
mat[0 * 4 + 3] = tmp[0];
|
||||
mat[1 * 4 + 3] = tmp[1];
|
||||
mat[2 * 4 + 3] = tmp[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Compare
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idJointMat::Compare( const idJointMat &a ) const {
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < 12; i++ ) {
|
||||
if ( mat[i] != a.mat[i] ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Compare
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idJointMat::Compare( const idJointMat &a, const float epsilon ) const {
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < 12; i++ ) {
|
||||
if ( idMath::Fabs( mat[i] - a.mat[i] ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator==
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idJointMat::operator==( const idJointMat &a ) const {
|
||||
return Compare( a );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::operator!=
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idJointMat::operator!=( const idJointMat &a ) const {
|
||||
return !Compare( a );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Identity
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Identity() {
|
||||
mat[0 * 4 + 0] = 1.0f; mat[0 * 4 + 1] = 0.0f; mat[0 * 4 + 2] = 0.0f; mat[0 * 4 + 3] = 0.0f;
|
||||
mat[1 * 4 + 0] = 0.0f; mat[1 * 4 + 1] = 1.0f; mat[1 * 4 + 2] = 0.0f; mat[1 * 4 + 3] = 0.0f;
|
||||
mat[2 * 4 + 0] = 0.0f; mat[2 * 4 + 1] = 0.0f; mat[2 * 4 + 2] = 1.0f; mat[2 * 4 + 3] = 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Invert
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Invert() {
|
||||
float tmp[3];
|
||||
|
||||
// negate inverse rotated translation part
|
||||
tmp[0] = mat[0 * 4 + 0] * mat[0 * 4 + 3] + mat[1 * 4 + 0] * mat[1 * 4 + 3] + mat[2 * 4 + 0] * mat[2 * 4 + 3];
|
||||
tmp[1] = mat[0 * 4 + 1] * mat[0 * 4 + 3] + mat[1 * 4 + 1] * mat[1 * 4 + 3] + mat[2 * 4 + 1] * mat[2 * 4 + 3];
|
||||
tmp[2] = mat[0 * 4 + 2] * mat[0 * 4 + 3] + mat[1 * 4 + 2] * mat[1 * 4 + 3] + mat[2 * 4 + 2] * mat[2 * 4 + 3];
|
||||
mat[0 * 4 + 3] = -tmp[0];
|
||||
mat[1 * 4 + 3] = -tmp[1];
|
||||
mat[2 * 4 + 3] = -tmp[2];
|
||||
|
||||
// transpose rotation part
|
||||
tmp[0] = mat[0 * 4 + 1];
|
||||
mat[0 * 4 + 1] = mat[1 * 4 + 0];
|
||||
mat[1 * 4 + 0] = tmp[0];
|
||||
tmp[1] = mat[0 * 4 + 2];
|
||||
mat[0 * 4 + 2] = mat[2 * 4 + 0];
|
||||
mat[2 * 4 + 0] = tmp[1];
|
||||
tmp[2] = mat[1 * 4 + 2];
|
||||
mat[1 * 4 + 2] = mat[2 * 4 + 1];
|
||||
mat[2 * 4 + 1] = tmp[2];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::ToMat3
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idMat3 idJointMat::ToMat3() const {
|
||||
return idMat3( mat[0 * 4 + 0], mat[1 * 4 + 0], mat[2 * 4 + 0],
|
||||
mat[0 * 4 + 1], mat[1 * 4 + 1], mat[2 * 4 + 1],
|
||||
mat[0 * 4 + 2], mat[1 * 4 + 2], mat[2 * 4 + 2] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::ToMat4
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idMat4 idJointMat::ToMat4() const {
|
||||
return idMat4(
|
||||
mat[0 * 4 + 0], mat[0 * 4 + 1], mat[0 * 4 + 2], mat[0 * 4 + 3],
|
||||
mat[1 * 4 + 0], mat[1 * 4 + 1], mat[1 * 4 + 2], mat[1 * 4 + 3],
|
||||
mat[2 * 4 + 0], mat[2 * 4 + 1], mat[2 * 4 + 2], mat[2 * 4 + 3],
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::FromMat4
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::FromMat4( const idMat4 & m ) {
|
||||
mat[0*4+0] = m[0][0], mat[0*4+1] = m[0][1], mat[0*4+2] = m[0][2], mat[0*4+3] = m[0][3];
|
||||
mat[1*4+0] = m[1][0], mat[1*4+1] = m[1][1], mat[1*4+2] = m[1][2], mat[1*4+3] = m[1][3];
|
||||
mat[2*4+0] = m[2][0], mat[2*4+1] = m[2][1], mat[2*4+2] = m[2][2], mat[2*4+3] = m[2][3];
|
||||
assert( m[3][0] == 0.0f );
|
||||
assert( m[3][1] == 0.0f );
|
||||
assert( m[3][2] == 0.0f );
|
||||
assert( m[3][3] == 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::ToVec3
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idVec3 idJointMat::ToVec3() const {
|
||||
return idVec3( mat[0 * 4 + 3], mat[1 * 4 + 3], mat[2 * 4 + 3] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Transform
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Transform( idVec3 &result, const idVec3 &v ) const {
|
||||
result.x = mat[0 * 4 + 0] * v.x + mat[0 * 4 + 1] * v.y + mat[0 * 4 + 2] * v.z + mat[0 * 4 + 3];
|
||||
result.y = mat[1 * 4 + 0] * v.x + mat[1 * 4 + 1] * v.y + mat[1 * 4 + 2] * v.z + mat[1 * 4 + 3];
|
||||
result.z = mat[2 * 4 + 0] * v.x + mat[2 * 4 + 1] * v.y + mat[2 * 4 + 2] * v.z + mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Rotate
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Rotate( idVec3 &result, const idVec3 &v ) const {
|
||||
result.x = mat[0 * 4 + 0] * v.x + mat[0 * 4 + 1] * v.y + mat[0 * 4 + 2] * v.z;
|
||||
result.y = mat[1 * 4 + 0] * v.x + mat[1 * 4 + 1] * v.y + mat[1 * 4 + 2] * v.z;
|
||||
result.z = mat[2 * 4 + 0] * v.x + mat[2 * 4 + 1] * v.y + mat[2 * 4 + 2] * v.z;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Mul
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Mul( idJointMat &result, const idJointMat &mat, const float s ) {
|
||||
result.mat[0 * 4 + 0] = s * mat.mat[0 * 4 + 0];
|
||||
result.mat[0 * 4 + 1] = s * mat.mat[0 * 4 + 1];
|
||||
result.mat[0 * 4 + 2] = s * mat.mat[0 * 4 + 2];
|
||||
result.mat[0 * 4 + 3] = s * mat.mat[0 * 4 + 3];
|
||||
result.mat[1 * 4 + 0] = s * mat.mat[1 * 4 + 0];
|
||||
result.mat[1 * 4 + 1] = s * mat.mat[1 * 4 + 1];
|
||||
result.mat[1 * 4 + 2] = s * mat.mat[1 * 4 + 2];
|
||||
result.mat[1 * 4 + 3] = s * mat.mat[1 * 4 + 3];
|
||||
result.mat[2 * 4 + 0] = s * mat.mat[2 * 4 + 0];
|
||||
result.mat[2 * 4 + 1] = s * mat.mat[2 * 4 + 1];
|
||||
result.mat[2 * 4 + 2] = s * mat.mat[2 * 4 + 2];
|
||||
result.mat[2 * 4 + 3] = s * mat.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Mad
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Mad( idJointMat &result, const idJointMat &mat, const float s ) {
|
||||
result.mat[0 * 4 + 0] += s * mat.mat[0 * 4 + 0];
|
||||
result.mat[0 * 4 + 1] += s * mat.mat[0 * 4 + 1];
|
||||
result.mat[0 * 4 + 2] += s * mat.mat[0 * 4 + 2];
|
||||
result.mat[0 * 4 + 3] += s * mat.mat[0 * 4 + 3];
|
||||
result.mat[1 * 4 + 0] += s * mat.mat[1 * 4 + 0];
|
||||
result.mat[1 * 4 + 1] += s * mat.mat[1 * 4 + 1];
|
||||
result.mat[1 * 4 + 2] += s * mat.mat[1 * 4 + 2];
|
||||
result.mat[1 * 4 + 3] += s * mat.mat[1 * 4 + 3];
|
||||
result.mat[2 * 4 + 0] += s * mat.mat[2 * 4 + 0];
|
||||
result.mat[2 * 4 + 1] += s * mat.mat[2 * 4 + 1];
|
||||
result.mat[2 * 4 + 2] += s * mat.mat[2 * 4 + 2];
|
||||
result.mat[2 * 4 + 3] += s * mat.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::Multiply
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::Multiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 ) {
|
||||
result.mat[0 * 4 + 0] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 0] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 0];
|
||||
result.mat[0 * 4 + 1] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 1] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 1];
|
||||
result.mat[0 * 4 + 2] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 2] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 2] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
result.mat[0 * 4 + 3] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 3] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 3] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 3] + m1.mat[0 * 4 + 3];
|
||||
|
||||
result.mat[1 * 4 + 0] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 0] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 0];
|
||||
result.mat[1 * 4 + 1] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 1] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 1];
|
||||
result.mat[1 * 4 + 2] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 2] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 2] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
result.mat[1 * 4 + 3] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 3] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 3] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 3] + m1.mat[1 * 4 + 3];
|
||||
|
||||
result.mat[2 * 4 + 0] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 0] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 0];
|
||||
result.mat[2 * 4 + 1] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 1] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 1];
|
||||
result.mat[2 * 4 + 2] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 2] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 2] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
result.mat[2 * 4 + 3] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 3] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 3] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 3] + m1.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idJointMat::InverseMultiply
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idJointMat::InverseMultiply( idJointMat &result, const idJointMat &m1, const idJointMat &m2 ) {
|
||||
float dst[3];
|
||||
|
||||
result.mat[0 * 4 + 0] = m1.mat[0 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[0 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[0 * 4 + 2];
|
||||
result.mat[0 * 4 + 1] = m1.mat[0 * 4 + 0] * m2.mat[1 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[1 * 4 + 2];
|
||||
result.mat[0 * 4 + 2] = m1.mat[0 * 4 + 0] * m2.mat[2 * 4 + 0] + m1.mat[0 * 4 + 1] * m2.mat[2 * 4 + 1] + m1.mat[0 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
|
||||
result.mat[1 * 4 + 0] = m1.mat[1 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[0 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[0 * 4 + 2];
|
||||
result.mat[1 * 4 + 1] = m1.mat[1 * 4 + 0] * m2.mat[1 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[1 * 4 + 2];
|
||||
result.mat[1 * 4 + 2] = m1.mat[1 * 4 + 0] * m2.mat[2 * 4 + 0] + m1.mat[1 * 4 + 1] * m2.mat[2 * 4 + 1] + m1.mat[1 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
|
||||
result.mat[2 * 4 + 0] = m1.mat[2 * 4 + 0] * m2.mat[0 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[0 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[0 * 4 + 2];
|
||||
result.mat[2 * 4 + 1] = m1.mat[2 * 4 + 0] * m2.mat[1 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[1 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[1 * 4 + 2];
|
||||
result.mat[2 * 4 + 2] = m1.mat[2 * 4 + 0] * m2.mat[2 * 4 + 0] + m1.mat[2 * 4 + 1] * m2.mat[2 * 4 + 1] + m1.mat[2 * 4 + 2] * m2.mat[2 * 4 + 2];
|
||||
|
||||
dst[0] = - ( m2.mat[0 * 4 + 0] * m2.mat[0 * 4 + 3] + m2.mat[1 * 4 + 0] * m2.mat[1 * 4 + 3] + m2.mat[2 * 4 + 0] * m2.mat[2 * 4 + 3] );
|
||||
dst[1] = - ( m2.mat[0 * 4 + 1] * m2.mat[0 * 4 + 3] + m2.mat[1 * 4 + 1] * m2.mat[1 * 4 + 3] + m2.mat[2 * 4 + 1] * m2.mat[2 * 4 + 3] );
|
||||
dst[2] = - ( m2.mat[0 * 4 + 2] * m2.mat[0 * 4 + 3] + m2.mat[1 * 4 + 2] * m2.mat[1 * 4 + 3] + m2.mat[2 * 4 + 2] * m2.mat[2 * 4 + 3] );
|
||||
|
||||
result.mat[0 * 4 + 3] = m1.mat[0 * 4 + 0] * dst[0] + m1.mat[0 * 4 + 1] * dst[1] + m1.mat[0 * 4 + 2] * dst[2] + m1.mat[0 * 4 + 3];
|
||||
result.mat[1 * 4 + 3] = m1.mat[1 * 4 + 0] * dst[0] + m1.mat[1 * 4 + 1] * dst[1] + m1.mat[1 * 4 + 2] * dst[2] + m1.mat[1 * 4 + 3];
|
||||
result.mat[2 * 4 + 3] = m1.mat[2 * 4 + 0] * dst[0] + m1.mat[2 * 4 + 1] * dst[1] + m1.mat[2 * 4 + 2] * dst[2] + m1.mat[2 * 4 + 3];
|
||||
}
|
||||
|
||||
#endif /* !__JOINTTRANSFORM_H__ */
|
||||
3238
neo/idlib/geometry/RenderMatrix.cpp
Normal file
3238
neo/idlib/geometry/RenderMatrix.cpp
Normal file
File diff suppressed because it is too large
Load Diff
489
neo/idlib/geometry/RenderMatrix.h
Normal file
489
neo/idlib/geometry/RenderMatrix.h
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef __RENDERMATRIX_H__
|
||||
#define __RENDERMATRIX_H__
|
||||
|
||||
static const int NUM_FRUSTUM_CORNERS = 8;
|
||||
|
||||
struct frustumCorners_t {
|
||||
float x[NUM_FRUSTUM_CORNERS];
|
||||
float y[NUM_FRUSTUM_CORNERS];
|
||||
float z[NUM_FRUSTUM_CORNERS];
|
||||
};
|
||||
|
||||
enum frustumCull_t {
|
||||
FRUSTUM_CULL_FRONT = 1,
|
||||
FRUSTUM_CULL_BACK = 2,
|
||||
FRUSTUM_CULL_CROSS = 3
|
||||
};
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
|
||||
idRenderMatrix
|
||||
|
||||
This is a row-major matrix and transforms are applied with left-multiplication.
|
||||
|
||||
================================================================================================
|
||||
*/
|
||||
class idRenderMatrix {
|
||||
public:
|
||||
idRenderMatrix() {}
|
||||
ID_INLINE idRenderMatrix( float a0, float a1, float a2, float a3,
|
||||
float b0, float b1, float b2, float b3,
|
||||
float c0, float c1, float c2, float c3,
|
||||
float d0, float d1, float d2, float d3 );
|
||||
|
||||
const float * operator[]( int index ) const { assert( index >= 0 && index < 4 ); return &m[index*4]; }
|
||||
float * operator[]( int index ) { assert( index >= 0 && index < 4 ); return &m[index*4]; }
|
||||
|
||||
void Zero() { memset( m, 0, sizeof( m ) ); }
|
||||
ID_INLINE void Identity();
|
||||
|
||||
// Matrix classification (only meant to be used for asserts).
|
||||
ID_INLINE bool IsZero( float epsilon ) const;
|
||||
ID_INLINE bool IsIdentity( float epsilon ) const;
|
||||
ID_INLINE bool IsAffineTransform( float epsilon ) const;
|
||||
ID_INLINE bool IsUniformScale( float epsilon ) const;
|
||||
|
||||
// Transform a point.
|
||||
// NOTE: the idVec3 out variant does not divide by W.
|
||||
ID_INLINE void TransformPoint( const idVec3 & in, idVec3 & out ) const;
|
||||
ID_INLINE void TransformPoint( const idVec3 & in, idVec4 & out ) const;
|
||||
ID_INLINE void TransformPoint( const idVec4 & in, idVec4 & out ) const;
|
||||
|
||||
// These assume the matrix has no non-uniform scaling or shearing.
|
||||
// NOTE: a direction will only stay normalized if the matrix has no skewing or scaling.
|
||||
ID_INLINE void TransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const;
|
||||
ID_INLINE void TransformPlane( const idPlane & in, idPlane & out, bool normalize ) const;
|
||||
|
||||
// These transforms work with non-uniform scaling and shearing by multiplying
|
||||
// with 'transpose(inverse(M))' where this matrix is assumed to be 'inverse(M)'.
|
||||
ID_INLINE void InverseTransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const;
|
||||
ID_INLINE void InverseTransformPlane( const idPlane & in, idPlane & out, bool normalize ) const;
|
||||
|
||||
// Project a point.
|
||||
static ID_INLINE void TransformModelToClip( const idVec3 & src, const idRenderMatrix & modelMatrix, const idRenderMatrix & projectionMatrix, idVec4 & eye, idVec4 & clip );
|
||||
static ID_INLINE void TransformClipToDevice( const idVec4 & clip, idVec3 & ndc );
|
||||
|
||||
// Create a matrix that goes from local space to the space defined by the 'origin' and 'axis'.
|
||||
static void CreateFromOriginAxis( const idVec3 & origin, const idMat3 & axis, idRenderMatrix & out );
|
||||
static void CreateFromOriginAxisScale( const idVec3 & origin, const idMat3 & axis, const idVec3 & scale, idRenderMatrix & out );
|
||||
|
||||
// Create a matrix that goes from a global coordinate to a view coordinate (OpenGL looking down -Z) based on the given view origin/axis.
|
||||
static void CreateViewMatrix( const idVec3 & origin, const idMat3 & axis, idRenderMatrix & out );
|
||||
|
||||
// Create a projection matrix.
|
||||
static void CreateProjectionMatrix( float xMin, float xMax, float yMin, float yMax, float zNear, float zFar, idRenderMatrix & out );
|
||||
static void CreateProjectionMatrixFov( float xFovDegrees, float yFovDegrees, float zNear, float zFar, float xOffset, float yOffset, idRenderMatrix & out );
|
||||
|
||||
// Apply depth hacks to a projection matrix.
|
||||
static ID_INLINE void ApplyDepthHack( idRenderMatrix & src );
|
||||
static ID_INLINE void ApplyModelDepthHack( idRenderMatrix & src, float value );
|
||||
|
||||
// Offset and scale the given matrix such that the result matrix transforms the unit-cube to exactly cover the given bounds (and the inverse).
|
||||
static void OffsetScaleForBounds( const idRenderMatrix & src, const idBounds & bounds, idRenderMatrix & out );
|
||||
static void InverseOffsetScaleForBounds( const idRenderMatrix & src, const idBounds & bounds, idRenderMatrix & out );
|
||||
|
||||
// Basic matrix operations.
|
||||
static void Transpose( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
static void Multiply( const idRenderMatrix & a, const idRenderMatrix & b, idRenderMatrix & out );
|
||||
static bool Inverse( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
static void InverseByTranspose( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
static bool InverseByDoubles( const idRenderMatrix & src, idRenderMatrix & out );
|
||||
|
||||
// Copy or create a matrix that is stored directly into four float4 vectors which is useful for directly setting vertex program uniforms.
|
||||
static void CopyMatrix( const idRenderMatrix & matrix, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3 );
|
||||
static void SetMVP( const idRenderMatrix & mvp, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3, bool & negativeDeterminant );
|
||||
static void SetMVPForBounds( const idRenderMatrix & mvp, const idBounds & bounds, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3, bool & negativeDeterminant );
|
||||
static void SetMVPForInverseProject( const idRenderMatrix & mvp, const idRenderMatrix & inverseProject, idVec4 & row0, idVec4 & row1, idVec4 & row2, idVec4 & row3, bool & negativeDeterminant );
|
||||
|
||||
// Cull to a Model-View-Projection (MVP) matrix.
|
||||
static bool CullPointToMVP( const idRenderMatrix & mvp, const idVec3 & point, bool zeroToOne = false );
|
||||
static bool CullPointToMVPbits( const idRenderMatrix & mvp, const idVec3 & point, byte * outBits, bool zeroToOne = false );
|
||||
static bool CullBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, bool zeroToOne = false );
|
||||
static bool CullBoundsToMVPbits( const idRenderMatrix & mvp, const idBounds & bounds, byte * outBits, bool zeroToOne = false );
|
||||
static bool CullExtrudedBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, bool zeroToOne = false );
|
||||
static bool CullExtrudedBoundsToMVPbits( const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, byte * outBits, bool zeroToOne = false );
|
||||
|
||||
// Calculate the projected bounds.
|
||||
static void ProjectedBounds( idBounds & projected, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
static void ProjectedNearClippedBounds( idBounds & projected, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
static void ProjectedFullyClippedBounds( idBounds & projected, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
|
||||
// Calculate the projected depth bounds.
|
||||
static void DepthBoundsForBounds( float & min, float & max, const idRenderMatrix & mvp, const idBounds & bounds, bool windowSpace = true );
|
||||
static void DepthBoundsForExtrudedBounds( float & min, float & max, const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, bool windowSpace = true );
|
||||
static void DepthBoundsForShadowBounds( float & min, float & max, const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & localLightOrigin, bool windowSpace = true );
|
||||
|
||||
// Create frustum planes and corners from a matrix.
|
||||
static void GetFrustumPlanes( idPlane planes[6], const idRenderMatrix & frustum, bool zeroToOne, bool normalize );
|
||||
static void GetFrustumCorners( frustumCorners_t & corners, const idRenderMatrix & frustumTransform, const idBounds & frustumBounds );
|
||||
static frustumCull_t CullFrustumCornersToPlane( const frustumCorners_t & corners, const idPlane & plane );
|
||||
|
||||
private:
|
||||
float m[16];
|
||||
};
|
||||
|
||||
extern const idRenderMatrix renderMatrix_identity;
|
||||
extern const idRenderMatrix renderMatrix_flipToOpenGL;
|
||||
extern const idRenderMatrix renderMatrix_windowSpaceToClipSpace;
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::idRenderMatrix
|
||||
========================
|
||||
*/
|
||||
ID_INLINE idRenderMatrix::idRenderMatrix( float a0, float a1, float a2, float a3,
|
||||
float b0, float b1, float b2, float b3,
|
||||
float c0, float c1, float c2, float c3,
|
||||
float d0, float d1, float d2, float d3 ) {
|
||||
m[0*4+0] = a0; m[0*4+1] = a1; m[0*4+2] = a2; m[0*4+3] = a3;
|
||||
m[1*4+0] = b0; m[1*4+1] = b1; m[1*4+2] = b2; m[1*4+3] = b3;
|
||||
m[2*4+0] = c0; m[2*4+1] = c1; m[2*4+2] = c2; m[2*4+3] = c3;
|
||||
m[3*4+0] = d0; m[3*4+1] = d1; m[3*4+2] = d2; m[3*4+3] = d3;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::Identity
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::Identity() {
|
||||
m[0*4+0] = 1.0f;
|
||||
m[0*4+1] = 0.0f;
|
||||
m[0*4+2] = 0.0f;
|
||||
m[0*4+3] = 0.0f;
|
||||
|
||||
m[1*4+0] = 0.0f;
|
||||
m[1*4+1] = 1.0f;
|
||||
m[1*4+2] = 0.0f;
|
||||
m[1*4+3] = 0.0f;
|
||||
|
||||
m[2*4+0] = 0.0f;
|
||||
m[2*4+1] = 0.0f;
|
||||
m[2*4+2] = 1.0f;
|
||||
m[2*4+3] = 0.0f;
|
||||
|
||||
m[3*4+0] = 0.0f;
|
||||
m[3*4+1] = 0.0f;
|
||||
m[3*4+2] = 0.0f;
|
||||
m[3*4+3] = 1.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsZero
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsZero( float epsilon ) const {
|
||||
for ( int i = 0; i < 16; i++ ) {
|
||||
if ( idMath::Fabs( m[i] ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsIdentity
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsIdentity( float epsilon ) const {
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
for ( int j = 0; j < 4; j++ ) {
|
||||
if ( i == j ) {
|
||||
if ( idMath::Fabs( m[i * 4 + j] - 1.0f ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( idMath::Fabs( m[i * 4 + j] ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsAffineTransform
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsAffineTransform( float epsilon ) const {
|
||||
if ( idMath::Fabs( m[3 * 4 + 0] ) > epsilon ||
|
||||
idMath::Fabs( m[3 * 4 + 1] ) > epsilon ||
|
||||
idMath::Fabs( m[3 * 4 + 2] ) > epsilon ||
|
||||
idMath::Fabs( m[3 * 4 + 3] - 1.0f ) > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::IsUniformScale
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::IsUniformScale( float epsilon ) const {
|
||||
float d0 = idMath::InvSqrt( m[0*4+0] * m[0*4+0] + m[1*4+0] * m[1*4+0] + m[2*4+0] * m[2*4+0] );
|
||||
float d1 = idMath::InvSqrt( m[0*4+1] * m[0*4+1] + m[1*4+1] * m[1*4+1] + m[2*4+1] * m[2*4+1] );
|
||||
float d2 = idMath::InvSqrt( m[0*4+2] * m[0*4+2] + m[1*4+2] * m[1*4+2] + m[2*4+2] * m[2*4+2] );
|
||||
if ( idMath::Fabs( d0 - d1 ) > epsilon ) { return false; }
|
||||
if ( idMath::Fabs( d1 - d2 ) > epsilon ) { return false; }
|
||||
if ( idMath::Fabs( d0 - d2 ) > epsilon ) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPoint
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPoint( const idVec3 & in, idVec3 & out ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
out[0] = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2] + matrix[0][3];
|
||||
out[1] = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2] + matrix[1][3];
|
||||
out[2] = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2] + matrix[2][3];
|
||||
assert( idMath::Fabs( in[0] * matrix[3][0] + in[1] * matrix[3][1] + in[2] * matrix[3][2] + matrix[3][3] - 1.0f ) < 0.01f );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPoint
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPoint( const idVec3 & in, idVec4 & out ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
out[0] = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2] + matrix[0][3];
|
||||
out[1] = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2] + matrix[1][3];
|
||||
out[2] = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2] + matrix[2][3];
|
||||
out[3] = in[0] * matrix[3][0] + in[1] * matrix[3][1] + in[2] * matrix[3][2] + matrix[3][3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPoint
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPoint( const idVec4 & in, idVec4 & out ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
out[0] = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2] + in[3] * matrix[0][3];
|
||||
out[1] = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2] + in[3] * matrix[1][3];
|
||||
out[2] = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2] + in[3] * matrix[2][3];
|
||||
out[3] = in[0] * matrix[3][0] + in[1] * matrix[3][1] + in[2] * matrix[3][2] + in[3] * matrix[3][3];
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformDir
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const {
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2];
|
||||
float p1 = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2];
|
||||
float p2 = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformPlane
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformPlane( const idPlane & in, idPlane & out, bool normalize ) const {
|
||||
assert( IsUniformScale( 0.01f ) );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[0][1] + in[2] * matrix[0][2];
|
||||
float p1 = in[0] * matrix[1][0] + in[1] * matrix[1][1] + in[2] * matrix[1][2];
|
||||
float p2 = in[0] * matrix[2][0] + in[1] * matrix[2][1] + in[2] * matrix[2][2];
|
||||
float d0 = matrix[0][3] - p0 * in[3];
|
||||
float d1 = matrix[1][3] - p1 * in[3];
|
||||
float d2 = matrix[2][3] - p2 * in[3];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
out[3] = - p0 * d0 - p1 * d1 - p2 * d2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::InverseTransformDir
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::InverseTransformDir( const idVec3 & in, idVec3 & out, bool normalize ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[1][0] + in[2] * matrix[2][0];
|
||||
float p1 = in[0] * matrix[0][1] + in[1] * matrix[1][1] + in[2] * matrix[2][1];
|
||||
float p2 = in[0] * matrix[0][2] + in[1] * matrix[1][2] + in[2] * matrix[2][2];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::InverseTransformPlane
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::InverseTransformPlane( const idPlane & in, idPlane & out, bool normalize ) const {
|
||||
assert( in.ToFloatPtr() != out.ToFloatPtr() );
|
||||
const idRenderMatrix & matrix = *this;
|
||||
float p0 = in[0] * matrix[0][0] + in[1] * matrix[1][0] + in[2] * matrix[2][0] + in[3] * matrix[3][0];
|
||||
float p1 = in[0] * matrix[0][1] + in[1] * matrix[1][1] + in[2] * matrix[2][1] + in[3] * matrix[3][1];
|
||||
float p2 = in[0] * matrix[0][2] + in[1] * matrix[1][2] + in[2] * matrix[2][2] + in[3] * matrix[3][2];
|
||||
float p3 = in[0] * matrix[0][3] + in[1] * matrix[1][3] + in[2] * matrix[2][3] + in[3] * matrix[3][3];
|
||||
if ( normalize ) {
|
||||
float r = idMath::InvSqrt( p0 * p0 + p1 * p1 + p2 * p2 );
|
||||
p0 *= r;
|
||||
p1 *= r;
|
||||
p2 *= r;
|
||||
p3 *= r;
|
||||
}
|
||||
out[0] = p0;
|
||||
out[1] = p1;
|
||||
out[2] = p2;
|
||||
out[3] = p3;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformModelToClip
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformModelToClip( const idVec3 & src, const idRenderMatrix & modelMatrix, const idRenderMatrix & projectionMatrix, idVec4 & eye, idVec4 & clip ) {
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
eye[i] = modelMatrix[i][0] * src[0] +
|
||||
modelMatrix[i][1] * src[1] +
|
||||
modelMatrix[i][2] * src[2] +
|
||||
modelMatrix[i][3];
|
||||
}
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
clip[i] = projectionMatrix[i][0] * eye[0] +
|
||||
projectionMatrix[i][1] * eye[1] +
|
||||
projectionMatrix[i][2] * eye[2] +
|
||||
projectionMatrix[i][3] * eye[3];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::TransformClipToDevice
|
||||
|
||||
Clip to normalized device coordinates.
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::TransformClipToDevice( const idVec4 & clip, idVec3 & ndc ) {
|
||||
assert( idMath::Fabs( clip[3] ) > idMath::FLT_SMALLEST_NON_DENORMAL );
|
||||
float r = 1.0f / clip[3];
|
||||
ndc[0] = clip[0] * r;
|
||||
ndc[1] = clip[1] * r;
|
||||
ndc[2] = clip[2] * r;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::ApplyDepthHack
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::ApplyDepthHack( idRenderMatrix & src ) {
|
||||
// scale projected z by 25%
|
||||
src.m[2*4+0] *= 0.25f;
|
||||
src.m[2*4+1] *= 0.25f;
|
||||
src.m[2*4+2] *= 0.25f;
|
||||
src.m[2*4+3] *= 0.25f;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::ApplyModelDepthHack
|
||||
========================
|
||||
*/
|
||||
ID_INLINE void idRenderMatrix::ApplyModelDepthHack( idRenderMatrix & src, float value ) {
|
||||
// offset projected z
|
||||
src.m[2*4+3] -= value;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::CullPointToMVP
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::CullPointToMVP( const idRenderMatrix & mvp, const idVec3 & point, bool zeroToOne ) {
|
||||
byte bits;
|
||||
return CullPointToMVPbits( mvp, point, &bits, zeroToOne );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::CullBoundsToMVP
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::CullBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, bool zeroToOne ) {
|
||||
byte bits;
|
||||
return CullBoundsToMVPbits( mvp, bounds, &bits, zeroToOne );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idRenderMatrix::CullExtrudedBoundsToMVP
|
||||
========================
|
||||
*/
|
||||
ID_INLINE bool idRenderMatrix::CullExtrudedBoundsToMVP( const idRenderMatrix & mvp, const idBounds & bounds, const idVec3 & extrudeDirection, const idPlane & clipPlane, bool zeroToOne ) {
|
||||
byte bits;
|
||||
return CullExtrudedBoundsToMVPbits( mvp, bounds, extrudeDirection, clipPlane, &bits, zeroToOne );
|
||||
}
|
||||
|
||||
#endif // !__RENDERMATRIX_H__
|
||||
929
neo/idlib/geometry/Surface.cpp
Normal file
929
neo/idlib/geometry/Surface.cpp
Normal file
@@ -0,0 +1,929 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
=================
|
||||
UpdateVertexIndex
|
||||
=================
|
||||
*/
|
||||
ID_INLINE int UpdateVertexIndex( int vertexIndexNum[2], int *vertexRemap, int *vertexCopyIndex, int vertNum ) {
|
||||
int s = INT32_SIGNBITSET( vertexRemap[vertNum] );
|
||||
vertexIndexNum[0] = vertexRemap[vertNum];
|
||||
vertexRemap[vertNum] = vertexIndexNum[s];
|
||||
vertexIndexNum[1] += s;
|
||||
vertexCopyIndex[vertexRemap[vertNum]] = vertNum;
|
||||
return vertexRemap[vertNum];
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::Split
|
||||
=================
|
||||
*/
|
||||
int idSurface::Split( const idPlane &plane, const float epsilon, idSurface **front, idSurface **back, int *frontOnPlaneEdges, int *backOnPlaneEdges ) const {
|
||||
float * dists;
|
||||
float f;
|
||||
byte * sides;
|
||||
int counts[3];
|
||||
int * edgeSplitVertex;
|
||||
int numEdgeSplitVertexes;
|
||||
int * vertexRemap[2];
|
||||
int vertexIndexNum[2][2];
|
||||
int * vertexCopyIndex[2];
|
||||
int * indexPtr[2];
|
||||
int indexNum[2];
|
||||
int * index;
|
||||
int * onPlaneEdges[2];
|
||||
int numOnPlaneEdges[2];
|
||||
int maxOnPlaneEdges;
|
||||
int i;
|
||||
idSurface * surface[2];
|
||||
idDrawVert v;
|
||||
|
||||
dists = (float *) _alloca( verts.Num() * sizeof( float ) );
|
||||
sides = (byte *) _alloca( verts.Num() * sizeof( byte ) );
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine side for each vertex
|
||||
for ( i = 0; i < verts.Num(); i++ ) {
|
||||
dists[i] = f = plane.Distance( verts[i].xyz );
|
||||
if ( f > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
} else if ( f < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
} else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
|
||||
*front = *back = NULL;
|
||||
|
||||
// if coplanar, put on the front side if the normals match
|
||||
if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
|
||||
|
||||
f = ( verts[indexes[1]].xyz - verts[indexes[0]].xyz ).Cross( verts[indexes[0]].xyz - verts[indexes[2]].xyz ) * plane.Normal();
|
||||
if ( IEEE_FLT_SIGNBITSET( f ) ) {
|
||||
*back = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_BACK;
|
||||
} else {
|
||||
*front = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
}
|
||||
// if nothing at the front of the clipping plane
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
*back = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_BACK;
|
||||
}
|
||||
// if nothing at the back of the clipping plane
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
*front = new (TAG_IDLIB_SURFACE) idSurface( *this );
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
|
||||
// allocate front and back surface
|
||||
*front = surface[0] = new (TAG_IDLIB_SURFACE) idSurface();
|
||||
*back = surface[1] = new (TAG_IDLIB_SURFACE) idSurface();
|
||||
|
||||
edgeSplitVertex = (int *) _alloca( edges.Num() * sizeof( int ) );
|
||||
numEdgeSplitVertexes = 0;
|
||||
|
||||
maxOnPlaneEdges = 4 * counts[SIDE_ON];
|
||||
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
|
||||
|
||||
// split edges
|
||||
for ( i = 0; i < edges.Num(); i++ ) {
|
||||
int v0 = edges[i].verts[0];
|
||||
int v1 = edges[i].verts[1];
|
||||
int sidesOr = ( sides[v0] | sides[v1] );
|
||||
|
||||
// if both vertexes are on the same side or one is on the clipping plane
|
||||
if ( !( sides[v0] ^ sides[v1] ) || ( sidesOr & SIDE_ON ) ) {
|
||||
edgeSplitVertex[i] = -1;
|
||||
counts[sidesOr & SIDE_BACK]++;
|
||||
counts[SIDE_ON] += ( sidesOr & SIDE_ON ) >> 1;
|
||||
} else {
|
||||
f = dists[v0] / ( dists[v0] - dists[v1] );
|
||||
v.LerpAll( verts[v0], verts[v1], f );
|
||||
edgeSplitVertex[i] = numEdgeSplitVertexes++;
|
||||
surface[0]->verts.Append( v );
|
||||
surface[1]->verts.Append( v );
|
||||
}
|
||||
}
|
||||
|
||||
// each edge is shared by at most two triangles, as such there can never be more indexes than twice the number of edges
|
||||
surface[0]->indexes.Resize( ( ( counts[SIDE_FRONT] + counts[SIDE_ON] ) * 2 ) + ( numEdgeSplitVertexes * 4 ) );
|
||||
surface[1]->indexes.Resize( ( ( counts[SIDE_BACK] + counts[SIDE_ON] ) * 2 ) + ( numEdgeSplitVertexes * 4 ) );
|
||||
|
||||
// allocate indexes to construct the triangle indexes for the front and back surface
|
||||
vertexRemap[0] = (int *) _alloca( verts.Num() * sizeof( int ) );
|
||||
memset( vertexRemap[0], -1, verts.Num() * sizeof( int ) );
|
||||
vertexRemap[1] = (int *) _alloca( verts.Num() * sizeof( int ) );
|
||||
memset( vertexRemap[1], -1, verts.Num() * sizeof( int ) );
|
||||
|
||||
vertexCopyIndex[0] = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
|
||||
vertexCopyIndex[1] = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
|
||||
|
||||
vertexIndexNum[0][0] = vertexIndexNum[1][0] = 0;
|
||||
vertexIndexNum[0][1] = vertexIndexNum[1][1] = numEdgeSplitVertexes;
|
||||
|
||||
indexPtr[0] = surface[0]->indexes.Ptr();
|
||||
indexPtr[1] = surface[1]->indexes.Ptr();
|
||||
indexNum[0] = surface[0]->indexes.Num();
|
||||
indexNum[1] = surface[1]->indexes.Num();
|
||||
|
||||
maxOnPlaneEdges += 4 * numEdgeSplitVertexes;
|
||||
// allocate one more in case no triangles are actually split which may happen for a disconnected surface
|
||||
onPlaneEdges[0] = (int *) _alloca( ( maxOnPlaneEdges + 1 ) * sizeof( int ) );
|
||||
onPlaneEdges[1] = (int *) _alloca( ( maxOnPlaneEdges + 1 ) * sizeof( int ) );
|
||||
numOnPlaneEdges[0] = numOnPlaneEdges[1] = 0;
|
||||
|
||||
// split surface triangles
|
||||
for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
|
||||
int e0, e1, e2, v0, v1, v2, s, n;
|
||||
|
||||
e0 = abs( edgeIndexes[i+0] );
|
||||
e1 = abs( edgeIndexes[i+1] );
|
||||
e2 = abs( edgeIndexes[i+2] );
|
||||
|
||||
v0 = indexes[i+0];
|
||||
v1 = indexes[i+1];
|
||||
v2 = indexes[i+2];
|
||||
|
||||
switch( ( INT32_SIGNBITSET( edgeSplitVertex[e0] ) | ( INT32_SIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INT32_SIGNBITSET( edgeSplitVertex[e2] ) << 2 ) ) ^ 7 ) {
|
||||
case 0: { // no edges split
|
||||
if ( ( sides[v0] & sides[v1] & sides[v2] ) & SIDE_ON ) {
|
||||
// coplanar
|
||||
f = ( verts[v1].xyz - verts[v0].xyz ).Cross( verts[v0].xyz - verts[v2].xyz ) * plane.Normal();
|
||||
s = IEEE_FLT_SIGNBITSET( f );
|
||||
} else {
|
||||
s = ( sides[v0] | sides[v1] | sides[v2] ) & SIDE_BACK;
|
||||
}
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]] = n;
|
||||
numOnPlaneEdges[s] += ( sides[v0] & sides[v1] ) >> 1;
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]] = n+1;
|
||||
numOnPlaneEdges[s] += ( sides[v1] & sides[v2] ) >> 1;
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]] = n+2;
|
||||
numOnPlaneEdges[s] += ( sides[v2] & sides[v0] ) >> 1;
|
||||
index = indexPtr[s];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
case 1: { // first edge split
|
||||
s = sides[v0] & SIDE_BACK;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e0];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
indexNum[s] = n;
|
||||
s ^= 1;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
index[n++] = edgeSplitVertex[e0];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
case 2: { // second edge split
|
||||
s = sides[v1] & SIDE_BACK;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
indexNum[s] = n;
|
||||
s ^= 1;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
case 3: { // first and second edge split
|
||||
s = sides[v1] & SIDE_BACK;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = edgeSplitVertex[e0];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
indexNum[s] = n;
|
||||
s ^= 1;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e0];
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
case 4: { // third edge split
|
||||
s = sides[v2] & SIDE_BACK;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
indexNum[s] = n;
|
||||
s ^= 1;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
case 5: { // first and third edge split
|
||||
s = sides[v0] & SIDE_BACK;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e0];
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
indexNum[s] = n;
|
||||
s ^= 1;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
index[n++] = edgeSplitVertex[e0];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
case 6: { // second and third edge split
|
||||
s = sides[v2] & SIDE_BACK;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
|
||||
indexNum[s] = n;
|
||||
s ^= 1;
|
||||
n = indexNum[s];
|
||||
onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
|
||||
index = indexPtr[s];
|
||||
index[n++] = edgeSplitVertex[e1];
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
|
||||
index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
|
||||
index[n++] = edgeSplitVertex[e2];
|
||||
indexNum[s] = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
surface[0]->indexes.SetNum( indexNum[0] );
|
||||
surface[1]->indexes.SetNum( indexNum[1] );
|
||||
|
||||
// copy vertexes
|
||||
surface[0]->verts.SetNum( vertexIndexNum[0][1] );
|
||||
index = vertexCopyIndex[0];
|
||||
for ( i = numEdgeSplitVertexes; i < surface[0]->verts.Num(); i++ ) {
|
||||
surface[0]->verts[i] = verts[index[i]];
|
||||
}
|
||||
surface[1]->verts.SetNum( vertexIndexNum[1][1] );
|
||||
index = vertexCopyIndex[1];
|
||||
for ( i = numEdgeSplitVertexes; i < surface[1]->verts.Num(); i++ ) {
|
||||
surface[1]->verts[i] = verts[index[i]];
|
||||
}
|
||||
|
||||
// generate edge indexes
|
||||
surface[0]->GenerateEdgeIndexes();
|
||||
surface[1]->GenerateEdgeIndexes();
|
||||
|
||||
if ( frontOnPlaneEdges ) {
|
||||
memcpy( frontOnPlaneEdges, onPlaneEdges[0], numOnPlaneEdges[0] * sizeof( int ) );
|
||||
frontOnPlaneEdges[numOnPlaneEdges[0]] = -1;
|
||||
}
|
||||
|
||||
if ( backOnPlaneEdges ) {
|
||||
memcpy( backOnPlaneEdges, onPlaneEdges[1], numOnPlaneEdges[1] * sizeof( int ) );
|
||||
backOnPlaneEdges[numOnPlaneEdges[1]] = -1;
|
||||
}
|
||||
|
||||
return SIDE_CROSS;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::ClipInPlace
|
||||
=================
|
||||
*/
|
||||
bool idSurface::ClipInPlace( const idPlane &plane, const float epsilon, const bool keepOn ) {
|
||||
float * dists;
|
||||
float f;
|
||||
byte * sides;
|
||||
int counts[3];
|
||||
int i;
|
||||
int * edgeSplitVertex;
|
||||
int * vertexRemap;
|
||||
int vertexIndexNum[2];
|
||||
int * vertexCopyIndex;
|
||||
int * indexPtr;
|
||||
int indexNum;
|
||||
int numEdgeSplitVertexes;
|
||||
idDrawVert v;
|
||||
idList<idDrawVert, TAG_IDLIB_LIST_SURFACE> newVerts;
|
||||
idList<int, TAG_IDLIB_LIST_SURFACE> newIndexes;
|
||||
|
||||
dists = (float *) _alloca( verts.Num() * sizeof( float ) );
|
||||
sides = (byte *) _alloca( verts.Num() * sizeof( byte ) );
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine side for each vertex
|
||||
for ( i = 0; i < verts.Num(); i++ ) {
|
||||
dists[i] = f = plane.Distance( verts[i].xyz );
|
||||
if ( f > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
} else if ( f < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
} else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
|
||||
// if coplanar, put on the front side if the normals match
|
||||
if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
|
||||
|
||||
f = ( verts[indexes[1]].xyz - verts[indexes[0]].xyz ).Cross( verts[indexes[0]].xyz - verts[indexes[2]].xyz ) * plane.Normal();
|
||||
if ( IEEE_FLT_SIGNBITSET( f ) ) {
|
||||
Clear();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// if nothing at the front of the clipping plane
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
// if nothing at the back of the clipping plane
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
edgeSplitVertex = (int *) _alloca( edges.Num() * sizeof( int ) );
|
||||
numEdgeSplitVertexes = 0;
|
||||
|
||||
counts[SIDE_FRONT] = counts[SIDE_BACK] = 0;
|
||||
|
||||
// split edges
|
||||
for ( i = 0; i < edges.Num(); i++ ) {
|
||||
int v0 = edges[i].verts[0];
|
||||
int v1 = edges[i].verts[1];
|
||||
|
||||
// if both vertexes are on the same side or one is on the clipping plane
|
||||
if ( !( sides[v0] ^ sides[v1] ) || ( ( sides[v0] | sides[v1] ) & SIDE_ON ) ) {
|
||||
edgeSplitVertex[i] = -1;
|
||||
counts[(sides[v0]|sides[v1]) & SIDE_BACK]++;
|
||||
} else {
|
||||
f = dists[v0] / ( dists[v0] - dists[v1] );
|
||||
v.LerpAll( verts[v0], verts[v1], f );
|
||||
edgeSplitVertex[i] = numEdgeSplitVertexes++;
|
||||
newVerts.Append( v );
|
||||
}
|
||||
}
|
||||
|
||||
// each edge is shared by at most two triangles, as such there can never be
|
||||
// more indexes than twice the number of edges
|
||||
newIndexes.Resize( ( counts[SIDE_FRONT] << 1 ) + ( numEdgeSplitVertexes << 2 ) );
|
||||
|
||||
// allocate indexes to construct the triangle indexes for the front and back surface
|
||||
vertexRemap = (int *) _alloca( verts.Num() * sizeof( int ) );
|
||||
memset( vertexRemap, -1, verts.Num() * sizeof( int ) );
|
||||
|
||||
vertexCopyIndex = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
|
||||
|
||||
vertexIndexNum[0] = 0;
|
||||
vertexIndexNum[1] = numEdgeSplitVertexes;
|
||||
|
||||
indexPtr = newIndexes.Ptr();
|
||||
indexNum = newIndexes.Num();
|
||||
|
||||
// split surface triangles
|
||||
for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
|
||||
int e0, e1, e2, v0, v1, v2;
|
||||
|
||||
e0 = abs( edgeIndexes[i+0] );
|
||||
e1 = abs( edgeIndexes[i+1] );
|
||||
e2 = abs( edgeIndexes[i+2] );
|
||||
|
||||
v0 = indexes[i+0];
|
||||
v1 = indexes[i+1];
|
||||
v2 = indexes[i+2];
|
||||
|
||||
switch( ( INT32_SIGNBITSET( edgeSplitVertex[e0] ) | ( INT32_SIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INT32_SIGNBITSET( edgeSplitVertex[e2] ) << 2 ) ) ^ 7 ) {
|
||||
case 0: { // no edges split
|
||||
if ( ( sides[v0] | sides[v1] | sides[v2] ) & SIDE_BACK ) {
|
||||
break;
|
||||
}
|
||||
if ( ( sides[v0] & sides[v1] & sides[v2] ) & SIDE_ON ) {
|
||||
// coplanar
|
||||
if ( !keepOn ) {
|
||||
break;
|
||||
}
|
||||
f = ( verts[v1].xyz - verts[v0].xyz ).Cross( verts[v0].xyz - verts[v2].xyz ) * plane.Normal();
|
||||
if ( IEEE_FLT_SIGNBITSET( f ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
break;
|
||||
}
|
||||
case 1: { // first edge split
|
||||
if ( !( sides[v0] & SIDE_BACK ) ) {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e0];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
} else {
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e0];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: { // second edge split
|
||||
if ( !( sides[v1] & SIDE_BACK ) ) {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
} else {
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: { // first and second edge split
|
||||
if ( !( sides[v1] & SIDE_BACK ) ) {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e0];
|
||||
} else {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e0];
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: { // third edge split
|
||||
if ( !( sides[v2] & SIDE_BACK ) ) {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
} else {
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: { // first and third edge split
|
||||
if ( !( sides[v0] & SIDE_BACK ) ) {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e0];
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
} else {
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e0];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: { // second and third edge split
|
||||
if ( !( sides[v2] & SIDE_BACK ) ) {
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
} else {
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e1];
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
|
||||
indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
|
||||
indexPtr[indexNum++] = edgeSplitVertex[e2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newIndexes.SetNum( indexNum );
|
||||
|
||||
// copy vertexes
|
||||
newVerts.SetNum( vertexIndexNum[1] );
|
||||
for ( i = numEdgeSplitVertexes; i < newVerts.Num(); i++ ) {
|
||||
newVerts[i] = verts[vertexCopyIndex[i]];
|
||||
}
|
||||
|
||||
// copy back to this surface
|
||||
indexes = newIndexes;
|
||||
verts = newVerts;
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idSurface::IsConnected
|
||||
=============
|
||||
*/
|
||||
bool idSurface::IsConnected() const {
|
||||
int i, j, numIslands, numTris;
|
||||
int queueStart, queueEnd;
|
||||
int *queue, *islandNum;
|
||||
int curTri, nextTri, edgeNum;
|
||||
const int *index;
|
||||
|
||||
numIslands = 0;
|
||||
numTris = indexes.Num() / 3;
|
||||
islandNum = (int *) _alloca16( numTris * sizeof( int ) );
|
||||
memset( islandNum, -1, numTris * sizeof( int ) );
|
||||
queue = (int *) _alloca16( numTris * sizeof( int ) );
|
||||
|
||||
for ( i = 0; i < numTris; i++ ) {
|
||||
|
||||
if ( islandNum[i] != -1 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queueStart = 0;
|
||||
queueEnd = 1;
|
||||
queue[0] = i;
|
||||
islandNum[i] = numIslands;
|
||||
|
||||
for ( curTri = queue[queueStart]; queueStart < queueEnd; curTri = queue[++queueStart] ) {
|
||||
|
||||
index = &edgeIndexes[curTri * 3];
|
||||
|
||||
for ( j = 0; j < 3; j++ ) {
|
||||
|
||||
edgeNum = index[j];
|
||||
nextTri = edges[abs(edgeNum)].tris[INT32_SIGNBITNOTSET(edgeNum)];
|
||||
|
||||
if ( nextTri == -1 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nextTri /= 3;
|
||||
|
||||
if ( islandNum[nextTri] != -1 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queue[queueEnd++] = nextTri;
|
||||
islandNum[nextTri] = numIslands;
|
||||
}
|
||||
}
|
||||
numIslands++;
|
||||
}
|
||||
|
||||
return ( numIslands == 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::IsClosed
|
||||
=================
|
||||
*/
|
||||
bool idSurface::IsClosed() const {
|
||||
for ( int i = 0; i < edges.Num(); i++ ) {
|
||||
if ( edges[i].tris[0] < 0 || edges[i].tris[1] < 0 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idSurface::IsPolytope
|
||||
=============
|
||||
*/
|
||||
bool idSurface::IsPolytope( const float epsilon ) const {
|
||||
int i, j;
|
||||
idPlane plane;
|
||||
|
||||
if ( !IsClosed() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( i = 0; i < indexes.Num(); i += 3 ) {
|
||||
plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
|
||||
|
||||
for ( j = 0; j < verts.Num(); j++ ) {
|
||||
if ( plane.Side( verts[j].xyz, epsilon ) == SIDE_FRONT ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idSurface::PlaneDistance
|
||||
=============
|
||||
*/
|
||||
float idSurface::PlaneDistance( const idPlane &plane ) const {
|
||||
int i;
|
||||
float d, min, max;
|
||||
|
||||
min = idMath::INFINITY;
|
||||
max = -min;
|
||||
for ( i = 0; i < verts.Num(); i++ ) {
|
||||
d = plane.Distance( verts[i].xyz );
|
||||
if ( d < min ) {
|
||||
min = d;
|
||||
if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
if ( d > max ) {
|
||||
max = d;
|
||||
if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
|
||||
return min;
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITSET( max ) ) {
|
||||
return max;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idSurface::PlaneSide
|
||||
=============
|
||||
*/
|
||||
int idSurface::PlaneSide( const idPlane &plane, const float epsilon ) const {
|
||||
bool front, back;
|
||||
int i;
|
||||
float d;
|
||||
|
||||
front = false;
|
||||
back = false;
|
||||
for ( i = 0; i < verts.Num(); i++ ) {
|
||||
d = plane.Distance( verts[i].xyz );
|
||||
if ( d < -epsilon ) {
|
||||
if ( front ) {
|
||||
return SIDE_CROSS;
|
||||
}
|
||||
back = true;
|
||||
continue;
|
||||
}
|
||||
else if ( d > epsilon ) {
|
||||
if ( back ) {
|
||||
return SIDE_CROSS;
|
||||
}
|
||||
front = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( back ) {
|
||||
return SIDE_BACK;
|
||||
}
|
||||
if ( front ) {
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
return SIDE_ON;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::LineIntersection
|
||||
=================
|
||||
*/
|
||||
bool idSurface::LineIntersection( const idVec3 &start, const idVec3 &end, bool backFaceCull ) const {
|
||||
float scale;
|
||||
|
||||
RayIntersection( start, end - start, scale, false );
|
||||
return ( scale >= 0.0f && scale <= 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::RayIntersection
|
||||
=================
|
||||
*/
|
||||
bool idSurface::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull ) const {
|
||||
int i, i0, i1, i2, s0, s1, s2;
|
||||
float d, s;
|
||||
byte *sidedness;
|
||||
idPluecker rayPl, pl;
|
||||
idPlane plane;
|
||||
|
||||
sidedness = (byte *)_alloca( edges.Num() * sizeof(byte) );
|
||||
scale = idMath::INFINITY;
|
||||
|
||||
rayPl.FromRay( start, dir );
|
||||
|
||||
// ray sidedness for edges
|
||||
for ( i = 0; i < edges.Num(); i++ ) {
|
||||
pl.FromLine( verts[ edges[i].verts[1] ].xyz, verts[ edges[i].verts[0] ].xyz );
|
||||
d = pl.PermutedInnerProduct( rayPl );
|
||||
sidedness[ i ] = IEEE_FLT_SIGNBITSET( d );
|
||||
}
|
||||
|
||||
// test triangles
|
||||
for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
|
||||
i0 = edgeIndexes[i+0];
|
||||
i1 = edgeIndexes[i+1];
|
||||
i2 = edgeIndexes[i+2];
|
||||
s0 = sidedness[abs(i0)] ^ INT32_SIGNBITSET( i0 );
|
||||
s1 = sidedness[abs(i1)] ^ INT32_SIGNBITSET( i1 );
|
||||
s2 = sidedness[abs(i2)] ^ INT32_SIGNBITSET( i2 );
|
||||
|
||||
if ( s0 & s1 & s2 ) {
|
||||
plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
|
||||
plane.RayIntersection( start, dir, s );
|
||||
if ( idMath::Fabs( s ) < idMath::Fabs( scale ) ) {
|
||||
scale = s;
|
||||
}
|
||||
} else if ( !backFaceCull && !(s0 | s1 | s2) ) {
|
||||
plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
|
||||
plane.RayIntersection( start, dir, s );
|
||||
if ( idMath::Fabs( s ) < idMath::Fabs( scale ) ) {
|
||||
scale = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( idMath::Fabs( scale ) < idMath::INFINITY ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::GenerateEdgeIndexes
|
||||
|
||||
Assumes each edge is shared by at most two triangles.
|
||||
=================
|
||||
*/
|
||||
void idSurface::GenerateEdgeIndexes() {
|
||||
int i, j, i0, i1, i2, s, v0, v1, edgeNum;
|
||||
int *index, *vertexEdges, *edgeChain;
|
||||
surfaceEdge_t e[3];
|
||||
|
||||
vertexEdges = (int *) _alloca16( verts.Num() * sizeof( int ) );
|
||||
memset( vertexEdges, -1, verts.Num() * sizeof( int ) );
|
||||
edgeChain = (int *) _alloca16( indexes.Num() * sizeof( int ) );
|
||||
|
||||
edgeIndexes.SetNum( indexes.Num() );
|
||||
|
||||
edges.Clear();
|
||||
|
||||
// the first edge is a dummy
|
||||
e[0].verts[0] = e[0].verts[1] = e[0].tris[0] = e[0].tris[1] = 0;
|
||||
edges.Append( e[0] );
|
||||
|
||||
for ( i = 0; i < indexes.Num(); i += 3 ) {
|
||||
index = indexes.Ptr() + i;
|
||||
// vertex numbers
|
||||
i0 = index[0];
|
||||
i1 = index[1];
|
||||
i2 = index[2];
|
||||
// setup edges each with smallest vertex number first
|
||||
s = INT32_SIGNBITSET(i1 - i0);
|
||||
e[0].verts[0] = index[s];
|
||||
e[0].verts[1] = index[s^1];
|
||||
s = INT32_SIGNBITSET(i2 - i1) + 1;
|
||||
e[1].verts[0] = index[s];
|
||||
e[1].verts[1] = index[s^3];
|
||||
s = INT32_SIGNBITSET(i2 - i0) << 1;
|
||||
e[2].verts[0] = index[s];
|
||||
e[2].verts[1] = index[s^2];
|
||||
// get edges
|
||||
for ( j = 0; j < 3; j++ ) {
|
||||
v0 = e[j].verts[0];
|
||||
v1 = e[j].verts[1];
|
||||
for ( edgeNum = vertexEdges[v0]; edgeNum >= 0; edgeNum = edgeChain[edgeNum] ) {
|
||||
if ( edges[edgeNum].verts[1] == v1 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the edge does not yet exist
|
||||
if ( edgeNum < 0 ) {
|
||||
e[j].tris[0] = e[j].tris[1] = -1;
|
||||
edgeNum = edges.Append( e[j] );
|
||||
edgeChain[edgeNum] = vertexEdges[v0];
|
||||
vertexEdges[v0] = edgeNum;
|
||||
}
|
||||
// update edge index and edge tri references
|
||||
if ( index[j] == v0 ) {
|
||||
assert( edges[edgeNum].tris[0] == -1 ); // edge may not be shared by more than two triangles
|
||||
edges[edgeNum].tris[0] = i;
|
||||
edgeIndexes[i+j] = edgeNum;
|
||||
} else {
|
||||
assert( edges[edgeNum].tris[1] == -1 ); // edge may not be shared by more than two triangles
|
||||
edges[edgeNum].tris[1] = i;
|
||||
edgeIndexes[i+j] = -edgeNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::FindEdge
|
||||
=================
|
||||
*/
|
||||
int idSurface::FindEdge( int v1, int v2 ) const {
|
||||
int i, firstVert, secondVert;
|
||||
|
||||
if ( v1 < v2 ) {
|
||||
firstVert = v1;
|
||||
secondVert = v2;
|
||||
} else {
|
||||
firstVert = v2;
|
||||
secondVert = v1;
|
||||
}
|
||||
for ( i = 1; i < edges.Num(); i++ ) {
|
||||
if ( edges[i].verts[0] == firstVert ) {
|
||||
if ( edges[i].verts[1] == secondVert ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( i < edges.Num() ) {
|
||||
return v1 < v2 ? i : -i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
219
neo/idlib/geometry/Surface.h
Normal file
219
neo/idlib/geometry/Surface.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SURFACE_H__
|
||||
#define __SURFACE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Surface base class.
|
||||
|
||||
A surface is tesselated to a triangle mesh with each edge shared by
|
||||
at most two triangles.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
typedef struct surfaceEdge_s {
|
||||
int verts[2]; // edge vertices always with ( verts[0] < verts[1] )
|
||||
int tris[2]; // edge triangles
|
||||
} surfaceEdge_t;
|
||||
|
||||
|
||||
class idSurface {
|
||||
public:
|
||||
idSurface();
|
||||
explicit idSurface( const idSurface &surf );
|
||||
explicit idSurface( const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes );
|
||||
~idSurface();
|
||||
|
||||
const idDrawVert & operator[]( const int index ) const;
|
||||
idDrawVert & operator[]( const int index );
|
||||
idSurface & operator+=( const idSurface &surf );
|
||||
|
||||
int GetNumIndexes() const { return indexes.Num(); }
|
||||
const int * GetIndexes() const { return indexes.Ptr(); }
|
||||
int GetNumVertices() const { return verts.Num(); }
|
||||
const idDrawVert * GetVertices() const { return verts.Ptr(); }
|
||||
const int * GetEdgeIndexes() const { return edgeIndexes.Ptr(); }
|
||||
const surfaceEdge_t * GetEdges() const { return edges.Ptr(); }
|
||||
|
||||
void Clear();
|
||||
void TranslateSelf( const idVec3 &translation );
|
||||
void RotateSelf( const idMat3 &rotation );
|
||||
|
||||
// splits the surface into a front and back surface, the surface itself stays unchanged
|
||||
// frontOnPlaneEdges and backOnPlaneEdges optionally store the indexes to the edges that lay on the split plane
|
||||
// returns a SIDE_?
|
||||
int Split( const idPlane &plane, const float epsilon, idSurface **front, idSurface **back, int *frontOnPlaneEdges = NULL, int *backOnPlaneEdges = NULL ) const;
|
||||
// cuts off the part at the back side of the plane, returns true if some part was at the front
|
||||
// if there is nothing at the front the number of points is set to zero
|
||||
bool ClipInPlace( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
|
||||
|
||||
// returns true if each triangle can be reached from any other triangle by a traversal
|
||||
bool IsConnected() const;
|
||||
// returns true if the surface is closed
|
||||
bool IsClosed() const;
|
||||
// returns true if the surface is a convex hull
|
||||
bool IsPolytope( const float epsilon = 0.1f ) const;
|
||||
|
||||
float PlaneDistance( const idPlane &plane ) const;
|
||||
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
|
||||
|
||||
// returns true if the line intersects one of the surface triangles
|
||||
bool LineIntersection( const idVec3 &start, const idVec3 &end, bool backFaceCull = false ) const;
|
||||
// intersection point is start + dir * scale
|
||||
bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull = false ) const;
|
||||
|
||||
protected:
|
||||
idList<idDrawVert, TAG_IDLIB_LIST_SURFACE> verts; // vertices
|
||||
idList<int, TAG_IDLIB_LIST_SURFACE> indexes; // 3 references to vertices for each triangle
|
||||
idList<surfaceEdge_t, TAG_IDLIB_LIST_SURFACE> edges; // edges
|
||||
idList<int, TAG_IDLIB_LIST_SURFACE> edgeIndexes; // 3 references to edges for each triangle, may be negative for reversed edge
|
||||
|
||||
protected:
|
||||
void GenerateEdgeIndexes();
|
||||
int FindEdge( int v1, int v2 ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface::idSurface
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface::idSurface() {
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::idSurface
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idSurface::idSurface( const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) {
|
||||
assert( verts != NULL && indexes != NULL && numVerts > 0 && numIndexes > 0 );
|
||||
this->verts.SetNum( numVerts );
|
||||
memcpy( this->verts.Ptr(), verts, numVerts * sizeof( verts[0] ) );
|
||||
this->indexes.SetNum( numIndexes );
|
||||
memcpy( this->indexes.Ptr(), indexes, numIndexes * sizeof( indexes[0] ) );
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface::idSurface
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface::idSurface( const idSurface &surf ) {
|
||||
this->verts = surf.verts;
|
||||
this->indexes = surf.indexes;
|
||||
this->edges = surf.edges;
|
||||
this->edgeIndexes = surf.edgeIndexes;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface::~idSurface
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface::~idSurface() {
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::operator[]
|
||||
=================
|
||||
*/
|
||||
ID_INLINE const idDrawVert &idSurface::operator[]( const int index ) const {
|
||||
return verts[ index ];
|
||||
};
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::operator[]
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idDrawVert &idSurface::operator[]( const int index ) {
|
||||
return verts[ index ];
|
||||
};
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::operator+=
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idSurface &idSurface::operator+=( const idSurface &surf ) {
|
||||
int i, m, n;
|
||||
n = verts.Num();
|
||||
m = indexes.Num();
|
||||
verts.Append( surf.verts ); // merge verts where possible ?
|
||||
indexes.Append( surf.indexes );
|
||||
for ( i = m; i < indexes.Num(); i++ ) {
|
||||
indexes[i] += n;
|
||||
}
|
||||
GenerateEdgeIndexes();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::Clear
|
||||
=================
|
||||
*/
|
||||
ID_INLINE void idSurface::Clear() {
|
||||
verts.Clear();
|
||||
indexes.Clear();
|
||||
edges.Clear();
|
||||
edgeIndexes.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::TranslateSelf
|
||||
=================
|
||||
*/
|
||||
ID_INLINE void idSurface::TranslateSelf( const idVec3 &translation ) {
|
||||
for ( int i = 0; i < verts.Num(); i++ ) {
|
||||
verts[i].xyz += translation;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface::RotateSelf
|
||||
=================
|
||||
*/
|
||||
ID_INLINE void idSurface::RotateSelf( const idMat3 &rotation ) {
|
||||
for ( int i = 0; i < verts.Num(); i++ ) {
|
||||
verts[i].xyz *= rotation;
|
||||
verts[i].SetNormal( verts[i].GetNormal() * rotation );
|
||||
verts[i].SetTangent( verts[i].GetTangent() * rotation );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_H__ */
|
||||
698
neo/idlib/geometry/Surface_Patch.cpp
Normal file
698
neo/idlib/geometry/Surface_Patch.cpp
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::SetSize
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::SetSize( int patchWidth, int patchHeight ) {
|
||||
if ( patchWidth < 1 || patchWidth > maxWidth ) {
|
||||
idLib::common->FatalError("idSurface_Patch::SetSize: invalid patchWidth");
|
||||
}
|
||||
if ( patchHeight < 1 || patchHeight > maxHeight ) {
|
||||
idLib::common->FatalError("idSurface_Patch::SetSize: invalid patchHeight");
|
||||
}
|
||||
width = patchWidth;
|
||||
height = patchHeight;
|
||||
verts.SetNum( width * height );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::PutOnCurve
|
||||
|
||||
Expects an expanded patch.
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::PutOnCurve() {
|
||||
int i, j;
|
||||
idDrawVert prev, next;
|
||||
|
||||
assert( expanded == true );
|
||||
// put all the approximating points on the curve
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
for ( j = 1; j < height; j += 2 ) {
|
||||
LerpVert( verts[j*maxWidth+i], verts[(j+1)*maxWidth+i], prev );
|
||||
LerpVert( verts[j*maxWidth+i], verts[(j-1)*maxWidth+i], next );
|
||||
LerpVert( prev, next, verts[j*maxWidth+i] );
|
||||
}
|
||||
}
|
||||
|
||||
for ( j = 0; j < height; j++ ) {
|
||||
for ( i = 1; i < width; i += 2 ) {
|
||||
LerpVert( verts[j*maxWidth+i], verts[j*maxWidth+i+1], prev );
|
||||
LerpVert( verts[j*maxWidth+i], verts[j*maxWidth+i-1], next );
|
||||
LerpVert( prev, next, verts[j*maxWidth+i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idSurface_Patch::ProjectPointOntoVector
|
||||
================
|
||||
*/
|
||||
void idSurface_Patch::ProjectPointOntoVector( const idVec3 &point, const idVec3 &vStart, const idVec3 &vEnd, idVec3 &vProj ) {
|
||||
idVec3 pVec, vec;
|
||||
|
||||
pVec = point - vStart;
|
||||
vec = vEnd - vStart;
|
||||
vec.Normalize();
|
||||
// project onto the directional vector for this segment
|
||||
vProj = vStart + (pVec * vec) * vec;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idSurface_Patch::RemoveLinearColumnsRows
|
||||
|
||||
Expects an expanded patch.
|
||||
================
|
||||
*/
|
||||
void idSurface_Patch::RemoveLinearColumnsRows() {
|
||||
int i, j, k;
|
||||
float len, maxLength;
|
||||
idVec3 proj, dir;
|
||||
|
||||
assert( expanded == true );
|
||||
for ( j = 1; j < width - 1; j++ ) {
|
||||
maxLength = 0;
|
||||
for ( i = 0; i < height; i++ ) {
|
||||
idSurface_Patch::ProjectPointOntoVector( verts[i*maxWidth + j].xyz,
|
||||
verts[i*maxWidth + j-1].xyz, verts[i*maxWidth + j+1].xyz, proj);
|
||||
dir = verts[i*maxWidth + j].xyz - proj;
|
||||
len = dir.LengthSqr();
|
||||
if ( len > maxLength ) {
|
||||
maxLength = len;
|
||||
}
|
||||
}
|
||||
if ( maxLength < Square( 0.2f ) ) {
|
||||
width--;
|
||||
for ( i = 0; i < height; i++ ) {
|
||||
for ( k = j; k < width; k++ ) {
|
||||
verts[i*maxWidth + k] = verts[i*maxWidth + k+1];
|
||||
}
|
||||
}
|
||||
j--;
|
||||
}
|
||||
}
|
||||
for ( j = 1; j < height - 1; j++ ) {
|
||||
maxLength = 0;
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
idSurface_Patch::ProjectPointOntoVector( verts[j*maxWidth + i].xyz,
|
||||
verts[(j-1)*maxWidth + i].xyz, verts[(j+1)*maxWidth + i].xyz, proj);
|
||||
dir = verts[j*maxWidth + i].xyz - proj;
|
||||
len = dir.LengthSqr();
|
||||
if ( len > maxLength ) {
|
||||
maxLength = len;
|
||||
}
|
||||
}
|
||||
if ( maxLength < Square( 0.2f ) ) {
|
||||
height--;
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
for ( k = j; k < height; k++ ) {
|
||||
verts[k*maxWidth + i] = verts[(k+1)*maxWidth + i];
|
||||
}
|
||||
}
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idSurface_Patch::ResizeExpanded
|
||||
================
|
||||
*/
|
||||
void idSurface_Patch::ResizeExpanded( int newHeight, int newWidth ) {
|
||||
int i, j;
|
||||
|
||||
assert( expanded == true );
|
||||
if ( newHeight <= maxHeight && newWidth <= maxWidth ) {
|
||||
return;
|
||||
}
|
||||
if ( newHeight * newWidth > maxHeight * maxWidth ) {
|
||||
verts.SetNum( newHeight * newWidth );
|
||||
}
|
||||
// space out verts for new height and width
|
||||
for ( j = maxHeight-1; j >= 0; j-- ) {
|
||||
for ( i = maxWidth-1; i >= 0; i-- ) {
|
||||
verts[j*newWidth + i] = verts[j*maxWidth + i];
|
||||
}
|
||||
}
|
||||
maxHeight = newHeight;
|
||||
maxWidth = newWidth;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idSurface_Patch::Collapse
|
||||
================
|
||||
*/
|
||||
void idSurface_Patch::Collapse() {
|
||||
int i, j;
|
||||
|
||||
if ( !expanded ) {
|
||||
idLib::common->FatalError("idSurface_Patch::Collapse: patch not expanded");
|
||||
}
|
||||
expanded = false;
|
||||
if ( width != maxWidth ) {
|
||||
for ( j = 0; j < height; j++ ) {
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
verts[j*width + i] = verts[j*maxWidth + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
verts.SetNum( width * height );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idSurface_Patch::Expand
|
||||
================
|
||||
*/
|
||||
void idSurface_Patch::Expand() {
|
||||
int i, j;
|
||||
|
||||
if ( expanded ) {
|
||||
idLib::common->FatalError("idSurface_Patch::Expand: patch alread expanded");
|
||||
}
|
||||
expanded = true;
|
||||
verts.SetNum( maxWidth * maxHeight );
|
||||
if ( width != maxWidth ) {
|
||||
for ( j = height-1; j >= 0; j-- ) {
|
||||
for ( i = width-1; i >= 0; i-- ) {
|
||||
verts[j*maxWidth + i] = verts[j*width + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idSurface_Patch::LerpVert
|
||||
============
|
||||
*/
|
||||
void idSurface_Patch::LerpVert( const idDrawVert &a, const idDrawVert &b, idDrawVert &out ) const {
|
||||
out.xyz[0] = 0.5f * ( a.xyz[0] + b.xyz[0] );
|
||||
out.xyz[1] = 0.5f * ( a.xyz[1] + b.xyz[1] );
|
||||
out.xyz[2] = 0.5f * ( a.xyz[2] + b.xyz[2] );
|
||||
out.SetNormal( ( a.GetNormal() + b.GetNormal() ) * 0.5f );
|
||||
out.SetTexCoord( ( a.GetTexCoord() + b.GetTexCoord() ) * 0.5f );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::GenerateNormals
|
||||
|
||||
Handles all the complicated wrapping and degenerate cases
|
||||
Expects a Not expanded patch.
|
||||
=================
|
||||
*/
|
||||
#define COPLANAR_EPSILON 0.1f
|
||||
|
||||
void idSurface_Patch::GenerateNormals() {
|
||||
int i, j, k, dist;
|
||||
idVec3 norm;
|
||||
idVec3 sum;
|
||||
int count;
|
||||
idVec3 base;
|
||||
idVec3 delta;
|
||||
int x, y;
|
||||
idVec3 around[8], temp;
|
||||
bool good[8];
|
||||
bool wrapWidth, wrapHeight;
|
||||
static int neighbors[8][2] = {
|
||||
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
|
||||
};
|
||||
|
||||
assert( expanded == false );
|
||||
|
||||
//
|
||||
// if all points are coplanar, set all normals to that plane
|
||||
//
|
||||
idVec3 extent[3];
|
||||
float offset;
|
||||
|
||||
extent[0] = verts[width - 1].xyz - verts[0].xyz;
|
||||
extent[1] = verts[(height-1) * width + width - 1].xyz - verts[0].xyz;
|
||||
extent[2] = verts[(height-1) * width].xyz - verts[0].xyz;
|
||||
|
||||
norm = extent[0].Cross( extent[1] );
|
||||
if ( norm.LengthSqr() == 0.0f ) {
|
||||
norm = extent[0].Cross( extent[2] );
|
||||
if ( norm.LengthSqr() == 0.0f ) {
|
||||
norm = extent[1].Cross( extent[2] );
|
||||
}
|
||||
}
|
||||
|
||||
// wrapped patched may not get a valid normal here
|
||||
if ( norm.Normalize() != 0.0f ) {
|
||||
|
||||
offset = verts[0].xyz * norm;
|
||||
for ( i = 1; i < width * height; i++ ) {
|
||||
float d = verts[i].xyz * norm;
|
||||
if ( idMath::Fabs( d - offset ) > COPLANAR_EPSILON ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i == width * height ) {
|
||||
// all are coplanar
|
||||
for ( i = 0; i < width * height; i++ ) {
|
||||
verts[i].SetNormal( norm );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check for wrapped edge cases, which should smooth across themselves
|
||||
wrapWidth = false;
|
||||
for ( i = 0; i < height; i++ ) {
|
||||
delta = verts[i * width].xyz - verts[i * width + width-1].xyz;
|
||||
if ( delta.LengthSqr() > Square( 1.0f ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i == height ) {
|
||||
wrapWidth = true;
|
||||
}
|
||||
|
||||
wrapHeight = false;
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
delta = verts[i].xyz - verts[(height-1) * width + i].xyz;
|
||||
if ( delta.LengthSqr() > Square( 1.0f ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i == width ) {
|
||||
wrapHeight = true;
|
||||
}
|
||||
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
for ( j = 0; j < height; j++ ) {
|
||||
count = 0;
|
||||
base = verts[j * width + i].xyz;
|
||||
for ( k = 0; k < 8; k++ ) {
|
||||
around[k] = vec3_origin;
|
||||
good[k] = false;
|
||||
|
||||
for ( dist = 1; dist <= 3; dist++ ) {
|
||||
x = i + neighbors[k][0] * dist;
|
||||
y = j + neighbors[k][1] * dist;
|
||||
if ( wrapWidth ) {
|
||||
if ( x < 0 ) {
|
||||
x = width - 1 + x;
|
||||
} else if ( x >= width ) {
|
||||
x = 1 + x - width;
|
||||
}
|
||||
}
|
||||
if ( wrapHeight ) {
|
||||
if ( y < 0 ) {
|
||||
y = height - 1 + y;
|
||||
} else if ( y >= height ) {
|
||||
y = 1 + y - height;
|
||||
}
|
||||
}
|
||||
|
||||
if ( x < 0 || x >= width || y < 0 || y >= height ) {
|
||||
break; // edge of patch
|
||||
}
|
||||
temp = verts[y * width + x].xyz - base;
|
||||
if ( temp.Normalize() == 0.0f ) {
|
||||
continue; // degenerate edge, get more dist
|
||||
} else {
|
||||
good[k] = true;
|
||||
around[k] = temp;
|
||||
break; // good edge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sum = vec3_origin;
|
||||
for ( k = 0; k < 8; k++ ) {
|
||||
if ( !good[k] || !good[(k+1)&7] ) {
|
||||
continue; // didn't get two points
|
||||
}
|
||||
norm = around[(k+1)&7].Cross( around[k] );
|
||||
if ( norm.Normalize() == 0.0f ) {
|
||||
continue;
|
||||
}
|
||||
sum += norm;
|
||||
count++;
|
||||
}
|
||||
if ( count == 0 ) {
|
||||
//idLib::common->Printf("bad normal\n");
|
||||
count = 1;
|
||||
}
|
||||
sum.Normalize();
|
||||
verts[j * width + i].SetNormal( sum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::GenerateIndexes
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::GenerateIndexes() {
|
||||
int i, j, v1, v2, v3, v4, index;
|
||||
|
||||
indexes.SetNum( (width-1) * (height-1) * 2 * 3 );
|
||||
index = 0;
|
||||
for ( i = 0; i < width - 1; i++ ) {
|
||||
for ( j = 0; j < height - 1; j++ ) {
|
||||
v1 = j * width + i;
|
||||
v2 = v1 + 1;
|
||||
v3 = v1 + width + 1;
|
||||
v4 = v1 + width;
|
||||
indexes[index++] = v1;
|
||||
indexes[index++] = v3;
|
||||
indexes[index++] = v2;
|
||||
indexes[index++] = v1;
|
||||
indexes[index++] = v4;
|
||||
indexes[index++] = v3;
|
||||
}
|
||||
}
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idSurface_Patch::SampleSinglePatchPoint
|
||||
===============
|
||||
*/
|
||||
void idSurface_Patch::SampleSinglePatchPoint( const idDrawVert ctrl[3][3], float u, float v, idDrawVert *out ) const {
|
||||
float vCtrl[3][8];
|
||||
int vPoint;
|
||||
int axis;
|
||||
|
||||
// find the control points for the v coordinate
|
||||
for ( vPoint = 0; vPoint < 3; vPoint++ ) {
|
||||
for ( axis = 0; axis < 8; axis++ ) {
|
||||
float a, b, c;
|
||||
float qA, qB, qC;
|
||||
if ( axis < 3 ) {
|
||||
a = ctrl[0][vPoint].xyz[axis];
|
||||
b = ctrl[1][vPoint].xyz[axis];
|
||||
c = ctrl[2][vPoint].xyz[axis];
|
||||
} else if ( axis < 6 ) {
|
||||
a = ctrl[0][vPoint].GetNormal()[axis-3];
|
||||
b = ctrl[1][vPoint].GetNormal()[axis-3];
|
||||
c = ctrl[2][vPoint].GetNormal()[axis-3];
|
||||
} else {
|
||||
a = ctrl[0][vPoint].GetTexCoord()[axis-6];
|
||||
b = ctrl[1][vPoint].GetTexCoord()[axis-6];
|
||||
c = ctrl[2][vPoint].GetTexCoord()[axis-6];
|
||||
}
|
||||
qA = a - 2.0f * b + c;
|
||||
qB = 2.0f * b - 2.0f * a;
|
||||
qC = a;
|
||||
vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
|
||||
}
|
||||
}
|
||||
|
||||
// interpolate the v value
|
||||
for ( axis = 0; axis < 8; axis++ ) {
|
||||
float a, b, c;
|
||||
float qA, qB, qC;
|
||||
|
||||
a = vCtrl[0][axis];
|
||||
b = vCtrl[1][axis];
|
||||
c = vCtrl[2][axis];
|
||||
qA = a - 2.0f * b + c;
|
||||
qB = 2.0f * b - 2.0f * a;
|
||||
qC = a;
|
||||
|
||||
if ( axis < 3 ) {
|
||||
out->xyz[axis] = qA * v * v + qB * v + qC;
|
||||
} else if ( axis < 6 ) {
|
||||
idVec3 tempNormal = out->GetNormal();
|
||||
tempNormal[axis-3] = qA * v * v + qB * v + qC;
|
||||
out->SetNormal( tempNormal );
|
||||
//out->normal[axis-3] = qA * v * v + qB * v + qC;
|
||||
} else {
|
||||
idVec2 tempST = out->GetTexCoord();
|
||||
tempST[axis-6] = qA * v * v + qB * v + qC;
|
||||
out->SetTexCoord( tempST );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
idSurface_Patch::SampleSinglePatch
|
||||
===================
|
||||
*/
|
||||
void idSurface_Patch::SampleSinglePatch( const idDrawVert ctrl[3][3], int baseCol, int baseRow, int width, int horzSub, int vertSub, idDrawVert *outVerts ) const {
|
||||
int i, j;
|
||||
float u, v;
|
||||
|
||||
horzSub++;
|
||||
vertSub++;
|
||||
for ( i = 0; i < horzSub; i++ ) {
|
||||
for ( j = 0; j < vertSub; j++ ) {
|
||||
u = (float) i / ( horzSub - 1 );
|
||||
v = (float) j / ( vertSub - 1 );
|
||||
SampleSinglePatchPoint( ctrl, u, v, &outVerts[((baseRow + j) * width) + i + baseCol] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::SubdivideExplicit
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::SubdivideExplicit( int horzSubdivisions, int vertSubdivisions, bool genNormals, bool removeLinear ) {
|
||||
int i, j, k, l;
|
||||
idDrawVert sample[3][3];
|
||||
int outWidth = ((width - 1) / 2 * horzSubdivisions) + 1;
|
||||
int outHeight = ((height - 1) / 2 * vertSubdivisions) + 1;
|
||||
idDrawVert *dv = new (TAG_IDLIB_SURFACE) idDrawVert[ outWidth * outHeight ];
|
||||
|
||||
// generate normals for the control mesh
|
||||
if ( genNormals ) {
|
||||
GenerateNormals();
|
||||
}
|
||||
|
||||
int baseCol = 0;
|
||||
for ( i = 0; i + 2 < width; i += 2 ) {
|
||||
int baseRow = 0;
|
||||
for ( j = 0; j + 2 < height; j += 2 ) {
|
||||
for ( k = 0; k < 3; k++ ) {
|
||||
for ( l = 0; l < 3; l++ ) {
|
||||
sample[k][l] = verts[ ((j + l) * width) + i + k ];
|
||||
}
|
||||
}
|
||||
SampleSinglePatch( sample, baseCol, baseRow, outWidth, horzSubdivisions, vertSubdivisions, dv );
|
||||
baseRow += vertSubdivisions;
|
||||
}
|
||||
baseCol += horzSubdivisions;
|
||||
}
|
||||
verts.SetNum( outWidth * outHeight );
|
||||
for ( i = 0; i < outWidth * outHeight; i++ ) {
|
||||
verts[i] = dv[i];
|
||||
}
|
||||
|
||||
delete[] dv;
|
||||
|
||||
width = maxWidth = outWidth;
|
||||
height = maxHeight = outHeight;
|
||||
expanded = false;
|
||||
|
||||
if ( removeLinear ) {
|
||||
Expand();
|
||||
RemoveLinearColumnsRows();
|
||||
Collapse();
|
||||
}
|
||||
|
||||
// normalize all the lerped normals
|
||||
if ( genNormals ) {
|
||||
idVec3 tempNormal;
|
||||
for ( i = 0; i < width * height; i++ ) {
|
||||
tempNormal= verts[i].GetNormal();
|
||||
tempNormal.Normalize();
|
||||
verts[i].SetNormal( tempNormal );
|
||||
}
|
||||
}
|
||||
|
||||
GenerateIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::Subdivide
|
||||
=================
|
||||
*/
|
||||
void idSurface_Patch::Subdivide( float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals ) {
|
||||
int i, j, k, l;
|
||||
idDrawVert prev, next, mid;
|
||||
idVec3 prevxyz, nextxyz, midxyz;
|
||||
idVec3 delta;
|
||||
float maxHorizontalErrorSqr, maxVerticalErrorSqr, maxLengthSqr;
|
||||
|
||||
// generate normals for the control mesh
|
||||
if ( genNormals ) {
|
||||
GenerateNormals();
|
||||
}
|
||||
|
||||
maxHorizontalErrorSqr = Square( maxHorizontalError );
|
||||
maxVerticalErrorSqr = Square( maxVerticalError );
|
||||
maxLengthSqr = Square( maxLength );
|
||||
|
||||
Expand();
|
||||
|
||||
// horizontal subdivisions
|
||||
for ( j = 0; j + 2 < width; j += 2 ) {
|
||||
// check subdivided midpoints against control points
|
||||
for ( i = 0; i < height; i++ ) {
|
||||
for ( l = 0; l < 3; l++ ) {
|
||||
prevxyz[l] = verts[i*maxWidth + j+1].xyz[l] - verts[i*maxWidth + j ].xyz[l];
|
||||
nextxyz[l] = verts[i*maxWidth + j+2].xyz[l] - verts[i*maxWidth + j+1].xyz[l];
|
||||
midxyz[l] = (verts[i*maxWidth + j ].xyz[l] + verts[i*maxWidth + j+1].xyz[l] * 2.0f +
|
||||
verts[i*maxWidth + j+2].xyz[l] ) * 0.25f;
|
||||
}
|
||||
|
||||
if ( maxLength > 0.0f ) {
|
||||
// if the span length is too long, force a subdivision
|
||||
if ( prevxyz.LengthSqr() > maxLengthSqr || nextxyz.LengthSqr() > maxLengthSqr ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// see if this midpoint is off far enough to subdivide
|
||||
delta = verts[i*maxWidth + j+1].xyz - midxyz;
|
||||
if ( delta.LengthSqr() > maxHorizontalErrorSqr ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i == height ) {
|
||||
continue; // didn't need subdivision
|
||||
}
|
||||
|
||||
if ( width + 2 >= maxWidth ) {
|
||||
ResizeExpanded( maxHeight, maxWidth + 4 );
|
||||
}
|
||||
|
||||
// insert two columns and replace the peak
|
||||
width += 2;
|
||||
|
||||
for ( i = 0; i < height; i++ ) {
|
||||
idSurface_Patch::LerpVert( verts[i*maxWidth + j ], verts[i*maxWidth + j+1], prev );
|
||||
idSurface_Patch::LerpVert( verts[i*maxWidth + j+1], verts[i*maxWidth + j+2], next );
|
||||
idSurface_Patch::LerpVert( prev, next, mid );
|
||||
|
||||
for ( k = width - 1; k > j + 3; k-- ) {
|
||||
verts[i*maxWidth + k] = verts[i*maxWidth + k-2];
|
||||
}
|
||||
verts[i*maxWidth + j+1] = prev;
|
||||
verts[i*maxWidth + j+2] = mid;
|
||||
verts[i*maxWidth + j+3] = next;
|
||||
}
|
||||
|
||||
// back up and recheck this set again, it may need more subdivision
|
||||
j -= 2;
|
||||
}
|
||||
|
||||
// vertical subdivisions
|
||||
for ( j = 0; j + 2 < height; j += 2 ) {
|
||||
// check subdivided midpoints against control points
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
for ( l = 0; l < 3; l++ ) {
|
||||
prevxyz[l] = verts[(j+1)*maxWidth + i].xyz[l] - verts[j*maxWidth + i].xyz[l];
|
||||
nextxyz[l] = verts[(j+2)*maxWidth + i].xyz[l] - verts[(j+1)*maxWidth + i].xyz[l];
|
||||
midxyz[l] = (verts[j*maxWidth + i].xyz[l] + verts[(j+1)*maxWidth + i].xyz[l] * 2.0f +
|
||||
verts[(j+2)*maxWidth + i].xyz[l] ) * 0.25f;
|
||||
}
|
||||
|
||||
if ( maxLength > 0.0f ) {
|
||||
// if the span length is too long, force a subdivision
|
||||
if ( prevxyz.LengthSqr() > maxLengthSqr || nextxyz.LengthSqr() > maxLengthSqr ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// see if this midpoint is off far enough to subdivide
|
||||
delta = verts[(j+1)*maxWidth + i].xyz - midxyz;
|
||||
if ( delta.LengthSqr() > maxVerticalErrorSqr ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i == width ) {
|
||||
continue; // didn't need subdivision
|
||||
}
|
||||
|
||||
if ( height + 2 >= maxHeight ) {
|
||||
ResizeExpanded( maxHeight + 4, maxWidth );
|
||||
}
|
||||
|
||||
// insert two columns and replace the peak
|
||||
height += 2;
|
||||
|
||||
for ( i = 0; i < width; i++ ) {
|
||||
LerpVert( verts[j*maxWidth + i], verts[(j+1)*maxWidth + i], prev );
|
||||
LerpVert( verts[(j+1)*maxWidth + i], verts[(j+2)*maxWidth + i], next );
|
||||
LerpVert( prev, next, mid );
|
||||
|
||||
for ( k = height - 1; k > j + 3; k-- ) {
|
||||
verts[k*maxWidth + i] = verts[(k-2)*maxWidth + i];
|
||||
}
|
||||
verts[(j+1)*maxWidth + i] = prev;
|
||||
verts[(j+2)*maxWidth + i] = mid;
|
||||
verts[(j+3)*maxWidth + i] = next;
|
||||
}
|
||||
|
||||
// back up and recheck this set again, it may need more subdivision
|
||||
j -= 2;
|
||||
}
|
||||
|
||||
PutOnCurve();
|
||||
|
||||
RemoveLinearColumnsRows();
|
||||
|
||||
Collapse();
|
||||
|
||||
// normalize all the lerped normals
|
||||
if ( genNormals ) {
|
||||
idVec3 tempNormal;
|
||||
for ( i = 0; i < width * height; i++ ) {
|
||||
tempNormal = verts[i].GetNormal();
|
||||
tempNormal.Normalize();
|
||||
verts[i].SetNormal( tempNormal );
|
||||
}
|
||||
}
|
||||
|
||||
GenerateIndexes();
|
||||
}
|
||||
146
neo/idlib/geometry/Surface_Patch.h
Normal file
146
neo/idlib/geometry/Surface_Patch.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SURFACE_PATCH_H__
|
||||
#define __SURFACE_PATCH_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Bezier patch surface.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idSurface_Patch : public idSurface {
|
||||
|
||||
public:
|
||||
idSurface_Patch();
|
||||
idSurface_Patch( int maxPatchWidth, int maxPatchHeight );
|
||||
idSurface_Patch( const idSurface_Patch &patch );
|
||||
~idSurface_Patch();
|
||||
|
||||
void SetSize( int patchWidth, int patchHeight );
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
|
||||
// subdivide the patch mesh based on error
|
||||
void Subdivide( float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals = false );
|
||||
// subdivide the patch up to an explicit number of horizontal and vertical subdivisions
|
||||
void SubdivideExplicit( int horzSubdivisions, int vertSubdivisions, bool genNormals, bool removeLinear = false );
|
||||
|
||||
protected:
|
||||
int width; // width of patch
|
||||
int height; // height of patch
|
||||
int maxWidth; // maximum width allocated for
|
||||
int maxHeight; // maximum height allocated for
|
||||
bool expanded; // true if vertices are spaced out
|
||||
|
||||
private:
|
||||
// put the approximation points on the curve
|
||||
void PutOnCurve();
|
||||
// remove columns and rows with all points on one line
|
||||
void RemoveLinearColumnsRows();
|
||||
// resize verts buffer
|
||||
void ResizeExpanded( int height, int width );
|
||||
// space points out over maxWidth * maxHeight buffer
|
||||
void Expand();
|
||||
// move all points to the start of the verts buffer
|
||||
void Collapse();
|
||||
// project a point onto a vector to calculate maximum curve error
|
||||
void ProjectPointOntoVector( const idVec3 &point, const idVec3 &vStart, const idVec3 &vEnd, idVec3 &vProj );
|
||||
// generate normals
|
||||
void GenerateNormals();
|
||||
// generate triangle indexes
|
||||
void GenerateIndexes();
|
||||
// lerp point from two patch point
|
||||
void LerpVert( const idDrawVert &a, const idDrawVert &b, idDrawVert &out ) const;
|
||||
// sample a single 3x3 patch
|
||||
void SampleSinglePatchPoint( const idDrawVert ctrl[3][3], float u, float v, idDrawVert *out ) const;
|
||||
void SampleSinglePatch( const idDrawVert ctrl[3][3], int baseCol, int baseRow, int width, int horzSub, int vertSub, idDrawVert *outVerts ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::idSurface_Patch
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idSurface_Patch::idSurface_Patch() {
|
||||
height = width = maxHeight = maxWidth = 0;
|
||||
expanded = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::idSurface_Patch
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idSurface_Patch::idSurface_Patch( int maxPatchWidth, int maxPatchHeight ) {
|
||||
width = height = 0;
|
||||
maxWidth = maxPatchWidth;
|
||||
maxHeight = maxPatchHeight;
|
||||
verts.SetNum( maxWidth * maxHeight );
|
||||
expanded = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::idSurface_Patch
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idSurface_Patch::idSurface_Patch( const idSurface_Patch &patch ) {
|
||||
(*this) = patch;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::~idSurface_Patch
|
||||
=================
|
||||
*/
|
||||
ID_INLINE idSurface_Patch::~idSurface_Patch() {
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::GetWidth
|
||||
=================
|
||||
*/
|
||||
ID_INLINE int idSurface_Patch::GetWidth() const {
|
||||
return width;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idSurface_Patch::GetHeight
|
||||
=================
|
||||
*/
|
||||
ID_INLINE int idSurface_Patch::GetHeight() const {
|
||||
return height;
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_PATCH_H__ */
|
||||
334
neo/idlib/geometry/Surface_Polytope.cpp
Normal file
334
neo/idlib/geometry/Surface_Polytope.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
#define POLYTOPE_VERTEX_EPSILON 0.1f
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::FromPlanes
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::FromPlanes( const idPlane *planes, const int numPlanes ) {
|
||||
int i, j, k, *windingVerts;
|
||||
idFixedWinding w;
|
||||
idDrawVert newVert;
|
||||
|
||||
windingVerts = (int *) _alloca( MAX_POINTS_ON_WINDING * sizeof( int ) );
|
||||
memset( &newVert, 0, sizeof( newVert ) );
|
||||
|
||||
for ( i = 0; i < numPlanes; i++ ) {
|
||||
|
||||
w.BaseForPlane( planes[i] );
|
||||
|
||||
for ( j = 0; j < numPlanes; j++ ) {
|
||||
if ( j == i ) {
|
||||
continue;
|
||||
}
|
||||
if ( !w.ClipInPlace( -planes[j], ON_EPSILON, true ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !w.GetNumPoints() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( j = 0; j < w.GetNumPoints(); j++ ) {
|
||||
for ( k = 0; k < verts.Num(); k++ ) {
|
||||
if ( verts[k].xyz.Compare( w[j].ToVec3(), POLYTOPE_VERTEX_EPSILON ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k >= verts.Num() ) {
|
||||
newVert.xyz = w[j].ToVec3();
|
||||
k = verts.Append( newVert );
|
||||
}
|
||||
windingVerts[j] = k;
|
||||
}
|
||||
|
||||
for ( j = 2; j < w.GetNumPoints(); j++ ) {
|
||||
indexes.Append( windingVerts[0] );
|
||||
indexes.Append( windingVerts[j-1] );
|
||||
indexes.Append( windingVerts[j] );
|
||||
}
|
||||
}
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupTetrahedron
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupTetrahedron( const idBounds &bounds ) {
|
||||
idVec3 center, scale;
|
||||
float c1, c2, c3;
|
||||
|
||||
c1 = 0.4714045207f;
|
||||
c2 = 0.8164965809f;
|
||||
c3 = -0.3333333333f;
|
||||
|
||||
center = bounds.GetCenter();
|
||||
scale = bounds[1] - center;
|
||||
|
||||
verts.SetNum( 4 );
|
||||
verts[0].xyz = center + idVec3( 0.0f, 0.0f, scale.z );
|
||||
verts[1].xyz = center + idVec3( 2.0f * c1 * scale.x, 0.0f, c3 * scale.z );
|
||||
verts[2].xyz = center + idVec3( -c1 * scale.x, c2 * scale.y, c3 * scale.z );
|
||||
verts[3].xyz = center + idVec3( -c1 * scale.x, -c2 * scale.y, c3 * scale.z );
|
||||
|
||||
indexes.SetNum( 4*3 );
|
||||
indexes[0*3+0] = 0;
|
||||
indexes[0*3+1] = 1;
|
||||
indexes[0*3+2] = 2;
|
||||
indexes[1*3+0] = 0;
|
||||
indexes[1*3+1] = 2;
|
||||
indexes[1*3+2] = 3;
|
||||
indexes[2*3+0] = 0;
|
||||
indexes[2*3+1] = 3;
|
||||
indexes[2*3+2] = 1;
|
||||
indexes[3*3+0] = 1;
|
||||
indexes[3*3+1] = 3;
|
||||
indexes[3*3+2] = 2;
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupHexahedron
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupHexahedron( const idBounds &bounds ) {
|
||||
idVec3 center, scale;
|
||||
|
||||
center = bounds.GetCenter();
|
||||
scale = bounds[1] - center;
|
||||
|
||||
verts.SetNum( 8 );
|
||||
verts[0].xyz = center + idVec3( -scale.x, -scale.y, -scale.z );
|
||||
verts[1].xyz = center + idVec3( scale.x, -scale.y, -scale.z );
|
||||
verts[2].xyz = center + idVec3( scale.x, scale.y, -scale.z );
|
||||
verts[3].xyz = center + idVec3( -scale.x, scale.y, -scale.z );
|
||||
verts[4].xyz = center + idVec3( -scale.x, -scale.y, scale.z );
|
||||
verts[5].xyz = center + idVec3( scale.x, -scale.y, scale.z );
|
||||
verts[6].xyz = center + idVec3( scale.x, scale.y, scale.z );
|
||||
verts[7].xyz = center + idVec3( -scale.x, scale.y, scale.z );
|
||||
|
||||
indexes.SetNum( 12*3 );
|
||||
indexes[ 0*3+0] = 0;
|
||||
indexes[ 0*3+1] = 3;
|
||||
indexes[ 0*3+2] = 2;
|
||||
indexes[ 1*3+0] = 0;
|
||||
indexes[ 1*3+1] = 2;
|
||||
indexes[ 1*3+2] = 1;
|
||||
indexes[ 2*3+0] = 0;
|
||||
indexes[ 2*3+1] = 1;
|
||||
indexes[ 2*3+2] = 5;
|
||||
indexes[ 3*3+0] = 0;
|
||||
indexes[ 3*3+1] = 5;
|
||||
indexes[ 3*3+2] = 4;
|
||||
indexes[ 4*3+0] = 0;
|
||||
indexes[ 4*3+1] = 4;
|
||||
indexes[ 4*3+2] = 7;
|
||||
indexes[ 5*3+0] = 0;
|
||||
indexes[ 5*3+1] = 7;
|
||||
indexes[ 5*3+2] = 3;
|
||||
indexes[ 6*3+0] = 6;
|
||||
indexes[ 6*3+1] = 5;
|
||||
indexes[ 6*3+2] = 1;
|
||||
indexes[ 7*3+0] = 6;
|
||||
indexes[ 7*3+1] = 1;
|
||||
indexes[ 7*3+2] = 2;
|
||||
indexes[ 8*3+0] = 6;
|
||||
indexes[ 8*3+1] = 2;
|
||||
indexes[ 8*3+2] = 3;
|
||||
indexes[ 9*3+0] = 6;
|
||||
indexes[ 9*3+1] = 3;
|
||||
indexes[ 9*3+2] = 7;
|
||||
indexes[10*3+0] = 6;
|
||||
indexes[10*3+1] = 7;
|
||||
indexes[10*3+2] = 4;
|
||||
indexes[11*3+0] = 6;
|
||||
indexes[11*3+1] = 4;
|
||||
indexes[11*3+2] = 5;
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupOctahedron
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupOctahedron( const idBounds &bounds ) {
|
||||
idVec3 center, scale;
|
||||
|
||||
center = bounds.GetCenter();
|
||||
scale = bounds[1] - center;
|
||||
|
||||
verts.SetNum( 6 );
|
||||
verts[0].xyz = center + idVec3( scale.x, 0.0f, 0.0f );
|
||||
verts[1].xyz = center + idVec3( -scale.x, 0.0f, 0.0f );
|
||||
verts[2].xyz = center + idVec3( 0.0f, scale.y, 0.0f );
|
||||
verts[3].xyz = center + idVec3( 0.0f, -scale.y, 0.0f );
|
||||
verts[4].xyz = center + idVec3( 0.0f, 0.0f, scale.z );
|
||||
verts[5].xyz = center + idVec3( 0.0f, 0.0f, -scale.z );
|
||||
|
||||
indexes.SetNum( 8*3 );
|
||||
indexes[0*3+0] = 4;
|
||||
indexes[0*3+1] = 0;
|
||||
indexes[0*3+2] = 2;
|
||||
indexes[1*3+0] = 4;
|
||||
indexes[1*3+1] = 2;
|
||||
indexes[1*3+2] = 1;
|
||||
indexes[2*3+0] = 4;
|
||||
indexes[2*3+1] = 1;
|
||||
indexes[2*3+2] = 3;
|
||||
indexes[3*3+0] = 4;
|
||||
indexes[3*3+1] = 3;
|
||||
indexes[3*3+2] = 0;
|
||||
indexes[4*3+0] = 5;
|
||||
indexes[4*3+1] = 2;
|
||||
indexes[4*3+2] = 0;
|
||||
indexes[5*3+0] = 5;
|
||||
indexes[5*3+1] = 1;
|
||||
indexes[5*3+2] = 2;
|
||||
indexes[6*3+0] = 5;
|
||||
indexes[6*3+1] = 3;
|
||||
indexes[6*3+2] = 1;
|
||||
indexes[7*3+0] = 5;
|
||||
indexes[7*3+1] = 0;
|
||||
indexes[7*3+2] = 3;
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupDodecahedron
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupDodecahedron( const idBounds &bounds ) {
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupIcosahedron
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupIcosahedron( const idBounds &bounds ) {
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupCylinder
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupCylinder( const idBounds &bounds, const int numSides ) {
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SetupCone
|
||||
====================
|
||||
*/
|
||||
void idSurface_Polytope::SetupCone( const idBounds &bounds, const int numSides ) {
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::SplitPolytope
|
||||
====================
|
||||
*/
|
||||
int idSurface_Polytope::SplitPolytope( const idPlane &plane, const float epsilon, idSurface_Polytope **front, idSurface_Polytope **back ) const {
|
||||
int side, i, j, s, v0, v1, v2, edgeNum;
|
||||
idSurface *surface[2];
|
||||
idSurface_Polytope *polytopeSurfaces[2], *surf;
|
||||
int *onPlaneEdges[2];
|
||||
|
||||
onPlaneEdges[0] = (int *) _alloca( indexes.Num() / 3 * sizeof( int ) );
|
||||
onPlaneEdges[1] = (int *) _alloca( indexes.Num() / 3 * sizeof( int ) );
|
||||
|
||||
side = Split( plane, epsilon, &surface[0], &surface[1], onPlaneEdges[0], onPlaneEdges[1] );
|
||||
|
||||
*front = polytopeSurfaces[0] = new (TAG_IDLIB_SURFACE) idSurface_Polytope;
|
||||
*back = polytopeSurfaces[1] = new (TAG_IDLIB_SURFACE) idSurface_Polytope;
|
||||
|
||||
for ( s = 0; s < 2; s++ ) {
|
||||
if ( surface[s] ) {
|
||||
polytopeSurfaces[s] = new idSurface_Polytope( *surface[s] );
|
||||
delete surface[s];
|
||||
surface[s] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*front = polytopeSurfaces[0];
|
||||
*back = polytopeSurfaces[1];
|
||||
|
||||
if ( side != SIDE_CROSS ) {
|
||||
return side;
|
||||
}
|
||||
|
||||
// add triangles to close off the front and back polytope
|
||||
for ( s = 0; s < 2; s++ ) {
|
||||
|
||||
surf = polytopeSurfaces[s];
|
||||
|
||||
edgeNum = surf->edgeIndexes[onPlaneEdges[s][0]];
|
||||
v0 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)];
|
||||
v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];
|
||||
|
||||
for ( i = 1; onPlaneEdges[s][i] >= 0; i++ ) {
|
||||
for ( j = i+1; onPlaneEdges[s][j] >= 0; j++ ) {
|
||||
edgeNum = surf->edgeIndexes[onPlaneEdges[s][j]];
|
||||
if ( v1 == surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)] ) {
|
||||
v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];
|
||||
SwapValues( onPlaneEdges[s][i], onPlaneEdges[s][j] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 2; onPlaneEdges[s][i] >= 0; i++ ) {
|
||||
edgeNum = surf->edgeIndexes[onPlaneEdges[s][i]];
|
||||
v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];
|
||||
v2 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)];
|
||||
surf->indexes.Append( v0 );
|
||||
surf->indexes.Append( v1 );
|
||||
surf->indexes.Append( v2 );
|
||||
}
|
||||
|
||||
surf->GenerateEdgeIndexes();
|
||||
}
|
||||
|
||||
return side;
|
||||
}
|
||||
71
neo/idlib/geometry/Surface_Polytope.h
Normal file
71
neo/idlib/geometry/Surface_Polytope.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SURFACE_POLYTOPE_H__
|
||||
#define __SURFACE_POLYTOPE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Polytope surface.
|
||||
|
||||
NOTE: vertexes are not duplicated for texture coordinates.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idSurface_Polytope : public idSurface {
|
||||
public:
|
||||
idSurface_Polytope();
|
||||
explicit idSurface_Polytope( const idSurface &surface ) : idSurface( surface ) {}
|
||||
|
||||
void FromPlanes( const idPlane *planes, const int numPlanes );
|
||||
|
||||
void SetupTetrahedron( const idBounds &bounds );
|
||||
void SetupHexahedron( const idBounds &bounds );
|
||||
void SetupOctahedron( const idBounds &bounds );
|
||||
void SetupDodecahedron( const idBounds &bounds );
|
||||
void SetupIcosahedron( const idBounds &bounds );
|
||||
void SetupCylinder( const idBounds &bounds, const int numSides );
|
||||
void SetupCone( const idBounds &bounds, const int numSides );
|
||||
|
||||
int SplitPolytope( const idPlane &plane, const float epsilon, idSurface_Polytope **front, idSurface_Polytope **back ) const;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_Polytope::idSurface_Polytope
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface_Polytope::idSurface_Polytope() {
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_POLYTOPE_H__ */
|
||||
223
neo/idlib/geometry/Surface_SweptSpline.cpp
Normal file
223
neo/idlib/geometry/Surface_SweptSpline.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::SetSpline
|
||||
====================
|
||||
*/
|
||||
void idSurface_SweptSpline::SetSpline( idCurve_Spline<idVec4> *spline ) {
|
||||
if ( this->spline ) {
|
||||
delete this->spline;
|
||||
}
|
||||
this->spline = spline;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::SetSweptSpline
|
||||
====================
|
||||
*/
|
||||
void idSurface_SweptSpline::SetSweptSpline( idCurve_Spline<idVec4> *sweptSpline ) {
|
||||
if ( this->sweptSpline ) {
|
||||
delete this->sweptSpline;
|
||||
}
|
||||
this->sweptSpline = sweptSpline;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::SetSweptCircle
|
||||
|
||||
Sets the swept spline to a NURBS circle.
|
||||
====================
|
||||
*/
|
||||
void idSurface_SweptSpline::SetSweptCircle( const float radius ) {
|
||||
idCurve_NURBS<idVec4> *nurbs = new (TAG_IDLIB_SURFACE) idCurve_NURBS<idVec4>();
|
||||
nurbs->Clear();
|
||||
nurbs->AddValue( 0.0f, idVec4( radius, radius, 0.0f, 0.00f ) );
|
||||
nurbs->AddValue( 100.0f, idVec4( -radius, radius, 0.0f, 0.25f ) );
|
||||
nurbs->AddValue( 200.0f, idVec4( -radius, -radius, 0.0f, 0.50f ) );
|
||||
nurbs->AddValue( 300.0f, idVec4( radius, -radius, 0.0f, 0.75f ) );
|
||||
nurbs->SetBoundaryType( idCurve_NURBS<idVec4>::BT_CLOSED );
|
||||
nurbs->SetCloseTime( 100.0f );
|
||||
if ( sweptSpline ) {
|
||||
delete sweptSpline;
|
||||
}
|
||||
sweptSpline = nurbs;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::GetFrame
|
||||
====================
|
||||
*/
|
||||
void idSurface_SweptSpline::GetFrame( const idMat3 &previousFrame, const idVec3 dir, idMat3 &newFrame ) {
|
||||
float wx, wy, wz;
|
||||
float xx, yy, yz;
|
||||
float xy, xz, zz;
|
||||
float x2, y2, z2;
|
||||
float a, c, s, x, y, z;
|
||||
idVec3 d, v;
|
||||
idMat3 axis;
|
||||
|
||||
d = dir;
|
||||
d.Normalize();
|
||||
v = d.Cross( previousFrame[2] );
|
||||
v.Normalize();
|
||||
|
||||
a = idMath::ACos( previousFrame[2] * d ) * 0.5f;
|
||||
c = idMath::Cos( a );
|
||||
s = idMath::Sqrt( 1.0f - c * c );
|
||||
|
||||
x = v[0] * s;
|
||||
y = v[1] * s;
|
||||
z = v[2] * s;
|
||||
|
||||
x2 = x + x;
|
||||
y2 = y + y;
|
||||
z2 = z + z;
|
||||
xx = x * x2;
|
||||
xy = x * y2;
|
||||
xz = x * z2;
|
||||
yy = y * y2;
|
||||
yz = y * z2;
|
||||
zz = z * z2;
|
||||
wx = c * x2;
|
||||
wy = c * y2;
|
||||
wz = c * z2;
|
||||
|
||||
axis[0][0] = 1.0f - ( yy + zz );
|
||||
axis[0][1] = xy - wz;
|
||||
axis[0][2] = xz + wy;
|
||||
axis[1][0] = xy + wz;
|
||||
axis[1][1] = 1.0f - ( xx + zz );
|
||||
axis[1][2] = yz - wx;
|
||||
axis[2][0] = xz - wy;
|
||||
axis[2][1] = yz + wx;
|
||||
axis[2][2] = 1.0f - ( xx + yy );
|
||||
|
||||
newFrame = previousFrame * axis;
|
||||
|
||||
newFrame[2] = dir;
|
||||
newFrame[2].Normalize();
|
||||
newFrame[1].Cross( newFrame[ 2 ], newFrame[ 0 ] );
|
||||
newFrame[1].Normalize();
|
||||
newFrame[0].Cross( newFrame[ 1 ], newFrame[ 2 ] );
|
||||
newFrame[0].Normalize();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::Tessellate
|
||||
|
||||
tesselate the surface
|
||||
====================
|
||||
*/
|
||||
void idSurface_SweptSpline::Tessellate( const int splineSubdivisions, const int sweptSplineSubdivisions ) {
|
||||
int i, j, offset, baseOffset, splineDiv, sweptSplineDiv;
|
||||
int i0, i1, j0, j1;
|
||||
float totalTime, t;
|
||||
idVec4 splinePos, splineD1;
|
||||
idMat3 splineMat;
|
||||
|
||||
if ( !spline || !sweptSpline ) {
|
||||
idSurface::Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
verts.SetNum( splineSubdivisions * sweptSplineSubdivisions );
|
||||
|
||||
// calculate the points and first derivatives for the swept spline
|
||||
totalTime = sweptSpline->GetTime( sweptSpline->GetNumValues() - 1 ) - sweptSpline->GetTime( 0 ) + sweptSpline->GetCloseTime();
|
||||
sweptSplineDiv = sweptSpline->GetBoundaryType() == idCurve_Spline<idVec3>::BT_CLOSED ? sweptSplineSubdivisions : sweptSplineSubdivisions - 1;
|
||||
baseOffset = (splineSubdivisions-1) * sweptSplineSubdivisions;
|
||||
for ( i = 0; i < sweptSplineSubdivisions; i++ ) {
|
||||
t = totalTime * i / sweptSplineDiv;
|
||||
splinePos = sweptSpline->GetCurrentValue( t );
|
||||
splineD1 = sweptSpline->GetCurrentFirstDerivative( t );
|
||||
verts[baseOffset+i].xyz = splinePos.ToVec3();
|
||||
verts[baseOffset+i].SetTexCoordS( splinePos.w );
|
||||
verts[baseOffset+i].SetTangent( splineD1.ToVec3() );
|
||||
}
|
||||
|
||||
// sweep the spline
|
||||
totalTime = spline->GetTime( spline->GetNumValues() - 1 ) - spline->GetTime( 0 ) + spline->GetCloseTime();
|
||||
splineDiv = spline->GetBoundaryType() == idCurve_Spline<idVec3>::BT_CLOSED ? splineSubdivisions : splineSubdivisions - 1;
|
||||
splineMat.Identity();
|
||||
idVec3 tempNormal;
|
||||
for ( i = 0; i < splineSubdivisions; i++ ) {
|
||||
t = totalTime * i / splineDiv;
|
||||
|
||||
splinePos = spline->GetCurrentValue( t );
|
||||
splineD1 = spline->GetCurrentFirstDerivative( t );
|
||||
|
||||
GetFrame( splineMat, splineD1.ToVec3(), splineMat );
|
||||
|
||||
offset = i * sweptSplineSubdivisions;
|
||||
for ( j = 0; j < sweptSplineSubdivisions; j++ ) {
|
||||
idDrawVert *v = &verts[offset+j];
|
||||
v->xyz = splinePos.ToVec3() + verts[baseOffset+j].xyz * splineMat;
|
||||
v->SetTexCoord( verts[baseOffset+j].GetTexCoord().x, splinePos.w );
|
||||
v->SetTangent( verts[baseOffset+j].GetTangent() * splineMat );
|
||||
v->SetBiTangent( splineD1.ToVec3() );
|
||||
tempNormal = v->GetBiTangent().Cross( v->GetTangent() );
|
||||
tempNormal.Normalize();
|
||||
v->SetNormal( tempNormal );
|
||||
v->color[0] = v->color[1] = v->color[2] = v->color[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
indexes.SetNum( splineDiv * sweptSplineDiv * 2 * 3 );
|
||||
|
||||
// create indexes for the triangles
|
||||
for ( offset = i = 0; i < splineDiv; i++ ) {
|
||||
|
||||
i0 = (i+0) * sweptSplineSubdivisions;
|
||||
i1 = (i+1) % splineSubdivisions * sweptSplineSubdivisions;
|
||||
|
||||
for ( j = 0; j < sweptSplineDiv; j++ ) {
|
||||
|
||||
j0 = (j+0);
|
||||
j1 = (j+1) % sweptSplineSubdivisions;
|
||||
|
||||
indexes[offset++] = i0 + j0;
|
||||
indexes[offset++] = i0 + j1;
|
||||
indexes[offset++] = i1 + j1;
|
||||
|
||||
indexes[offset++] = i1 + j1;
|
||||
indexes[offset++] = i1 + j0;
|
||||
indexes[offset++] = i0 + j0;
|
||||
}
|
||||
}
|
||||
|
||||
GenerateEdgeIndexes();
|
||||
}
|
||||
93
neo/idlib/geometry/Surface_SweptSpline.h
Normal file
93
neo/idlib/geometry/Surface_SweptSpline.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SURFACE_SWEPTSPLINE_H__
|
||||
#define __SURFACE_SWEPTSPLINE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Swept Spline surface.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idSurface_SweptSpline : public idSurface {
|
||||
public:
|
||||
idSurface_SweptSpline();
|
||||
~idSurface_SweptSpline();
|
||||
|
||||
void SetSpline( idCurve_Spline<idVec4> *spline );
|
||||
void SetSweptSpline( idCurve_Spline<idVec4> *sweptSpline );
|
||||
void SetSweptCircle( const float radius );
|
||||
|
||||
void Tessellate( const int splineSubdivisions, const int sweptSplineSubdivisions );
|
||||
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
idCurve_Spline<idVec4> *spline;
|
||||
idCurve_Spline<idVec4> *sweptSpline;
|
||||
|
||||
void GetFrame( const idMat3 &previousFrame, const idVec3 dir, idMat3 &newFrame );
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::idSurface_SweptSpline
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface_SweptSpline::idSurface_SweptSpline() {
|
||||
spline = NULL;
|
||||
sweptSpline = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::~idSurface_SweptSpline
|
||||
====================
|
||||
*/
|
||||
ID_INLINE idSurface_SweptSpline::~idSurface_SweptSpline() {
|
||||
delete spline;
|
||||
delete sweptSpline;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idSurface_SweptSpline::Clear
|
||||
====================
|
||||
*/
|
||||
ID_INLINE void idSurface_SweptSpline::Clear() {
|
||||
idSurface::Clear();
|
||||
delete spline;
|
||||
spline = NULL;
|
||||
delete sweptSpline;
|
||||
sweptSpline = NULL;
|
||||
}
|
||||
|
||||
#endif /* !__SURFACE_SWEPTSPLINE_H__ */
|
||||
1492
neo/idlib/geometry/TraceModel.cpp
Normal file
1492
neo/idlib/geometry/TraceModel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
189
neo/idlib/geometry/TraceModel.h
Normal file
189
neo/idlib/geometry/TraceModel.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __TRACEMODEL_H__
|
||||
#define __TRACEMODEL_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
A trace model is an arbitrary polygonal model which is used by the
|
||||
collision detection system to find collisions, contacts or the contents
|
||||
of a volume. For collision detection speed reasons the number of vertices
|
||||
and edges are limited. The trace model can have any shape. However convex
|
||||
models are usually preferred.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idVec3;
|
||||
class idMat3;
|
||||
class idBounds;
|
||||
|
||||
// trace model type
|
||||
typedef enum {
|
||||
TRM_INVALID, // invalid trm
|
||||
TRM_BOX, // box
|
||||
TRM_OCTAHEDRON, // octahedron
|
||||
TRM_DODECAHEDRON, // dodecahedron
|
||||
TRM_CYLINDER, // cylinder approximation
|
||||
TRM_CONE, // cone approximation
|
||||
TRM_BONE, // two tetrahedrons attached to each other
|
||||
TRM_POLYGON, // arbitrary convex polygon
|
||||
TRM_POLYGONVOLUME, // volume for arbitrary convex polygon
|
||||
TRM_CUSTOM // loaded from map model or ASE/LWO
|
||||
} traceModel_t;
|
||||
|
||||
// these are bit cache limits
|
||||
#define MAX_TRACEMODEL_VERTS 32
|
||||
#define MAX_TRACEMODEL_EDGES 32
|
||||
#define MAX_TRACEMODEL_POLYS 16
|
||||
#define MAX_TRACEMODEL_POLYEDGES 16
|
||||
|
||||
typedef idVec3 traceModelVert_t;
|
||||
|
||||
typedef struct {
|
||||
int v[2];
|
||||
idVec3 normal;
|
||||
} traceModelEdge_t;
|
||||
|
||||
typedef struct {
|
||||
idVec3 normal;
|
||||
float dist;
|
||||
idBounds bounds;
|
||||
int numEdges;
|
||||
int edges[MAX_TRACEMODEL_POLYEDGES];
|
||||
} traceModelPoly_t;
|
||||
|
||||
class idTraceModel {
|
||||
|
||||
public:
|
||||
traceModel_t type;
|
||||
int numVerts;
|
||||
traceModelVert_t verts[MAX_TRACEMODEL_VERTS];
|
||||
int numEdges;
|
||||
traceModelEdge_t edges[MAX_TRACEMODEL_EDGES+1];
|
||||
int numPolys;
|
||||
traceModelPoly_t polys[MAX_TRACEMODEL_POLYS];
|
||||
idVec3 offset; // offset to center of model
|
||||
idBounds bounds; // bounds of model
|
||||
bool isConvex; // true when model is convex
|
||||
|
||||
public:
|
||||
idTraceModel();
|
||||
// axial bounding box
|
||||
idTraceModel( const idBounds &boxBounds );
|
||||
// cylinder approximation
|
||||
idTraceModel( const idBounds &cylBounds, const int numSides );
|
||||
// bone
|
||||
idTraceModel( const float length, const float width );
|
||||
|
||||
// axial box
|
||||
void SetupBox( const idBounds &boxBounds );
|
||||
void SetupBox( const float size );
|
||||
// octahedron
|
||||
void SetupOctahedron( const idBounds &octBounds );
|
||||
void SetupOctahedron( const float size );
|
||||
// dodecahedron
|
||||
void SetupDodecahedron( const idBounds &dodBounds );
|
||||
void SetupDodecahedron( const float size );
|
||||
// cylinder approximation
|
||||
void SetupCylinder( const idBounds &cylBounds, const int numSides );
|
||||
void SetupCylinder( const float height, const float width, const int numSides );
|
||||
// cone approximation
|
||||
void SetupCone( const idBounds &coneBounds, const int numSides );
|
||||
void SetupCone( const float height, const float width, const int numSides );
|
||||
// two tetrahedrons attached to each other
|
||||
void SetupBone( const float length, const float width );
|
||||
// arbitrary convex polygon
|
||||
void SetupPolygon( const idVec3 *v, const int count );
|
||||
void SetupPolygon( const idWinding &w );
|
||||
// generate edge normals
|
||||
int GenerateEdgeNormals();
|
||||
// translate the trm
|
||||
void Translate( const idVec3 &translation );
|
||||
// rotate the trm
|
||||
void Rotate( const idMat3 &rotation );
|
||||
// shrink the model m units on all sides
|
||||
void Shrink( const float m );
|
||||
// compare
|
||||
bool Compare( const idTraceModel &trm ) const;
|
||||
bool operator==( const idTraceModel &trm ) const;
|
||||
bool operator!=( const idTraceModel &trm ) const;
|
||||
// get the area of one of the polygons
|
||||
float GetPolygonArea( int polyNum ) const;
|
||||
// get the silhouette edges
|
||||
int GetProjectionSilhouetteEdges( const idVec3 &projectionOrigin, int silEdges[MAX_TRACEMODEL_EDGES] ) const;
|
||||
int GetParallelProjectionSilhouetteEdges( const idVec3 &projectionDir, int silEdges[MAX_TRACEMODEL_EDGES] ) const;
|
||||
// calculate mass properties assuming an uniform density
|
||||
void GetMassProperties( const float density, float &mass, idVec3 ¢erOfMass, idMat3 &inertiaTensor ) const;
|
||||
|
||||
private:
|
||||
void InitBox();
|
||||
void InitOctahedron();
|
||||
void InitDodecahedron();
|
||||
void InitBone();
|
||||
|
||||
void ProjectionIntegrals( int polyNum, int a, int b, struct projectionIntegrals_s &integrals ) const;
|
||||
void PolygonIntegrals( int polyNum, int a, int b, int c, struct polygonIntegrals_s &integrals ) const;
|
||||
void VolumeIntegrals( struct volumeIntegrals_s &integrals ) const;
|
||||
void VolumeFromPolygon( idTraceModel &trm, float thickness ) const;
|
||||
int GetOrderedSilhouetteEdges( const int edgeIsSilEdge[MAX_TRACEMODEL_EDGES+1], int silEdges[MAX_TRACEMODEL_EDGES] ) const;
|
||||
};
|
||||
|
||||
|
||||
ID_INLINE idTraceModel::idTraceModel() {
|
||||
type = TRM_INVALID;
|
||||
numVerts = numEdges = numPolys = 0;
|
||||
bounds.Zero();
|
||||
}
|
||||
|
||||
ID_INLINE idTraceModel::idTraceModel( const idBounds &boxBounds ) {
|
||||
InitBox();
|
||||
SetupBox( boxBounds );
|
||||
}
|
||||
|
||||
ID_INLINE idTraceModel::idTraceModel( const idBounds &cylBounds, const int numSides ) {
|
||||
SetupCylinder( cylBounds, numSides );
|
||||
}
|
||||
|
||||
ID_INLINE idTraceModel::idTraceModel( const float length, const float width ) {
|
||||
InitBone();
|
||||
SetupBone( length, width );
|
||||
}
|
||||
|
||||
ID_INLINE bool idTraceModel::operator==( const idTraceModel &trm ) const {
|
||||
return Compare( trm );
|
||||
}
|
||||
|
||||
ID_INLINE bool idTraceModel::operator!=( const idTraceModel &trm ) const {
|
||||
return !Compare( trm );
|
||||
}
|
||||
|
||||
#endif /* !__TRACEMODEL_H__ */
|
||||
|
||||
1600
neo/idlib/geometry/Winding.cpp
Normal file
1600
neo/idlib/geometry/Winding.cpp
Normal file
File diff suppressed because it is too large
Load Diff
401
neo/idlib/geometry/Winding.h
Normal file
401
neo/idlib/geometry/Winding.h
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __WINDING_H__
|
||||
#define __WINDING_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
A winding is an arbitrary convex polygon defined by an array of points.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idWinding {
|
||||
|
||||
public:
|
||||
idWinding();
|
||||
explicit idWinding( const int n ); // allocate for n points
|
||||
explicit idWinding( const idVec3 *verts, const int n ); // winding from points
|
||||
explicit idWinding( const idVec3 &normal, const float dist ); // base winding for plane
|
||||
explicit idWinding( const idPlane &plane ); // base winding for plane
|
||||
explicit idWinding( const idWinding &winding );
|
||||
virtual ~idWinding();
|
||||
|
||||
idWinding & operator=( const idWinding &winding );
|
||||
const idVec5 & operator[]( const int index ) const;
|
||||
idVec5 & operator[]( const int index );
|
||||
|
||||
// add a point to the end of the winding point array
|
||||
idWinding & operator+=( const idVec3 &v );
|
||||
idWinding & operator+=( const idVec5 &v );
|
||||
void AddPoint( const idVec3 &v );
|
||||
void AddPoint( const idVec5 &v );
|
||||
|
||||
// number of points on winding
|
||||
int GetNumPoints() const;
|
||||
void SetNumPoints( int n );
|
||||
virtual void Clear();
|
||||
|
||||
// huge winding for plane, the points go counter clockwise when facing the front of the plane
|
||||
void BaseForPlane( const idVec3 &normal, const float dist );
|
||||
void BaseForPlane( const idPlane &plane );
|
||||
|
||||
// splits the winding into a front and back winding, the winding itself stays unchanged
|
||||
// returns a SIDE_?
|
||||
int Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const;
|
||||
// returns the winding fragment at the front of the clipping plane,
|
||||
// if there is nothing at the front the winding itself is destroyed and NULL is returned
|
||||
idWinding * Clip( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
|
||||
// cuts off the part at the back side of the plane, returns true if some part was at the front
|
||||
// if there is nothing at the front the number of points is set to zero
|
||||
bool ClipInPlace( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
|
||||
|
||||
// returns a copy of the winding
|
||||
idWinding * Copy() const;
|
||||
idWinding * Reverse() const;
|
||||
void ReverseSelf();
|
||||
void RemoveEqualPoints( const float epsilon = ON_EPSILON );
|
||||
void RemoveColinearPoints( const idVec3 &normal, const float epsilon = ON_EPSILON );
|
||||
void RemovePoint( int point );
|
||||
void InsertPoint( const idVec5 &point, int spot );
|
||||
bool InsertPointIfOnEdge( const idVec5 &point, const idPlane &plane, const float epsilon = ON_EPSILON );
|
||||
// add a winding to the convex hull
|
||||
void AddToConvexHull( const idWinding *winding, const idVec3 &normal, const float epsilon = ON_EPSILON );
|
||||
// add a point to the convex hull
|
||||
void AddToConvexHull( const idVec3 &point, const idVec3 &normal, const float epsilon = ON_EPSILON );
|
||||
// tries to merge 'this' with the given winding, returns NULL if merge fails, both 'this' and 'w' stay intact
|
||||
// 'keep' tells if the contacting points should stay even if they create colinear edges
|
||||
idWinding * TryMerge( const idWinding &w, const idVec3 &normal, int keep = false ) const;
|
||||
// check whether the winding is valid or not
|
||||
bool Check( bool print = true ) const;
|
||||
|
||||
float GetArea() const;
|
||||
idVec3 GetCenter() const;
|
||||
float GetRadius( const idVec3 ¢er ) const;
|
||||
void GetPlane( idVec3 &normal, float &dist ) const;
|
||||
void GetPlane( idPlane &plane ) const;
|
||||
void GetBounds( idBounds &bounds ) const;
|
||||
|
||||
bool IsTiny() const;
|
||||
bool IsHuge() const; // base winding for a plane is typically huge
|
||||
void Print() const;
|
||||
|
||||
float PlaneDistance( const idPlane &plane ) const;
|
||||
int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
|
||||
|
||||
bool PlanesConcave( const idWinding &w2, const idVec3 &normal1, const idVec3 &normal2, float dist1, float dist2 ) const;
|
||||
|
||||
bool PointInside( const idVec3 &normal, const idVec3 &point, const float epsilon ) const;
|
||||
// returns true if the line or ray intersects the winding
|
||||
bool LineIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &end, bool backFaceCull = false ) const;
|
||||
// intersection point is start + dir * scale
|
||||
bool RayIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull = false ) const;
|
||||
|
||||
static float TriangleArea( const idVec3 &a, const idVec3 &b, const idVec3 &c );
|
||||
|
||||
protected:
|
||||
int numPoints; // number of points
|
||||
idVec5 * p; // pointer to point data
|
||||
int allocedSize;
|
||||
|
||||
bool EnsureAlloced( int n, bool keep = false );
|
||||
virtual bool ReAllocate( int n, bool keep = false );
|
||||
};
|
||||
|
||||
ID_INLINE idWinding::idWinding() {
|
||||
numPoints = allocedSize = 0;
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
ID_INLINE idWinding::idWinding( int n ) {
|
||||
numPoints = allocedSize = 0;
|
||||
p = NULL;
|
||||
EnsureAlloced( n );
|
||||
}
|
||||
|
||||
ID_INLINE idWinding::idWinding( const idVec3 *verts, const int n ) {
|
||||
int i;
|
||||
|
||||
numPoints = allocedSize = 0;
|
||||
p = NULL;
|
||||
if ( !EnsureAlloced( n ) ) {
|
||||
numPoints = 0;
|
||||
return;
|
||||
}
|
||||
for ( i = 0; i < n; i++ ) {
|
||||
p[i].ToVec3() = verts[i];
|
||||
p[i].s = p[i].t = 0.0f;
|
||||
}
|
||||
numPoints = n;
|
||||
}
|
||||
|
||||
ID_INLINE idWinding::idWinding( const idVec3 &normal, const float dist ) {
|
||||
numPoints = allocedSize = 0;
|
||||
p = NULL;
|
||||
BaseForPlane( normal, dist );
|
||||
}
|
||||
|
||||
ID_INLINE idWinding::idWinding( const idPlane &plane ) {
|
||||
numPoints = allocedSize = 0;
|
||||
p = NULL;
|
||||
BaseForPlane( plane );
|
||||
}
|
||||
|
||||
ID_INLINE idWinding::idWinding( const idWinding &winding ) {
|
||||
int i;
|
||||
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
|
||||
numPoints = 0;
|
||||
return;
|
||||
}
|
||||
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
|
||||
p[i] = winding[i];
|
||||
}
|
||||
numPoints = winding.GetNumPoints();
|
||||
}
|
||||
|
||||
ID_INLINE idWinding::~idWinding() {
|
||||
delete[] p;
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
ID_INLINE idWinding &idWinding::operator=( const idWinding &winding ) {
|
||||
int i;
|
||||
|
||||
if ( !EnsureAlloced( winding.numPoints ) ) {
|
||||
numPoints = 0;
|
||||
return *this;
|
||||
}
|
||||
for ( i = 0; i < winding.numPoints; i++ ) {
|
||||
p[i] = winding.p[i];
|
||||
}
|
||||
numPoints = winding.numPoints;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ID_INLINE const idVec5 &idWinding::operator[]( const int index ) const {
|
||||
//assert( index >= 0 && index < numPoints );
|
||||
return p[ index ];
|
||||
}
|
||||
|
||||
ID_INLINE idVec5 &idWinding::operator[]( const int index ) {
|
||||
//assert( index >= 0 && index < numPoints );
|
||||
return p[ index ];
|
||||
}
|
||||
|
||||
ID_INLINE idWinding &idWinding::operator+=( const idVec3 &v ) {
|
||||
AddPoint( v );
|
||||
return *this;
|
||||
}
|
||||
|
||||
ID_INLINE idWinding &idWinding::operator+=( const idVec5 &v ) {
|
||||
AddPoint( v );
|
||||
return *this;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::AddPoint( const idVec3 &v ) {
|
||||
if ( !EnsureAlloced(numPoints+1, true) ) {
|
||||
return;
|
||||
}
|
||||
p[numPoints] = v;
|
||||
numPoints++;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::AddPoint( const idVec5 &v ) {
|
||||
if ( !EnsureAlloced(numPoints+1, true) ) {
|
||||
return;
|
||||
}
|
||||
p[numPoints] = v;
|
||||
numPoints++;
|
||||
}
|
||||
|
||||
ID_INLINE int idWinding::GetNumPoints() const {
|
||||
return numPoints;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::SetNumPoints( int n ) {
|
||||
if ( !EnsureAlloced( n, true ) ) {
|
||||
return;
|
||||
}
|
||||
numPoints = n;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::Clear() {
|
||||
numPoints = 0;
|
||||
delete[] p;
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding::BaseForPlane( const idPlane &plane ) {
|
||||
BaseForPlane( plane.Normal(), plane.Dist() );
|
||||
}
|
||||
|
||||
ID_INLINE bool idWinding::EnsureAlloced( int n, bool keep ) {
|
||||
if ( n > allocedSize ) {
|
||||
return ReAllocate( n, keep );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
idFixedWinding is a fixed buffer size winding not using
|
||||
memory allocations.
|
||||
|
||||
When an operation would overflow the fixed buffer a warning
|
||||
is printed and the operation is safely cancelled.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define MAX_POINTS_ON_WINDING 64
|
||||
|
||||
class idFixedWinding : public idWinding {
|
||||
|
||||
public:
|
||||
idFixedWinding();
|
||||
explicit idFixedWinding( const int n );
|
||||
explicit idFixedWinding( const idVec3 *verts, const int n );
|
||||
explicit idFixedWinding( const idVec3 &normal, const float dist );
|
||||
explicit idFixedWinding( const idPlane &plane );
|
||||
explicit idFixedWinding( const idWinding &winding );
|
||||
explicit idFixedWinding( const idFixedWinding &winding );
|
||||
virtual ~idFixedWinding();
|
||||
|
||||
idFixedWinding &operator=( const idWinding &winding );
|
||||
|
||||
virtual void Clear();
|
||||
|
||||
// splits the winding in a back and front part, 'this' becomes the front part
|
||||
// returns a SIDE_?
|
||||
int Split( idFixedWinding *back, const idPlane &plane, const float epsilon = ON_EPSILON );
|
||||
|
||||
protected:
|
||||
idVec5 data[MAX_POINTS_ON_WINDING]; // point data
|
||||
|
||||
virtual bool ReAllocate( int n, bool keep = false );
|
||||
};
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding() {
|
||||
numPoints = 0;
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding( int n ) {
|
||||
numPoints = 0;
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding( const idVec3 *verts, const int n ) {
|
||||
int i;
|
||||
|
||||
numPoints = 0;
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
if ( !EnsureAlloced( n ) ) {
|
||||
numPoints = 0;
|
||||
return;
|
||||
}
|
||||
for ( i = 0; i < n; i++ ) {
|
||||
p[i].ToVec3() = verts[i];
|
||||
p[i].s = p[i].t = 0;
|
||||
}
|
||||
numPoints = n;
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding( const idVec3 &normal, const float dist ) {
|
||||
numPoints = 0;
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
BaseForPlane( normal, dist );
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding( const idPlane &plane ) {
|
||||
numPoints = 0;
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
BaseForPlane( plane );
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding( const idWinding &winding ) {
|
||||
int i;
|
||||
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
|
||||
numPoints = 0;
|
||||
return;
|
||||
}
|
||||
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
|
||||
p[i] = winding[i];
|
||||
}
|
||||
numPoints = winding.GetNumPoints();
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::idFixedWinding( const idFixedWinding &winding ) {
|
||||
int i;
|
||||
|
||||
p = data;
|
||||
allocedSize = MAX_POINTS_ON_WINDING;
|
||||
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
|
||||
numPoints = 0;
|
||||
return;
|
||||
}
|
||||
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
|
||||
p[i] = winding[i];
|
||||
}
|
||||
numPoints = winding.GetNumPoints();
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding::~idFixedWinding() {
|
||||
p = NULL; // otherwise it tries to free the fixed buffer
|
||||
}
|
||||
|
||||
ID_INLINE idFixedWinding &idFixedWinding::operator=( const idWinding &winding ) {
|
||||
int i;
|
||||
|
||||
if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
|
||||
numPoints = 0;
|
||||
return *this;
|
||||
}
|
||||
for ( i = 0; i < winding.GetNumPoints(); i++ ) {
|
||||
p[i] = winding[i];
|
||||
}
|
||||
numPoints = winding.GetNumPoints();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ID_INLINE void idFixedWinding::Clear() {
|
||||
numPoints = 0;
|
||||
}
|
||||
#endif /* !__WINDING_H__ */
|
||||
753
neo/idlib/geometry/Winding2D.cpp
Normal file
753
neo/idlib/geometry/Winding2D.cpp
Normal file
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
#include "Winding2D.h"
|
||||
|
||||
/*
|
||||
============
|
||||
GetAxialBevel
|
||||
============
|
||||
*/
|
||||
bool GetAxialBevel( const idVec3 &plane1, const idVec3 &plane2, const idVec2 &point, idVec3 &bevel ) {
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.x ) ^ IEEE_FLT_SIGNBITSET( plane2.x ) ) {
|
||||
if ( idMath::Fabs( plane1.x ) > 0.1f && idMath::Fabs( plane2.x ) > 0.1f ) {
|
||||
bevel.x = 0.0f;
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.y ) ) {
|
||||
bevel.y = -1.0f;
|
||||
}
|
||||
else {
|
||||
bevel.y = 1.0f;
|
||||
}
|
||||
bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.y ) ^ IEEE_FLT_SIGNBITSET( plane2.y ) ) {
|
||||
if ( idMath::Fabs( plane1.y ) > 0.1f && idMath::Fabs( plane2.y ) > 0.1f ) {
|
||||
bevel.y = 0.0f;
|
||||
if ( IEEE_FLT_SIGNBITSET( plane1.x ) ) {
|
||||
bevel.x = -1.0f;
|
||||
}
|
||||
else {
|
||||
bevel.x = 1.0f;
|
||||
}
|
||||
bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::ExpandForAxialBox
|
||||
============
|
||||
*/
|
||||
void idWinding2D::ExpandForAxialBox( const idVec2 bounds[2] ) {
|
||||
int i, j, numPlanes;
|
||||
idVec2 v;
|
||||
idVec3 planes[MAX_POINTS_ON_WINDING_2D], plane, bevel;
|
||||
|
||||
// get planes for the edges and add bevels
|
||||
for ( numPlanes = i = 0; i < numPoints; i++ ) {
|
||||
j = (i+1) % numPoints;
|
||||
if ( ( p[j] - p[i] ).LengthSqr() < 0.01f ) {
|
||||
continue;
|
||||
}
|
||||
plane = Plane2DFromPoints( p[i], p[j], true );
|
||||
if ( i ) {
|
||||
if ( GetAxialBevel( planes[numPlanes-1], plane, p[i], bevel ) ) {
|
||||
planes[numPlanes++] = bevel;
|
||||
}
|
||||
}
|
||||
assert( numPlanes < MAX_POINTS_ON_WINDING_2D );
|
||||
planes[numPlanes++] = plane;
|
||||
}
|
||||
assert( numPlanes < MAX_POINTS_ON_WINDING_2D && numPlanes > 0 );
|
||||
if ( GetAxialBevel( planes[numPlanes-1], planes[0], p[0], bevel ) ) {
|
||||
planes[numPlanes++] = bevel;
|
||||
}
|
||||
|
||||
// expand the planes
|
||||
for ( i = 0; i < numPlanes; i++ ) {
|
||||
v.x = bounds[ IEEE_FLT_SIGNBITSET( planes[i].x ) ].x;
|
||||
v.y = bounds[ IEEE_FLT_SIGNBITSET( planes[i].y ) ].y;
|
||||
planes[i].z += v.x * planes[i].x + v.y * planes[i].y;
|
||||
}
|
||||
|
||||
// get intersection points of the planes
|
||||
for ( numPoints = i = 0; i < numPlanes; i++ ) {
|
||||
if ( Plane2DIntersection( planes[(i+numPlanes-1) % numPlanes], planes[i], p[numPoints] ) ) {
|
||||
numPoints++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::Expand
|
||||
============
|
||||
*/
|
||||
void idWinding2D::Expand( const float d ) {
|
||||
int i;
|
||||
idVec2 edgeNormals[MAX_POINTS_ON_WINDING_2D];
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
idVec2 &start = p[i];
|
||||
idVec2 &end = p[(i+1)%numPoints];
|
||||
edgeNormals[i].x = start.y - end.y;
|
||||
edgeNormals[i].y = end.x - start.x;
|
||||
edgeNormals[i].Normalize();
|
||||
edgeNormals[i] *= d;
|
||||
}
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
p[i] += edgeNormals[i] + edgeNormals[(i+numPoints-1)%numPoints];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::Split
|
||||
=============
|
||||
*/
|
||||
int idWinding2D::Split( const idVec3 &plane, const float epsilon, idWinding2D **front, idWinding2D **back ) const {
|
||||
float dists[MAX_POINTS_ON_WINDING_2D];
|
||||
byte sides[MAX_POINTS_ON_WINDING_2D];
|
||||
int counts[3];
|
||||
float dot;
|
||||
int i, j;
|
||||
const idVec2 * p1, *p2;
|
||||
idVec2 mid;
|
||||
idWinding2D * f;
|
||||
idWinding2D * b;
|
||||
int maxpts;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
dists[i] = dot = plane.x * p[i].x + plane.y * p[i].y + plane.z;
|
||||
if ( dot > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
} else if ( dot < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
} else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
*front = *back = NULL;
|
||||
|
||||
// if nothing at the front of the clipping plane
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
*back = Copy();
|
||||
return SIDE_BACK;
|
||||
}
|
||||
// if nothing at the back of the clipping plane
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
*front = Copy();
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
|
||||
maxpts = numPoints+4; // cant use counts[0]+2 because of fp grouping errors
|
||||
|
||||
*front = f = new (TAG_IDLIB_WINDING) idWinding2D;
|
||||
*back = b = new (TAG_IDLIB_WINDING) idWinding2D;
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
p1 = &p[i];
|
||||
|
||||
if ( sides[i] == SIDE_ON ) {
|
||||
f->p[f->numPoints] = *p1;
|
||||
f->numPoints++;
|
||||
b->p[b->numPoints] = *p1;
|
||||
b->numPoints++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( sides[i] == SIDE_FRONT ) {
|
||||
f->p[f->numPoints] = *p1;
|
||||
f->numPoints++;
|
||||
}
|
||||
|
||||
if ( sides[i] == SIDE_BACK ) {
|
||||
b->p[b->numPoints] = *p1;
|
||||
b->numPoints++;
|
||||
}
|
||||
|
||||
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// generate a split point
|
||||
p2 = &p[(i+1)%numPoints];
|
||||
|
||||
// always calculate the split going from the same side
|
||||
// or minor epsilon issues can happen
|
||||
if ( sides[i] == SIDE_FRONT ) {
|
||||
dot = dists[i] / ( dists[i] - dists[i+1] );
|
||||
for ( j = 0; j < 2; j++ ) {
|
||||
// avoid round off error when possible
|
||||
if ( plane[j] == 1.0f ) {
|
||||
mid[j] = plane.z;
|
||||
} else if ( plane[j] == -1.0f ) {
|
||||
mid[j] = -plane.z;
|
||||
} else {
|
||||
mid[j] = (*p1)[j] + dot * ((*p2)[j] - (*p1)[j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dot = dists[i+1] / ( dists[i+1] - dists[i] );
|
||||
for ( j = 0; j < 2; j++ ) {
|
||||
// avoid round off error when possible
|
||||
if ( plane[j] == 1.0f ) {
|
||||
mid[j] = plane.z;
|
||||
} else if ( plane[j] == -1.0f ) {
|
||||
mid[j] = -plane.z;
|
||||
} else {
|
||||
mid[j] = (*p2)[j] + dot * ( (*p1)[j] - (*p2)[j] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f->p[f->numPoints] = mid;
|
||||
f->numPoints++;
|
||||
b->p[b->numPoints] = mid;
|
||||
b->numPoints++;
|
||||
}
|
||||
|
||||
return SIDE_CROSS;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::ClipInPlace
|
||||
============
|
||||
*/
|
||||
bool idWinding2D::ClipInPlace( const idVec3 &plane, const float epsilon, const bool keepOn ) {
|
||||
int i, j, maxpts, newNumPoints;
|
||||
int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
|
||||
float dot, dists[MAX_POINTS_ON_WINDING_2D+1];
|
||||
idVec2 *p1, *p2, mid, newPoints[MAX_POINTS_ON_WINDING_2D+4];
|
||||
|
||||
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
dists[i] = dot = plane.x * p[i].x + plane.y * p[i].y + plane.z;
|
||||
if ( dot > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
} else if ( dot < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
} else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
// if the winding is on the plane and we should keep it
|
||||
if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
|
||||
return true;
|
||||
}
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
numPoints = 0;
|
||||
return false;
|
||||
}
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
maxpts = numPoints + 4; // cant use counts[0]+2 because of fp grouping errors
|
||||
newNumPoints = 0;
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
p1 = &p[i];
|
||||
|
||||
if ( newNumPoints+1 > maxpts ) {
|
||||
return true; // can't split -- fall back to original
|
||||
}
|
||||
|
||||
if ( sides[i] == SIDE_ON ) {
|
||||
newPoints[newNumPoints] = *p1;
|
||||
newNumPoints++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( sides[i] == SIDE_FRONT ) {
|
||||
newPoints[newNumPoints] = *p1;
|
||||
newNumPoints++;
|
||||
}
|
||||
|
||||
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( newNumPoints+1 > maxpts ) {
|
||||
return true; // can't split -- fall back to original
|
||||
}
|
||||
|
||||
// generate a split point
|
||||
p2 = &p[(i+1)%numPoints];
|
||||
|
||||
dot = dists[i] / (dists[i] - dists[i+1]);
|
||||
for ( j = 0; j < 2; j++ ) {
|
||||
// avoid round off error when possible
|
||||
if ( plane[j] == 1.0f ) {
|
||||
mid[j] = plane.z;
|
||||
} else if ( plane[j] == -1.0f ) {
|
||||
mid[j] = -plane.z;
|
||||
} else {
|
||||
mid[j] = (*p1)[j] + dot * ((*p2)[j] - (*p1)[j]);
|
||||
}
|
||||
}
|
||||
|
||||
newPoints[newNumPoints] = mid;
|
||||
newNumPoints++;
|
||||
}
|
||||
|
||||
if ( newNumPoints >= MAX_POINTS_ON_WINDING_2D ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
numPoints = newNumPoints;
|
||||
memcpy( p, newPoints, newNumPoints * sizeof(idVec2) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::Copy
|
||||
=============
|
||||
*/
|
||||
idWinding2D *idWinding2D::Copy() const {
|
||||
idWinding2D *w;
|
||||
|
||||
w = new (TAG_IDLIB_WINDING) idWinding2D;
|
||||
w->numPoints = numPoints;
|
||||
memcpy( w->p, p, numPoints * sizeof( p[0] ) );
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::Reverse
|
||||
=============
|
||||
*/
|
||||
idWinding2D *idWinding2D::Reverse() const {
|
||||
idWinding2D *w;
|
||||
int i;
|
||||
|
||||
w = new (TAG_IDLIB_WINDING) idWinding2D;
|
||||
w->numPoints = numPoints;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
w->p[ numPoints - i - 1 ] = p[i];
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::GetArea
|
||||
============
|
||||
*/
|
||||
float idWinding2D::GetArea() const {
|
||||
int i;
|
||||
idVec2 d1, d2;
|
||||
float total;
|
||||
|
||||
total = 0.0f;
|
||||
for ( i = 2; i < numPoints; i++ ) {
|
||||
d1 = p[i-1] - p[0];
|
||||
d2 = p[i] - p[0];
|
||||
total += d1.x * d2.y - d1.y * d2.x;
|
||||
}
|
||||
return total * 0.5f;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::GetCenter
|
||||
============
|
||||
*/
|
||||
idVec2 idWinding2D::GetCenter() const {
|
||||
int i;
|
||||
idVec2 center;
|
||||
|
||||
center.Zero();
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
center += p[i];
|
||||
}
|
||||
center *= ( 1.0f / numPoints );
|
||||
return center;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::GetRadius
|
||||
============
|
||||
*/
|
||||
float idWinding2D::GetRadius( const idVec2 ¢er ) const {
|
||||
int i;
|
||||
float radius, r;
|
||||
idVec2 dir;
|
||||
|
||||
radius = 0.0f;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
dir = p[i] - center;
|
||||
r = dir * dir;
|
||||
if ( r > radius ) {
|
||||
radius = r;
|
||||
}
|
||||
}
|
||||
return idMath::Sqrt( radius );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::GetBounds
|
||||
============
|
||||
*/
|
||||
void idWinding2D::GetBounds( idVec2 bounds[2] ) const {
|
||||
int i;
|
||||
|
||||
if ( !numPoints ) {
|
||||
bounds[0].x = bounds[0].y = idMath::INFINITY;
|
||||
bounds[1].x = bounds[1].y = -idMath::INFINITY;
|
||||
return;
|
||||
}
|
||||
bounds[0] = bounds[1] = p[0];
|
||||
for ( i = 1; i < numPoints; i++ ) {
|
||||
if ( p[i].x < bounds[0].x ) {
|
||||
bounds[0].x = p[i].x;
|
||||
} else if ( p[i].x > bounds[1].x ) {
|
||||
bounds[1].x = p[i].x;
|
||||
}
|
||||
if ( p[i].y < bounds[0].y ) {
|
||||
bounds[0].y = p[i].y;
|
||||
} else if ( p[i].y > bounds[1].y ) {
|
||||
bounds[1].y = p[i].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::IsTiny
|
||||
=============
|
||||
*/
|
||||
#define EDGE_LENGTH 0.2f
|
||||
|
||||
bool idWinding2D::IsTiny() const {
|
||||
int i;
|
||||
float len;
|
||||
idVec2 delta;
|
||||
int edges;
|
||||
|
||||
edges = 0;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
delta = p[(i+1)%numPoints] - p[i];
|
||||
len = delta.Length();
|
||||
if ( len > EDGE_LENGTH ) {
|
||||
if ( ++edges == 3 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::IsHuge
|
||||
=============
|
||||
*/
|
||||
bool idWinding2D::IsHuge() const {
|
||||
int i, j;
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
for ( j = 0; j < 2; j++ ) {
|
||||
if ( p[i][j] <= MIN_WORLD_COORD || p[i][j] >= MAX_WORLD_COORD ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::Print
|
||||
=============
|
||||
*/
|
||||
void idWinding2D::Print() const {
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
idLib::common->Printf( "(%5.1f, %5.1f)\n", p[i][0], p[i][1] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::PlaneDistance
|
||||
=============
|
||||
*/
|
||||
float idWinding2D::PlaneDistance( const idVec3 &plane ) const {
|
||||
int i;
|
||||
float d, min, max;
|
||||
|
||||
min = idMath::INFINITY;
|
||||
max = -min;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
d = plane.x * p[i].x + plane.y * p[i].y + plane.z;
|
||||
if ( d < min ) {
|
||||
min = d;
|
||||
if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
if ( d > max ) {
|
||||
max = d;
|
||||
if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
|
||||
return min;
|
||||
}
|
||||
if ( IEEE_FLT_SIGNBITSET( max ) ) {
|
||||
return max;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding2D::PlaneSide
|
||||
=============
|
||||
*/
|
||||
int idWinding2D::PlaneSide( const idVec3 &plane, const float epsilon ) const {
|
||||
bool front, back;
|
||||
int i;
|
||||
float d;
|
||||
|
||||
front = false;
|
||||
back = false;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
d = plane.x * p[i].x + plane.y * p[i].y + plane.z;
|
||||
if ( d < -epsilon ) {
|
||||
if ( front ) {
|
||||
return SIDE_CROSS;
|
||||
}
|
||||
back = true;
|
||||
continue;
|
||||
}
|
||||
else if ( d > epsilon ) {
|
||||
if ( back ) {
|
||||
return SIDE_CROSS;
|
||||
}
|
||||
front = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( back ) {
|
||||
return SIDE_BACK;
|
||||
}
|
||||
if ( front ) {
|
||||
return SIDE_FRONT;
|
||||
}
|
||||
return SIDE_ON;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::PointInside
|
||||
============
|
||||
*/
|
||||
bool idWinding2D::PointInside( const idVec2 &point, const float epsilon ) const {
|
||||
int i;
|
||||
float d;
|
||||
idVec3 plane;
|
||||
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
plane = Plane2DFromPoints( p[i], p[(i+1) % numPoints] );
|
||||
d = plane.x * point.x + plane.y * point.y + plane.z;
|
||||
if ( d > epsilon ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::LineIntersection
|
||||
============
|
||||
*/
|
||||
bool idWinding2D::LineIntersection( const idVec2 &start, const idVec2 &end ) const {
|
||||
int i, numEdges;
|
||||
int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
|
||||
float d1, d2, epsilon = 0.1f;
|
||||
idVec3 plane, edges[2];
|
||||
|
||||
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
|
||||
|
||||
plane = Plane2DFromPoints( start, end );
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z;
|
||||
if ( d1 > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
}
|
||||
else if ( d1 < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
}
|
||||
else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
return false;
|
||||
}
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
numEdges = 0;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) {
|
||||
edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] );
|
||||
if ( numEdges >= 2 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( numEdges < 2 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z;
|
||||
d2 = edges[0].x * end.x + edges[0].y * end.y + edges[0].z;
|
||||
if ( IEEE_FLT_SIGNBITNOTSET( d1 ) & IEEE_FLT_SIGNBITNOTSET( d2 ) ) {
|
||||
return false;
|
||||
}
|
||||
d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z;
|
||||
d2 = edges[1].x * end.x + edges[1].y * end.y + edges[1].z;
|
||||
if ( IEEE_FLT_SIGNBITNOTSET( d1 ) & IEEE_FLT_SIGNBITNOTSET( d2 ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idWinding2D::RayIntersection
|
||||
============
|
||||
*/
|
||||
bool idWinding2D::RayIntersection( const idVec2 &start, const idVec2 &dir, float &scale1, float &scale2, int *edgeNums ) const {
|
||||
int i, numEdges, localEdgeNums[2];
|
||||
int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
|
||||
float d1, d2, epsilon = 0.1f;
|
||||
idVec3 plane, edges[2];
|
||||
|
||||
scale1 = scale2 = 0.0f;
|
||||
counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
|
||||
|
||||
plane = Plane2DFromVecs( start, dir );
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z;
|
||||
if ( d1 > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
}
|
||||
else if ( d1 < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
}
|
||||
else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
|
||||
if ( !counts[SIDE_FRONT] ) {
|
||||
return false;
|
||||
}
|
||||
if ( !counts[SIDE_BACK] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
numEdges = 0;
|
||||
for ( i = 0; i < numPoints; i++ ) {
|
||||
if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) {
|
||||
localEdgeNums[numEdges] = i;
|
||||
edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] );
|
||||
if ( numEdges >= 2 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( numEdges < 2 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z;
|
||||
d2 = - ( edges[0].x * dir.x + edges[0].y * dir.y );
|
||||
if ( d2 == 0.0f ) {
|
||||
return false;
|
||||
}
|
||||
scale1 = d1 / d2;
|
||||
d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z;
|
||||
d2 = - ( edges[1].x * dir.x + edges[1].y * dir.y );
|
||||
if ( d2 == 0.0f ) {
|
||||
return false;
|
||||
}
|
||||
scale2 = d1 / d2;
|
||||
|
||||
if ( idMath::Fabs( scale1 ) > idMath::Fabs( scale2 ) ) {
|
||||
SwapValues( scale1, scale2 );
|
||||
SwapValues( localEdgeNums[0], localEdgeNums[1] );
|
||||
}
|
||||
|
||||
if ( edgeNums ) {
|
||||
edgeNums[0] = localEdgeNums[0];
|
||||
edgeNums[1] = localEdgeNums[1];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
169
neo/idlib/geometry/Winding2D.h
Normal file
169
neo/idlib/geometry/Winding2D.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __WINDING2D_H__
|
||||
#define __WINDING2D_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
A 2D winding is an arbitrary convex 2D polygon defined by an array of points.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define MAX_POINTS_ON_WINDING_2D 16
|
||||
|
||||
|
||||
class idWinding2D {
|
||||
public:
|
||||
idWinding2D();
|
||||
|
||||
idWinding2D & operator=( const idWinding2D &winding );
|
||||
const idVec2 & operator[]( const int index ) const;
|
||||
idVec2 & operator[]( const int index );
|
||||
|
||||
void Clear();
|
||||
void AddPoint( const idVec2 &point );
|
||||
int GetNumPoints() const;
|
||||
|
||||
void Expand( const float d );
|
||||
void ExpandForAxialBox( const idVec2 bounds[2] );
|
||||
|
||||
// splits the winding into a front and back winding, the winding itself stays unchanged
|
||||
// returns a SIDE_?
|
||||
int Split( const idVec3 &plane, const float epsilon, idWinding2D **front, idWinding2D **back ) const;
|
||||
// cuts off the part at the back side of the plane, returns true if some part was at the front
|
||||
// if there is nothing at the front the number of points is set to zero
|
||||
bool ClipInPlace( const idVec3 &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
|
||||
|
||||
idWinding2D * Copy() const;
|
||||
idWinding2D * Reverse() const;
|
||||
|
||||
float GetArea() const;
|
||||
idVec2 GetCenter() const;
|
||||
float GetRadius( const idVec2 ¢er ) const;
|
||||
void GetBounds( idVec2 bounds[2] ) const;
|
||||
|
||||
bool IsTiny() const;
|
||||
bool IsHuge() const; // base winding for a plane is typically huge
|
||||
void Print() const;
|
||||
|
||||
float PlaneDistance( const idVec3 &plane ) const;
|
||||
int PlaneSide( const idVec3 &plane, const float epsilon = ON_EPSILON ) const;
|
||||
|
||||
bool PointInside( const idVec2 &point, const float epsilon ) const;
|
||||
bool LineIntersection( const idVec2 &start, const idVec2 &end ) const;
|
||||
bool RayIntersection( const idVec2 &start, const idVec2 &dir, float &scale1, float &scale2, int *edgeNums = NULL ) const;
|
||||
|
||||
static idVec3 Plane2DFromPoints( const idVec2 &start, const idVec2 &end, const bool normalize = false );
|
||||
static idVec3 Plane2DFromVecs( const idVec2 &start, const idVec2 &dir, const bool normalize = false );
|
||||
static bool Plane2DIntersection( const idVec3 &plane1, const idVec3 &plane2, idVec2 &point );
|
||||
|
||||
private:
|
||||
int numPoints;
|
||||
idVec2 p[MAX_POINTS_ON_WINDING_2D];
|
||||
};
|
||||
|
||||
ID_INLINE idWinding2D::idWinding2D() {
|
||||
numPoints = 0;
|
||||
}
|
||||
|
||||
ID_INLINE idWinding2D &idWinding2D::operator=( const idWinding2D &winding ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < winding.numPoints; i++ ) {
|
||||
p[i] = winding.p[i];
|
||||
}
|
||||
numPoints = winding.numPoints;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ID_INLINE const idVec2 &idWinding2D::operator[]( const int index ) const {
|
||||
return p[ index ];
|
||||
}
|
||||
|
||||
ID_INLINE idVec2 &idWinding2D::operator[]( const int index ) {
|
||||
return p[ index ];
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding2D::Clear() {
|
||||
numPoints = 0;
|
||||
}
|
||||
|
||||
ID_INLINE void idWinding2D::AddPoint( const idVec2 &point ) {
|
||||
p[numPoints++] = point;
|
||||
}
|
||||
|
||||
ID_INLINE int idWinding2D::GetNumPoints() const {
|
||||
return numPoints;
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 idWinding2D::Plane2DFromPoints( const idVec2 &start, const idVec2 &end, const bool normalize ) {
|
||||
idVec3 plane;
|
||||
plane.x = start.y - end.y;
|
||||
plane.y = end.x - start.x;
|
||||
if ( normalize ) {
|
||||
plane.ToVec2().Normalize();
|
||||
}
|
||||
plane.z = - ( start.x * plane.x + start.y * plane.y );
|
||||
return plane;
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 idWinding2D::Plane2DFromVecs( const idVec2 &start, const idVec2 &dir, const bool normalize ) {
|
||||
idVec3 plane;
|
||||
plane.x = -dir.y;
|
||||
plane.y = dir.x;
|
||||
if ( normalize ) {
|
||||
plane.ToVec2().Normalize();
|
||||
}
|
||||
plane.z = - ( start.x * plane.x + start.y * plane.y );
|
||||
return plane;
|
||||
}
|
||||
|
||||
ID_INLINE bool idWinding2D::Plane2DIntersection( const idVec3 &plane1, const idVec3 &plane2, idVec2 &point ) {
|
||||
float n00, n01, n11, det, invDet, f0, f1;
|
||||
|
||||
n00 = plane1.x * plane1.x + plane1.y * plane1.y;
|
||||
n01 = plane1.x * plane2.x + plane1.y * plane2.y;
|
||||
n11 = plane2.x * plane2.x + plane2.y * plane2.y;
|
||||
det = n00 * n11 - n01 * n01;
|
||||
|
||||
if ( idMath::Fabs(det) < 1e-6f ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
invDet = 1.0f / det;
|
||||
f0 = ( n01 * plane2.z - n11 * plane1.z ) * invDet;
|
||||
f1 = ( n01 * plane1.z - n00 * plane2.z ) * invDet;
|
||||
point.x = f0 * plane1.x + f1 * plane2.x;
|
||||
point.y = f0 * plane1.y + f1 * plane2.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* !__WINDING2D_H__ */
|
||||
167
neo/idlib/hashing/CRC32.cpp
Normal file
167
neo/idlib/hashing/CRC32.cpp
Normal 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
18
neo/idlib/hashing/CRC32.h
Normal 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
259
neo/idlib/hashing/MD4.cpp
Normal 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
15
neo/idlib/hashing/MD4.h
Normal 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
304
neo/idlib/hashing/MD5.cpp
Normal 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
24
neo/idlib/hashing/MD5.h
Normal 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
240
neo/idlib/math/Angles.cpp
Normal 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
262
neo/idlib/math/Angles.h
Normal 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__ */
|
||||
41
neo/idlib/math/Complex.cpp
Normal file
41
neo/idlib/math/Complex.cpp
Normal 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
348
neo/idlib/math/Complex.h
Normal 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
2542
neo/idlib/math/Curve.h
Normal file
File diff suppressed because it is too large
Load Diff
219
neo/idlib/math/Extrapolate.h
Normal file
219
neo/idlib/math/Extrapolate.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __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__ */
|
||||
400
neo/idlib/math/Interpolate.h
Normal file
400
neo/idlib/math/Interpolate.h
Normal 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
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
79
neo/idlib/math/Lcp.h
Normal 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
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
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
Reference in New Issue
Block a user