mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-02-08 09:12:30 +00:00
Merge pull request #150 from raynorpat/master
Add back dmap and aas compiler
This commit is contained in:
commit
f86bc286f6
45 changed files with 19973 additions and 169 deletions
|
@ -1049,9 +1049,9 @@ set(RBDOOM3_INCLUDES
|
|||
${DOOMCLASSIC_INCLUDES}
|
||||
${TIMIDITY_INCLUDES}
|
||||
|
||||
#${COMPILER_INCLUDES}
|
||||
#${COMPILER_AAS_INCLUDES} ${COMPILER_AAS_SOURCES}
|
||||
#${COMPILER_DMAP_INCLUDES} ${COMPILER_DMAP_SOURCES}
|
||||
${COMPILER_INCLUDES}
|
||||
${COMPILER_AAS_INCLUDES} ${COMPILER_AAS_SOURCES}
|
||||
${COMPILER_DMAP_INCLUDES} ${COMPILER_DMAP_SOURCES}
|
||||
#${COMPILER_RENDERBUMP_INCLUDES} ${COMPILER_RENDERBUMP_SOURCES}
|
||||
#${COMPILER_ROQVQ_INCLUDES} ${COMPILER_ROQVQ_SOURCES}
|
||||
)
|
||||
|
@ -1084,8 +1084,8 @@ set(RBDOOM3_SOURCES
|
|||
${DOOMCLASSIC_SOURCES}
|
||||
${TIMIDITY_SOURCES}
|
||||
|
||||
#${COMPILER_AAS_SOURCES}
|
||||
#${COMPILER_DMAP_SOURCES}
|
||||
${COMPILER_AAS_SOURCES}
|
||||
${COMPILER_DMAP_SOURCES}
|
||||
#${COMPILER_RENDERBUMP_SOURCES}
|
||||
#${COMPILER_ROQVQ_SOURCES}
|
||||
)
|
||||
|
|
|
@ -4453,6 +4453,14 @@ cmHandle_t idCollisionModelManagerLocal::LoadModel( const char* modelName )
|
|||
|
||||
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( modelName );
|
||||
|
||||
if( models == NULL )
|
||||
{
|
||||
// raynorpat: best clear this if there are no models ( hit by dmap )
|
||||
maxModels = MAX_SUBMODELS;
|
||||
numModels = 0;
|
||||
models = ( cm_model_t** ) Mem_ClearedAlloc( ( maxModels + 1 ) * sizeof( cm_model_t* ), TAG_COLLISION );
|
||||
}
|
||||
|
||||
models[ numModels ] = LoadBinaryModel( generatedFileName, sourceTimeStamp );
|
||||
if( models[ numModels ] != NULL )
|
||||
{
|
||||
|
|
|
@ -1336,6 +1336,9 @@ void idCommonLocal::Init( int argc, const char* const* argv, const char* cmdline
|
|||
// startup the script debugger
|
||||
// DebuggerServerInit();
|
||||
|
||||
// Init tool commands
|
||||
InitCommands();
|
||||
|
||||
// load the game dll
|
||||
LoadGameDLL();
|
||||
|
||||
|
@ -1675,6 +1678,21 @@ void idCommonLocal::BusyWait()
|
|||
session->Pump();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
idCommonLocal::InitCommands
|
||||
===============
|
||||
*/
|
||||
void idCommonLocal::InitCommands( void )
|
||||
{
|
||||
// compilers
|
||||
cmdSystem->AddCommand( "dmap", Dmap_f, CMD_FL_TOOL, "compiles a map", idCmdSystem::ArgCompletion_MapName );
|
||||
cmdSystem->AddCommand( "runAAS", RunAAS_f, CMD_FL_TOOL, "compiles an AAS file for a map", idCmdSystem::ArgCompletion_MapName );
|
||||
cmdSystem->AddCommand( "runAASDir", RunAASDir_f, CMD_FL_TOOL, "compiles AAS files for all maps in a folder", idCmdSystem::ArgCompletion_MapName );
|
||||
cmdSystem->AddCommand( "runReach", RunReach_f, CMD_FL_TOOL, "calculates reachability for an AAS file", idCmdSystem::ArgCompletion_MapName );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idCommonLocal::WaitForSessionState
|
||||
|
|
|
@ -115,18 +115,17 @@ ID_INLINE bool EndTraceRecording()
|
|||
typedef enum
|
||||
{
|
||||
EDITOR_NONE = 0,
|
||||
EDITOR_RADIANT = BIT( 1 ),
|
||||
EDITOR_GUI = BIT( 2 ),
|
||||
EDITOR_DEBUGGER = BIT( 3 ),
|
||||
EDITOR_SCRIPT = BIT( 4 ),
|
||||
EDITOR_LIGHT = BIT( 5 ),
|
||||
EDITOR_SOUND = BIT( 6 ),
|
||||
EDITOR_DECL = BIT( 7 ),
|
||||
EDITOR_AF = BIT( 8 ),
|
||||
EDITOR_PARTICLE = BIT( 9 ),
|
||||
EDITOR_PDA = BIT( 10 ),
|
||||
EDITOR_AAS = BIT( 11 ),
|
||||
EDITOR_MATERIAL = BIT( 12 )
|
||||
EDITOR_GUI = BIT( 1 ),
|
||||
EDITOR_DEBUGGER = BIT( 2 ),
|
||||
EDITOR_SCRIPT = BIT( 3 ),
|
||||
EDITOR_LIGHT = BIT( 4 ),
|
||||
EDITOR_SOUND = BIT( 5 ),
|
||||
EDITOR_DECL = BIT( 6 ),
|
||||
EDITOR_AF = BIT( 7 ),
|
||||
EDITOR_PARTICLE = BIT( 8 ),
|
||||
EDITOR_PDA = BIT( 9 ),
|
||||
EDITOR_AAS = BIT( 10 ),
|
||||
EDITOR_MATERIAL = BIT( 11 )
|
||||
} toolFlag_t;
|
||||
|
||||
#define STRTABLE_ID "#str_"
|
||||
|
|
|
@ -94,7 +94,7 @@ ID_INLINE void idVectorSet<type, dimension>::Init( const type& mins, const type&
|
|||
float boxSize;
|
||||
|
||||
idList<type>::AssureSize( initialSize );
|
||||
idList<type>::SetNum( 0, false );
|
||||
idList<type>::SetNum( 0 );
|
||||
|
||||
hash.Clear( idMath::IPow( boxHashSize, dimension ), initialSize );
|
||||
|
||||
|
|
|
@ -166,6 +166,8 @@ public:
|
|||
void SetTexCoordS( float s );
|
||||
void SetTexCoordT( float t );
|
||||
const idVec2 GetTexCoord() const;
|
||||
const float GetTexCoordS() const;
|
||||
const float GetTexCoordT() const;
|
||||
const halfFloat_t GetTexCoordNativeS() const;
|
||||
const halfFloat_t GetTexCoordNativeT() const;
|
||||
|
||||
|
@ -605,6 +607,26 @@ ID_INLINE const idVec2 idDrawVert::GetTexCoord() const
|
|||
return idVec2( F16toF32( st[0] ), F16toF32( st[1] ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordT
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const float idDrawVert::GetTexCoordS() const
|
||||
{
|
||||
return F16toF32( st[0] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordS
|
||||
========================
|
||||
*/
|
||||
ID_INLINE const float idDrawVert::GetTexCoordT() const
|
||||
{
|
||||
return F16toF32( st[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idDrawVert::GetTexCoordNativeS
|
||||
|
|
|
@ -1398,6 +1398,69 @@ bool idWinding::InsertPointIfOnEdge( const idVec5& point, const idPlane& plane,
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding::InsertPointIfOnEdge
|
||||
=============
|
||||
*/
|
||||
bool idWinding::InsertPointIfOnEdge( const idVec3& point, const idPlane& plane, const float epsilon )
|
||||
{
|
||||
int i;
|
||||
float dist, dot;
|
||||
idVec3 normal;
|
||||
|
||||
// point may not be too far from the winding plane
|
||||
if( idMath::Fabs( plane.Distance( point ) ) > epsilon )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for( i = 0; i < numPoints; i++ )
|
||||
{
|
||||
|
||||
// create plane through edge orthogonal to winding plane
|
||||
normal = ( p[( i + 1 ) % numPoints].ToVec3() - p[i].ToVec3() ).Cross( plane.Normal() );
|
||||
normal.Normalize();
|
||||
dist = normal * p[i].ToVec3();
|
||||
|
||||
if( idMath::Fabs( normal * point - dist ) > epsilon )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
normal = plane.Normal().Cross( normal );
|
||||
dot = normal * point;
|
||||
|
||||
dist = dot - normal * p[i].ToVec3();
|
||||
|
||||
if( dist < epsilon )
|
||||
{
|
||||
// if the winding already has the point
|
||||
if( dist > -epsilon )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dist = dot - normal * p[( i + 1 ) % numPoints].ToVec3();
|
||||
|
||||
if( dist > -epsilon )
|
||||
{
|
||||
// if the winding already has the point
|
||||
if( dist < epsilon )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
InsertPoint( idVec5( point.x, point.y, point.z, 0, 0 ), i + 1 );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
idWinding::IsTiny
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
void RemovePoint( int point );
|
||||
void InsertPoint( const idVec5& point, int spot );
|
||||
bool InsertPointIfOnEdge( const idVec5& point, const idPlane& plane, const float epsilon = ON_EPSILON );
|
||||
bool InsertPointIfOnEdge( const idVec3& point, const idPlane& plane, const float epsilon = ON_EPSILON );
|
||||
// add a winding to the convex hull
|
||||
void AddToConvexHull( const idWinding* winding, const idVec3& normal, const float epsilon = ON_EPSILON );
|
||||
// add a point to the convex hull
|
||||
|
|
|
@ -132,6 +132,9 @@ const int MAX_EXPRESSION_REGISTERS = 4096;
|
|||
#include "../sys/sys_session.h"
|
||||
#include "../sys/sys_achievements.h"
|
||||
|
||||
// tools
|
||||
#include "../tools/compilers/compiler_public.h"
|
||||
|
||||
//-----------------------------------------------------
|
||||
|
||||
#ifndef _D3SDK
|
||||
|
|
|
@ -143,4 +143,5 @@ MEM_TAG( PHYSICS_CLIP_ENTITY )
|
|||
MEM_TAG( PHYSICS_BRITTLE )
|
||||
MEM_TAG( PHYSICS_AF )
|
||||
MEM_TAG( RENDERPROG )
|
||||
MEM_TAG( TOOLS )
|
||||
#undef MEM_TAG
|
||||
|
|
|
@ -29,7 +29,9 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#pragma hdrstop
|
||||
#include "precompiled.h"
|
||||
#include "../snd_local.h"
|
||||
#if defined(USE_DOOMCLASSIC)
|
||||
#include "../../../doomclassic/doom/i_sound.h"
|
||||
#endif
|
||||
|
||||
idCVar s_showLevelMeter( "s_showLevelMeter", "0", CVAR_BOOL | CVAR_ARCHIVE, "Show VU meter" );
|
||||
idCVar s_meterTopTime( "s_meterTopTime", "1000", CVAR_INTEGER | CVAR_ARCHIVE, "How long (in milliseconds) peaks are displayed on the VU meter" );
|
||||
|
@ -336,10 +338,12 @@ void idSoundHardware_XAudio2::Init()
|
|||
|
||||
idSoundVoice::InitSurround( outputChannels, channelMask );
|
||||
|
||||
#if defined(USE_DOOMCLASSIC)
|
||||
// ---------------------
|
||||
// Initialize the Doom classic sound system.
|
||||
// ---------------------
|
||||
I_InitSoundHardware( outputChannels, channelMask );
|
||||
#endif
|
||||
|
||||
// ---------------------
|
||||
// Create VU Meter Effect
|
||||
|
@ -424,10 +428,12 @@ void idSoundHardware_XAudio2::Shutdown()
|
|||
freeVoices.Clear();
|
||||
zombieVoices.Clear();
|
||||
|
||||
#if defined(USE_DOOMCLASSIC)
|
||||
// ---------------------
|
||||
// Shutdown the Doom classic sound system.
|
||||
// ---------------------
|
||||
I_ShutdownSoundHardware();
|
||||
#endif
|
||||
|
||||
if( pXAudio2 != NULL )
|
||||
{
|
||||
|
|
|
@ -258,35 +258,6 @@ void Sys_CPUCount( int& numLogicalCPUCores, int& numPhysicalCPUCores, int& numCP
|
|||
}
|
||||
// RB end
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetSystemRam
|
||||
returns in megabytes
|
||||
================
|
||||
*/
|
||||
int Sys_GetSystemRam()
|
||||
{
|
||||
int mb;
|
||||
long count, page_size;
|
||||
|
||||
count = sysconf( _SC_PHYS_PAGES );
|
||||
if( count == -1 )
|
||||
{
|
||||
common->Printf( "GetSystemRam: sysconf _SC_PHYS_PAGES failed\n" );
|
||||
return 512;
|
||||
}
|
||||
page_size = sysconf( _SC_PAGE_SIZE );
|
||||
if( page_size == -1 )
|
||||
{
|
||||
common->Printf( "GetSystemRam: sysconf _SC_PAGE_SIZE failed\n" );
|
||||
return 512;
|
||||
}
|
||||
mb = ( int )( ( double )count * ( double )page_size / ( 1024 * 1024 ) );
|
||||
// round to the nearest 16Mb
|
||||
mb = ( mb + 8 ) & ~15;
|
||||
return mb;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_DoStartProcess
|
||||
|
|
|
@ -166,32 +166,6 @@ void Sys_CPUCount( int& numLogicalCPUCores, int& numPhysicalCPUCores, int& numCP
|
|||
}
|
||||
// RB end
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetSystemRam
|
||||
returns in megabytes
|
||||
================
|
||||
*/
|
||||
int Sys_GetSystemRam()
|
||||
{
|
||||
int mb, mib[2];
|
||||
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_MEMSIZE;
|
||||
int64_t size = 0;
|
||||
size_t len = sizeof( size );
|
||||
if( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
|
||||
{
|
||||
mb = size / ( 1024 * 1024 );
|
||||
mb = ( mb + 8 ) & ~15;
|
||||
return mb;
|
||||
}
|
||||
|
||||
common->Printf( "GetSystemRam: sysctl HW_MEMSIZE failed\n" );
|
||||
return 512;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_DoStartProcess
|
||||
|
|
|
@ -498,12 +498,6 @@ void Sys_FPU_SetFTZ( bool enable );
|
|||
// sets Denormals-Are-Zero mode (only available when CPUID_DAZ is set)
|
||||
void Sys_FPU_SetDAZ( bool enable );
|
||||
|
||||
// returns amount of system ram
|
||||
int Sys_GetSystemRam();
|
||||
|
||||
// returns amount of video ram
|
||||
int Sys_GetVideoRam();
|
||||
|
||||
// returns amount of drive space in path
|
||||
int Sys_GetDriveFreeSpace( const char* path );
|
||||
|
||||
|
|
|
@ -1140,8 +1140,14 @@ void Sys_Init() {
|
|||
win32.sys_arch.SetString( "Win2K (NT)" );
|
||||
} else if( win32.osversion.dwMajorVersion == 5 && win32.osversion.dwMinorVersion == 1 ) {
|
||||
win32.sys_arch.SetString( "WinXP (NT)" );
|
||||
} else if ( win32.osversion.dwMajorVersion == 6 ) {
|
||||
} else if( win32.osversion.dwMajorVersion == 6 ) {
|
||||
win32.sys_arch.SetString( "Vista" );
|
||||
} else if( win32.osversion.dwMajorVersion == 6 && win32.osversion.dwMinorVersion == 1 ) {
|
||||
win32.sys_arch.SetString( "Win7" );
|
||||
} else if( win32.osversion.dwMajorVersion == 6 && win32.osversion.dwMinorVersion == 2 ) {
|
||||
win32.sys_arch.SetString( "Win8" );
|
||||
} else if( win32.osversion.dwMajorVersion == 6 && win32.osversion.dwMinorVersion == 3 ) {
|
||||
win32.sys_arch.SetString( "Win8.1" );
|
||||
} else {
|
||||
win32.sys_arch.SetString( "Unknown NT variant" );
|
||||
}
|
||||
|
@ -1249,8 +1255,6 @@ void Sys_Init() {
|
|||
}
|
||||
|
||||
common->Printf( "%s\n", win32.sys_cpustring.GetString() );
|
||||
common->Printf( "%d MB System Memory\n", Sys_GetSystemRam() );
|
||||
common->Printf( "%d MB Video Memory\n", Sys_GetVideoRam() );
|
||||
if ( ( win32.cpuid & CPUID_SSE2 ) == 0 ) {
|
||||
common->Error( "SSE2 not supported!" );
|
||||
}
|
||||
|
|
|
@ -92,25 +92,6 @@ uint64 Sys_Microseconds()
|
|||
return ( ( uint64 )( ( int64 )Sys_GetClockTicks() << 10 ) ) / ticksPerMicrosecondTimes1024;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetSystemRam
|
||||
|
||||
returns amount of physical memory in MB
|
||||
================
|
||||
*/
|
||||
int Sys_GetSystemRam()
|
||||
{
|
||||
MEMORYSTATUSEX statex;
|
||||
statex.dwLength = sizeof( statex );
|
||||
GlobalMemoryStatusEx( &statex );
|
||||
int physRam = statex.ullTotalPhys / ( 1024 * 1024 );
|
||||
// HACK: For some reason, ullTotalPhys is sometimes off by a meg or two, so we round up to the nearest 16 megs
|
||||
physRam = ( physRam + 8 ) & ~15;
|
||||
return physRam;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetDriveFreeSpace
|
||||
|
@ -150,74 +131,6 @@ int64 Sys_GetDriveFreeSpaceInBytes( const char* path )
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetVideoRam
|
||||
returns in megabytes
|
||||
================
|
||||
*/
|
||||
int Sys_GetVideoRam()
|
||||
{
|
||||
unsigned int retSize = 64;
|
||||
|
||||
// RB begin
|
||||
#if !defined(__MINGW32__)
|
||||
CComPtr<IWbemLocator> spLoc = NULL;
|
||||
HRESULT hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, ( LPVOID* ) &spLoc );
|
||||
if( hr != S_OK || spLoc == NULL )
|
||||
{
|
||||
return retSize;
|
||||
}
|
||||
|
||||
CComBSTR bstrNamespace( _T( "\\\\.\\root\\CIMV2" ) );
|
||||
CComPtr<IWbemServices> spServices;
|
||||
|
||||
// Connect to CIM
|
||||
hr = spLoc->ConnectServer( bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices );
|
||||
if( hr != WBEM_S_NO_ERROR )
|
||||
{
|
||||
return retSize;
|
||||
}
|
||||
|
||||
// Switch the security level to IMPERSONATE so that provider will grant access to system-level objects.
|
||||
hr = CoSetProxyBlanket( spServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
|
||||
if( hr != S_OK )
|
||||
{
|
||||
return retSize;
|
||||
}
|
||||
|
||||
// Get the vid controller
|
||||
CComPtr<IEnumWbemClassObject> spEnumInst = NULL;
|
||||
hr = spServices->CreateInstanceEnum( CComBSTR( "Win32_VideoController" ), WBEM_FLAG_SHALLOW, NULL, &spEnumInst );
|
||||
if( hr != WBEM_S_NO_ERROR || spEnumInst == NULL )
|
||||
{
|
||||
return retSize;
|
||||
}
|
||||
|
||||
ULONG uNumOfInstances = 0;
|
||||
CComPtr<IWbemClassObject> spInstance = NULL;
|
||||
hr = spEnumInst->Next( 10000, 1, &spInstance, &uNumOfInstances );
|
||||
|
||||
if( hr == S_OK && spInstance )
|
||||
{
|
||||
// Get properties from the object
|
||||
CComVariant varSize;
|
||||
hr = spInstance->Get( CComBSTR( _T( "AdapterRAM" ) ), 0, &varSize, 0, 0 );
|
||||
if( hr == S_OK )
|
||||
{
|
||||
retSize = varSize.intVal / ( 1024 * 1024 );
|
||||
if( retSize == 0 )
|
||||
{
|
||||
retSize = 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// RB end
|
||||
|
||||
return retSize;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetCurrentMemoryStatus
|
||||
|
|
1172
neo/tools/compilers/aas/AASBuild.cpp
Normal file
1172
neo/tools/compilers/aas/AASBuild.cpp
Normal file
File diff suppressed because it is too large
Load diff
559
neo/tools/compilers/aas/AASBuild_file.cpp
Normal file
559
neo/tools/compilers/aas/AASBuild_file.cpp
Normal file
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASBuild_local.h"
|
||||
|
||||
#define VERTEX_HASH_BOXSIZE (1<<6) // must be power of 2
|
||||
#define VERTEX_HASH_SIZE (VERTEX_HASH_BOXSIZE*VERTEX_HASH_BOXSIZE)
|
||||
#define EDGE_HASH_SIZE (1<<14)
|
||||
|
||||
#define INTEGRAL_EPSILON 0.01f
|
||||
#define VERTEX_EPSILON 0.1f
|
||||
|
||||
#define AAS_PLANE_NORMAL_EPSILON 0.00001f
|
||||
#define AAS_PLANE_DIST_EPSILON 0.01f
|
||||
|
||||
|
||||
idHashIndex* aas_vertexHash;
|
||||
idHashIndex* aas_edgeHash;
|
||||
idBounds aas_vertexBounds;
|
||||
int aas_vertexShift;
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::SetupHash
|
||||
================
|
||||
*/
|
||||
void idAASBuild::SetupHash( void )
|
||||
{
|
||||
aas_vertexHash = new idHashIndex( VERTEX_HASH_SIZE, 1024 );
|
||||
aas_edgeHash = new idHashIndex( EDGE_HASH_SIZE, 1024 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::ShutdownHash
|
||||
================
|
||||
*/
|
||||
void idAASBuild::ShutdownHash( void )
|
||||
{
|
||||
delete aas_vertexHash;
|
||||
delete aas_edgeHash;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::ClearHash
|
||||
================
|
||||
*/
|
||||
void idAASBuild::ClearHash( const idBounds& bounds )
|
||||
{
|
||||
int i;
|
||||
float f, max;
|
||||
|
||||
aas_vertexHash->Clear();
|
||||
aas_edgeHash->Clear();
|
||||
aas_vertexBounds = bounds;
|
||||
|
||||
max = bounds[1].x - bounds[0].x;
|
||||
f = bounds[1].y - bounds[0].y;
|
||||
if( f > max )
|
||||
{
|
||||
max = f;
|
||||
}
|
||||
aas_vertexShift = ( float ) max / VERTEX_HASH_BOXSIZE;
|
||||
for( i = 0; ( 1 << i ) < aas_vertexShift; i++ )
|
||||
{
|
||||
}
|
||||
if( i == 0 )
|
||||
{
|
||||
aas_vertexShift = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
aas_vertexShift = i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::HashVec
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idAASBuild::HashVec( const idVec3& vec )
|
||||
{
|
||||
int x, y;
|
||||
|
||||
x = ( ( ( int )( vec[0] - aas_vertexBounds[0].x + 0.5 ) ) + 2 ) >> 2;
|
||||
y = ( ( ( int )( vec[1] - aas_vertexBounds[0].y + 0.5 ) ) + 2 ) >> 2;
|
||||
return ( x + y * VERTEX_HASH_BOXSIZE ) & ( VERTEX_HASH_SIZE - 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::GetVertex
|
||||
================
|
||||
*/
|
||||
bool idAASBuild::GetVertex( const idVec3& v, int* vertexNum )
|
||||
{
|
||||
int i, hashKey, vn;
|
||||
aasVertex_t vert, *p;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
if( idMath::Fabs( v[i] - idMath::Rint( v[i] ) ) < INTEGRAL_EPSILON )
|
||||
{
|
||||
vert[i] = idMath::Rint( v[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
vert[i] = v[i];
|
||||
}
|
||||
}
|
||||
|
||||
hashKey = idAASBuild::HashVec( vert );
|
||||
|
||||
for( vn = aas_vertexHash->First( hashKey ); vn >= 0; vn = aas_vertexHash->Next( vn ) )
|
||||
{
|
||||
p = &file->vertices[vn];
|
||||
// first compare z-axis because hash is based on x-y plane
|
||||
if( idMath::Fabs( vert.z - p->z ) < VERTEX_EPSILON &&
|
||||
idMath::Fabs( vert.x - p->x ) < VERTEX_EPSILON &&
|
||||
idMath::Fabs( vert.y - p->y ) < VERTEX_EPSILON )
|
||||
{
|
||||
*vertexNum = vn;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*vertexNum = file->vertices.Num();
|
||||
aas_vertexHash->Add( hashKey, file->vertices.Num() );
|
||||
file->vertices.Append( vert );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::GetEdge
|
||||
================
|
||||
*/
|
||||
bool idAASBuild::GetEdge( const idVec3& v1, const idVec3& v2, int* edgeNum, int v1num )
|
||||
{
|
||||
int v2num, hashKey, e;
|
||||
int* vertexNum;
|
||||
aasEdge_t edge;
|
||||
bool found;
|
||||
|
||||
if( v1num != -1 )
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = GetVertex( v1, &v1num );
|
||||
}
|
||||
found &= GetVertex( v2, &v2num );
|
||||
// if both vertexes are the same or snapped onto each other
|
||||
if( v1num == v2num )
|
||||
{
|
||||
*edgeNum = 0;
|
||||
return true;
|
||||
}
|
||||
hashKey = aas_edgeHash->GenerateKey( v1num, v2num );
|
||||
// if both vertexes where already stored
|
||||
if( found )
|
||||
{
|
||||
for( e = aas_edgeHash->First( hashKey ); e >= 0; e = aas_edgeHash->Next( e ) )
|
||||
{
|
||||
|
||||
vertexNum = file->edges[e].vertexNum;
|
||||
if( vertexNum[0] == v2num )
|
||||
{
|
||||
if( vertexNum[1] == v1num )
|
||||
{
|
||||
// negative for a reversed edge
|
||||
*edgeNum = -e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( vertexNum[0] == v1num )
|
||||
{
|
||||
if( vertexNum[1] == v2num )
|
||||
{
|
||||
*edgeNum = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if edge found in hash
|
||||
if( e >= 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*edgeNum = file->edges.Num();
|
||||
aas_edgeHash->Add( hashKey, file->edges.Num() );
|
||||
|
||||
edge.vertexNum[0] = v1num;
|
||||
edge.vertexNum[1] = v2num;
|
||||
|
||||
file->edges.Append( edge );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::GetFaceForPortal
|
||||
================
|
||||
*/
|
||||
bool idAASBuild::GetFaceForPortal( idBrushBSPPortal* portal, int side, int* faceNum )
|
||||
{
|
||||
int i, j, v1num;
|
||||
int numFaceEdges, faceEdges[MAX_POINTS_ON_WINDING];
|
||||
idWinding* w;
|
||||
aasFace_t face;
|
||||
|
||||
if( portal->GetFaceNum() > 0 )
|
||||
{
|
||||
if( side )
|
||||
{
|
||||
*faceNum = -portal->GetFaceNum();
|
||||
}
|
||||
else
|
||||
{
|
||||
*faceNum = portal->GetFaceNum();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
w = portal->GetWinding();
|
||||
// turn the winding into a sequence of edges
|
||||
numFaceEdges = 0;
|
||||
v1num = -1; // first vertex unknown
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
{
|
||||
|
||||
GetEdge( ( *w )[i].ToVec3(), ( *w )[( i + 1 ) % w->GetNumPoints()].ToVec3(), &faceEdges[numFaceEdges], v1num );
|
||||
|
||||
if( faceEdges[numFaceEdges] )
|
||||
{
|
||||
// last vertex of this edge is the first vertex of the next edge
|
||||
v1num = file->edges[abs( faceEdges[numFaceEdges] )].vertexNum[INT32_SIGNBITNOTSET( faceEdges[numFaceEdges] )];
|
||||
|
||||
// this edge is valid so keep it
|
||||
numFaceEdges++;
|
||||
}
|
||||
}
|
||||
|
||||
// should have at least 3 edges
|
||||
if( numFaceEdges < 3 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// the polygon is invalid if some edge is found twice
|
||||
for( i = 0; i < numFaceEdges; i++ )
|
||||
{
|
||||
for( j = i + 1; j < numFaceEdges; j++ )
|
||||
{
|
||||
if( faceEdges[i] == faceEdges[j] || faceEdges[i] == -faceEdges[j] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
portal->SetFaceNum( file->faces.Num() );
|
||||
|
||||
face.planeNum = file->planeList.FindPlane( portal->GetPlane(), AAS_PLANE_NORMAL_EPSILON, AAS_PLANE_DIST_EPSILON );
|
||||
face.flags = portal->GetFlags();
|
||||
face.areas[0] = face.areas[1] = 0;
|
||||
face.firstEdge = file->edgeIndex.Num();
|
||||
face.numEdges = numFaceEdges;
|
||||
for( i = 0; i < numFaceEdges; i++ )
|
||||
{
|
||||
file->edgeIndex.Append( faceEdges[i] );
|
||||
}
|
||||
if( side )
|
||||
{
|
||||
*faceNum = -file->faces.Num();
|
||||
}
|
||||
else
|
||||
{
|
||||
*faceNum = file->faces.Num();
|
||||
}
|
||||
file->faces.Append( face );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::GetAreaForLeafNode
|
||||
================
|
||||
*/
|
||||
bool idAASBuild::GetAreaForLeafNode( idBrushBSPNode* node, int* areaNum )
|
||||
{
|
||||
int s, faceNum;
|
||||
idBrushBSPPortal* p;
|
||||
aasArea_t area;
|
||||
|
||||
if( node->GetAreaNum() )
|
||||
{
|
||||
*areaNum = -node->GetAreaNum();
|
||||
return true;
|
||||
}
|
||||
|
||||
area.flags = node->GetFlags();
|
||||
area.cluster = area.clusterAreaNum = 0;
|
||||
area.contents = node->GetContents();
|
||||
area.firstFace = file->faceIndex.Num();
|
||||
area.numFaces = 0;
|
||||
area.reach = NULL;
|
||||
area.rev_reach = NULL;
|
||||
|
||||
for( p = node->GetPortals(); p; p = p->Next( s ) )
|
||||
{
|
||||
s = ( p->GetNode( 1 ) == node );
|
||||
|
||||
if( !GetFaceForPortal( p, s, &faceNum ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
file->faceIndex.Append( faceNum );
|
||||
area.numFaces++;
|
||||
|
||||
if( faceNum > 0 )
|
||||
{
|
||||
file->faces[abs( faceNum )].areas[0] = file->areas.Num();
|
||||
}
|
||||
else
|
||||
{
|
||||
file->faces[abs( faceNum )].areas[1] = file->areas.Num();
|
||||
}
|
||||
}
|
||||
|
||||
if( !area.numFaces )
|
||||
{
|
||||
*areaNum = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
*areaNum = -file->areas.Num();
|
||||
node->SetAreaNum( file->areas.Num() );
|
||||
file->areas.Append( area );
|
||||
|
||||
DisplayRealTimeString( "\r%6d", file->areas.Num() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::StoreTree_r
|
||||
================
|
||||
*/
|
||||
int idAASBuild::StoreTree_r( idBrushBSPNode* node )
|
||||
{
|
||||
int areaNum, nodeNum, child0, child1;
|
||||
aasNode_t aasNode;
|
||||
|
||||
if( !node )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
if( GetAreaForLeafNode( node, &areaNum ) )
|
||||
{
|
||||
return areaNum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
aasNode.planeNum = file->planeList.FindPlane( node->GetPlane(), AAS_PLANE_NORMAL_EPSILON, AAS_PLANE_DIST_EPSILON );
|
||||
aasNode.children[0] = aasNode.children[1] = 0;
|
||||
nodeNum = file->nodes.Num();
|
||||
file->nodes.Append( aasNode );
|
||||
|
||||
// !@#$%^ cause of some bug we cannot set the children directly with the StoreTree_r return value
|
||||
child0 = StoreTree_r( node->GetChild( 0 ) );
|
||||
file->nodes[nodeNum].children[0] = child0;
|
||||
child1 = StoreTree_r( node->GetChild( 1 ) );
|
||||
file->nodes[nodeNum].children[1] = child1;
|
||||
|
||||
if( !child0 && !child1 )
|
||||
{
|
||||
file->nodes.SetNum( file->nodes.Num() - 1 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nodeNum;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::GetSizeEstimate_r
|
||||
================
|
||||
*/
|
||||
typedef struct sizeEstimate_s
|
||||
{
|
||||
int numEdgeIndexes;
|
||||
int numFaceIndexes;
|
||||
int numAreas;
|
||||
int numNodes;
|
||||
} sizeEstimate_t;
|
||||
|
||||
void idAASBuild::GetSizeEstimate_r( idBrushBSPNode* parent, idBrushBSPNode* node, struct sizeEstimate_s& size )
|
||||
{
|
||||
idBrushBSPPortal* p;
|
||||
int s;
|
||||
|
||||
if( !node )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
// multiple branches of the bsp tree might point to the same leaf node
|
||||
if( node->GetParent() == parent )
|
||||
{
|
||||
size.numAreas++;
|
||||
for( p = node->GetPortals(); p; p = p->Next( s ) )
|
||||
{
|
||||
s = ( p->GetNode( 1 ) == node );
|
||||
size.numFaceIndexes++;
|
||||
size.numEdgeIndexes += p->GetWinding()->GetNumPoints();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size.numNodes++;
|
||||
}
|
||||
|
||||
GetSizeEstimate_r( node, node->GetChild( 0 ), size );
|
||||
GetSizeEstimate_r( node, node->GetChild( 1 ), size );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::SetSizeEstimate
|
||||
================
|
||||
*/
|
||||
void idAASBuild::SetSizeEstimate( const idBrushBSP& bsp, idAASFileLocal* file )
|
||||
{
|
||||
sizeEstimate_t size;
|
||||
|
||||
size.numEdgeIndexes = 1;
|
||||
size.numFaceIndexes = 1;
|
||||
size.numAreas = 1;
|
||||
size.numNodes = 1;
|
||||
|
||||
GetSizeEstimate_r( NULL, bsp.GetRootNode(), size );
|
||||
|
||||
file->planeList.Resize( size.numNodes / 2, 1024 );
|
||||
file->vertices.Resize( size.numEdgeIndexes / 3, 1024 );
|
||||
file->edges.Resize( size.numEdgeIndexes / 2, 1024 );
|
||||
file->edgeIndex.Resize( size.numEdgeIndexes, 4096 );
|
||||
file->faces.Resize( size.numFaceIndexes, 1024 );
|
||||
file->faceIndex.Resize( size.numFaceIndexes, 4096 );
|
||||
file->areas.Resize( size.numAreas, 1024 );
|
||||
file->nodes.Resize( size.numNodes, 1024 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASBuild::StoreFile
|
||||
================
|
||||
*/
|
||||
bool idAASBuild::StoreFile( const idBrushBSP& bsp )
|
||||
{
|
||||
aasEdge_t edge;
|
||||
aasFace_t face;
|
||||
aasArea_t area;
|
||||
aasNode_t node;
|
||||
|
||||
common->Printf( "[Store AAS]\n" );
|
||||
|
||||
SetupHash();
|
||||
ClearHash( bsp.GetTreeBounds() );
|
||||
|
||||
file = new idAASFileLocal();
|
||||
|
||||
file->Clear();
|
||||
|
||||
SetSizeEstimate( bsp, file );
|
||||
|
||||
// the first edge is a dummy
|
||||
memset( &edge, 0, sizeof( edge ) );
|
||||
file->edges.Append( edge );
|
||||
|
||||
// the first face is a dummy
|
||||
memset( &face, 0, sizeof( face ) );
|
||||
file->faces.Append( face );
|
||||
|
||||
// the first area is a dummy
|
||||
memset( &area, 0, sizeof( area ) );
|
||||
file->areas.Append( area );
|
||||
|
||||
// the first node is a dummy
|
||||
memset( &node, 0, sizeof( node ) );
|
||||
file->nodes.Append( node );
|
||||
|
||||
// store the tree
|
||||
StoreTree_r( bsp.GetRootNode() );
|
||||
|
||||
// calculate area bounds and a reachable point in the area
|
||||
file->FinishAreas();
|
||||
|
||||
ShutdownHash();
|
||||
|
||||
common->Printf( "\r%6d areas\n", file->areas.Num() );
|
||||
|
||||
return true;
|
||||
}
|
421
neo/tools/compilers/aas/AASBuild_gravity.cpp
Normal file
421
neo/tools/compilers/aas/AASBuild_gravity.cpp
Normal file
|
@ -0,0 +1,421 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASBuild_local.h"
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::SetPortalFlags_r
|
||||
============
|
||||
*/
|
||||
void idAASBuild::SetPortalFlags_r( idBrushBSPNode* node )
|
||||
{
|
||||
int s;
|
||||
idBrushBSPPortal* p;
|
||||
idVec3 normal;
|
||||
|
||||
if( !node )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
for( p = node->GetPortals(); p; p = p->Next( s ) )
|
||||
{
|
||||
s = ( p->GetNode( 1 ) == node );
|
||||
|
||||
// if solid at the other side of the portal
|
||||
if( p->GetNode( !s )->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
if( s )
|
||||
{
|
||||
normal = -p->GetPlane().Normal();
|
||||
}
|
||||
else
|
||||
{
|
||||
normal = p->GetPlane().Normal();
|
||||
}
|
||||
if( normal * aasSettings->invGravityDir > aasSettings->minFloorCos )
|
||||
{
|
||||
p->SetFlag( FACE_FLOOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
p->SetFlag( FACE_SOLID );
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SetPortalFlags_r( node->GetChild( 0 ) );
|
||||
SetPortalFlags_r( node->GetChild( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::PortalIsGap
|
||||
============
|
||||
*/
|
||||
bool idAASBuild::PortalIsGap( idBrushBSPPortal* portal, int side )
|
||||
{
|
||||
idVec3 normal;
|
||||
|
||||
// if solid at the other side of the portal
|
||||
if( portal->GetNode( !side )->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( side )
|
||||
{
|
||||
normal = -( portal->GetPlane().Normal() );
|
||||
}
|
||||
else
|
||||
{
|
||||
normal = portal->GetPlane().Normal();
|
||||
}
|
||||
if( normal * aasSettings->invGravityDir > aasSettings->minFloorCos )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::GravSubdivLeafNode
|
||||
============
|
||||
*/
|
||||
#define FACE_CHECKED BIT(31)
|
||||
#define GRAVSUBDIV_EPSILON 0.1f
|
||||
|
||||
void idAASBuild::GravSubdivLeafNode( idBrushBSPNode* node )
|
||||
{
|
||||
int s1, s2, i, j, k, side1;
|
||||
int numSplits, numSplitters;
|
||||
idBrushBSPPortal* p1, *p2;
|
||||
idWinding* w1, *w2;
|
||||
idVec3 normal;
|
||||
idPlane plane;
|
||||
idPlaneSet planeList;
|
||||
float d, min, max;
|
||||
int* splitterOrder;
|
||||
int* bestNumSplits;
|
||||
int floor, gap, numFloorChecked;
|
||||
|
||||
// if this leaf node is already classified it cannot have a combination of floor and gap portals
|
||||
if( node->GetFlags() & ( AREA_FLOOR | AREA_GAP ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
floor = gap = 0;
|
||||
|
||||
// check if the area has a floor
|
||||
for( p1 = node->GetPortals(); p1; p1 = p1->Next( s1 ) )
|
||||
{
|
||||
s1 = ( p1->GetNode( 1 ) == node );
|
||||
|
||||
if( p1->GetFlags() & FACE_FLOOR )
|
||||
{
|
||||
floor++;
|
||||
}
|
||||
}
|
||||
|
||||
// find seperating planes between gap and floor portals
|
||||
for( p1 = node->GetPortals(); p1; p1 = p1->Next( s1 ) )
|
||||
{
|
||||
s1 = ( p1->GetNode( 1 ) == node );
|
||||
|
||||
// if the portal is a gap seen from this side
|
||||
if( PortalIsGap( p1, s1 ) )
|
||||
{
|
||||
gap++;
|
||||
// if the area doesn't have a floor
|
||||
if( !floor )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numFloorChecked = 0;
|
||||
|
||||
w1 = p1->GetWinding();
|
||||
|
||||
// test all edges of the gap
|
||||
for( i = 0; i < w1->GetNumPoints(); i++ )
|
||||
{
|
||||
|
||||
// create a plane through the edge of the gap parallel to the direction of gravity
|
||||
normal = ( *w1 )[( i + 1 ) % w1->GetNumPoints()].ToVec3() - ( *w1 )[i].ToVec3();
|
||||
normal = normal.Cross( aasSettings->invGravityDir );
|
||||
if( normal.Normalize() < 0.2f )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
plane.SetNormal( normal );
|
||||
plane.FitThroughPoint( ( *w1 )[i].ToVec3() );
|
||||
|
||||
// get the side of the plane the gap is on
|
||||
side1 = w1->PlaneSide( plane, GRAVSUBDIV_EPSILON );
|
||||
if( side1 == SIDE_ON )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// test if the plane through the edge of the gap seperates the gap from a floor portal
|
||||
for( p2 = node->GetPortals(); p2; p2 = p2->Next( s2 ) )
|
||||
{
|
||||
s2 = ( p2->GetNode( 1 ) == node );
|
||||
|
||||
if( !( p2->GetFlags() & FACE_FLOOR ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( p2->GetFlags() & FACE_CHECKED )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
w2 = p2->GetWinding();
|
||||
|
||||
min = 2.0f * GRAVSUBDIV_EPSILON;
|
||||
max = GRAVSUBDIV_EPSILON;
|
||||
if( side1 == SIDE_FRONT )
|
||||
{
|
||||
for( j = 0; j < w2->GetNumPoints(); j++ )
|
||||
{
|
||||
d = plane.Distance( ( *w2 )[j].ToVec3() );
|
||||
if( d >= GRAVSUBDIV_EPSILON )
|
||||
{
|
||||
break; // point at the same side of the plane as the gap
|
||||
}
|
||||
d = idMath::Fabs( d );
|
||||
if( d < min )
|
||||
{
|
||||
min = d;
|
||||
}
|
||||
if( d > max )
|
||||
{
|
||||
max = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( j = 0; j < w2->GetNumPoints(); j++ )
|
||||
{
|
||||
d = plane.Distance( ( *w2 )[j].ToVec3() );
|
||||
if( d <= -GRAVSUBDIV_EPSILON )
|
||||
{
|
||||
break; // point at the same side of the plane as the gap
|
||||
}
|
||||
d = idMath::Fabs( d );
|
||||
if( d < min )
|
||||
{
|
||||
min = d;
|
||||
}
|
||||
if( d > max )
|
||||
{
|
||||
max = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a point of the floor portal was found to be at the same side of the plane as the gap
|
||||
if( j < w2->GetNumPoints() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the floor portal touches the plane
|
||||
if( min < GRAVSUBDIV_EPSILON && max > GRAVSUBDIV_EPSILON )
|
||||
{
|
||||
planeList.FindPlane( plane, 0.00001f, 0.1f );
|
||||
}
|
||||
|
||||
p2->SetFlag( FACE_CHECKED );
|
||||
numFloorChecked++;
|
||||
|
||||
}
|
||||
if( numFloorChecked == floor )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( p2 = node->GetPortals(); p2; p2 = p2->Next( s2 ) )
|
||||
{
|
||||
s2 = ( p2->GetNode( 1 ) == node );
|
||||
p2->RemoveFlag( FACE_CHECKED );
|
||||
}
|
||||
}
|
||||
|
||||
// if the leaf node does not have both floor and gap portals
|
||||
if( !( gap && floor ) )
|
||||
{
|
||||
if( floor )
|
||||
{
|
||||
node->SetFlag( AREA_FLOOR );
|
||||
}
|
||||
else if( gap )
|
||||
{
|
||||
node->SetFlag( AREA_GAP );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if no valid seperators found
|
||||
if( planeList.Num() == 0 )
|
||||
{
|
||||
// NOTE: this should never happend, if it does the leaf node has degenerate portals
|
||||
return;
|
||||
}
|
||||
|
||||
splitterOrder = ( int* ) _alloca( planeList.Num() * sizeof( int ) );
|
||||
bestNumSplits = ( int* ) _alloca( planeList.Num() * sizeof( int ) );
|
||||
numSplitters = 0;
|
||||
|
||||
// test all possible seperators and sort them from best to worst
|
||||
for( i = 0; i < planeList.Num(); i += 2 )
|
||||
{
|
||||
numSplits = 0;
|
||||
|
||||
for( p1 = node->GetPortals(); p1; p1 = p1->Next( s1 ) )
|
||||
{
|
||||
s1 = ( p1->GetNode( 1 ) == node );
|
||||
if( p1->GetWinding()->PlaneSide( planeList[i], 0.1f ) == SIDE_CROSS )
|
||||
{
|
||||
numSplits++;
|
||||
}
|
||||
}
|
||||
|
||||
for( j = 0; j < numSplitters; j++ )
|
||||
{
|
||||
if( numSplits < bestNumSplits[j] )
|
||||
{
|
||||
for( k = numSplitters; k > j; k-- )
|
||||
{
|
||||
bestNumSplits[k] = bestNumSplits[k - 1];
|
||||
splitterOrder[k] = splitterOrder[k - 1];
|
||||
}
|
||||
bestNumSplits[j] = numSplits;
|
||||
splitterOrder[j] = i;
|
||||
numSplitters++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j >= numSplitters )
|
||||
{
|
||||
bestNumSplits[j] = numSplits;
|
||||
splitterOrder[j] = i;
|
||||
numSplitters++;
|
||||
}
|
||||
}
|
||||
|
||||
// try all seperators in order from best to worst
|
||||
for( i = 0; i < numSplitters; i++ )
|
||||
{
|
||||
if( node->Split( planeList[splitterOrder[i]], -1 ) )
|
||||
{
|
||||
// we found a seperator that works
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i >= numSplitters )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayRealTimeString( "\r%6d", ++numGravitationalSubdivisions );
|
||||
|
||||
// test children for further splits
|
||||
GravSubdivLeafNode( node->GetChild( 0 ) );
|
||||
GravSubdivLeafNode( node->GetChild( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::GravSubdiv_r
|
||||
============
|
||||
*/
|
||||
void idAASBuild::GravSubdiv_r( idBrushBSPNode* node )
|
||||
{
|
||||
|
||||
if( !node )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
GravSubdivLeafNode( node );
|
||||
return;
|
||||
}
|
||||
|
||||
GravSubdiv_r( node->GetChild( 0 ) );
|
||||
GravSubdiv_r( node->GetChild( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::GravitationalSubdivision
|
||||
============
|
||||
*/
|
||||
void idAASBuild::GravitationalSubdivision( idBrushBSP& bsp )
|
||||
{
|
||||
numGravitationalSubdivisions = 0;
|
||||
|
||||
common->Printf( "[Gravitational Subdivision]\n" );
|
||||
|
||||
SetPortalFlags_r( bsp.GetRootNode() );
|
||||
GravSubdiv_r( bsp.GetRootNode() );
|
||||
|
||||
common->Printf( "\r%6d subdivisions\n", numGravitationalSubdivisions );
|
||||
}
|
652
neo/tools/compilers/aas/AASBuild_ledge.cpp
Normal file
652
neo/tools/compilers/aas/AASBuild_ledge.cpp
Normal file
|
@ -0,0 +1,652 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASBuild_local.h"
|
||||
|
||||
#define LEDGE_EPSILON 0.1f
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idLedge
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::idLedge
|
||||
============
|
||||
*/
|
||||
idLedge::idLedge( void )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::idLedge
|
||||
============
|
||||
*/
|
||||
idLedge::idLedge( const idVec3& v1, const idVec3& v2, const idVec3& gravityDir, idBrushBSPNode* n )
|
||||
{
|
||||
start = v1;
|
||||
end = v2;
|
||||
node = n;
|
||||
numPlanes = 4;
|
||||
planes[0].SetNormal( ( v1 - v2 ).Cross( gravityDir ) );
|
||||
planes[0].Normalize();
|
||||
planes[0].FitThroughPoint( v1 );
|
||||
planes[1].SetNormal( ( v1 - v2 ).Cross( planes[0].Normal() ) );
|
||||
planes[1].Normalize();
|
||||
planes[1].FitThroughPoint( v1 );
|
||||
planes[2].SetNormal( v1 - v2 );
|
||||
planes[2].Normalize();
|
||||
planes[2].FitThroughPoint( v1 );
|
||||
planes[3].SetNormal( v2 - v1 );
|
||||
planes[3].Normalize();
|
||||
planes[3].FitThroughPoint( v2 );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::AddPoint
|
||||
============
|
||||
*/
|
||||
void idLedge::AddPoint( const idVec3& v )
|
||||
{
|
||||
if( planes[2].Distance( v ) > 0.0f )
|
||||
{
|
||||
start = v;
|
||||
planes[2].FitThroughPoint( start );
|
||||
}
|
||||
if( planes[3].Distance( v ) > 0.0f )
|
||||
{
|
||||
end = v;
|
||||
planes[3].FitThroughPoint( end );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::CreateBevels
|
||||
|
||||
NOTE: this assumes the gravity is vertical
|
||||
============
|
||||
*/
|
||||
void idLedge::CreateBevels( const idVec3& gravityDir )
|
||||
{
|
||||
int i, j;
|
||||
idBounds bounds;
|
||||
idVec3 size, normal;
|
||||
|
||||
bounds.Clear();
|
||||
bounds.AddPoint( start );
|
||||
bounds.AddPoint( end );
|
||||
size = bounds[1] - bounds[0];
|
||||
|
||||
// plane through ledge
|
||||
planes[0].SetNormal( ( start - end ).Cross( gravityDir ) );
|
||||
planes[0].Normalize();
|
||||
planes[0].FitThroughPoint( start );
|
||||
// axial bevels at start and end point
|
||||
i = size[1] > size[0];
|
||||
normal = vec3_origin;
|
||||
normal[i] = 1.0f;
|
||||
j = end[i] > start[i];
|
||||
planes[1 + j].SetNormal( normal );
|
||||
planes[1 + !j].SetNormal( -normal );
|
||||
planes[1].FitThroughPoint( start );
|
||||
planes[2].FitThroughPoint( end );
|
||||
numExpandedPlanes = 3;
|
||||
// if additional bevels are required
|
||||
if( idMath::Fabs( size[!i] ) > 0.01f )
|
||||
{
|
||||
normal = vec3_origin;
|
||||
normal[!i] = 1.0f;
|
||||
j = end[!i] > start[!i];
|
||||
planes[3 + j].SetNormal( normal );
|
||||
planes[3 + !j].SetNormal( -normal );
|
||||
planes[3].FitThroughPoint( start );
|
||||
planes[4].FitThroughPoint( end );
|
||||
numExpandedPlanes = 5;
|
||||
}
|
||||
// opposite of first
|
||||
planes[numExpandedPlanes + 0] = -planes[0];
|
||||
// number of planes used for splitting
|
||||
numSplitPlanes = numExpandedPlanes + 1;
|
||||
// top plane
|
||||
planes[numSplitPlanes + 0].SetNormal( ( start - end ).Cross( planes[0].Normal() ) );
|
||||
planes[numSplitPlanes + 0].Normalize();
|
||||
planes[numSplitPlanes + 0].FitThroughPoint( start );
|
||||
// bottom plane
|
||||
planes[numSplitPlanes + 1] = -planes[numSplitPlanes + 0];
|
||||
// total number of planes
|
||||
numPlanes = numSplitPlanes + 2;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::Expand
|
||||
============
|
||||
*/
|
||||
void idLedge::Expand( const idBounds& bounds, float maxStepHeight )
|
||||
{
|
||||
int i, j;
|
||||
idVec3 v;
|
||||
|
||||
for( i = 0; i < numExpandedPlanes; i++ )
|
||||
{
|
||||
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
if( planes[i].Normal()[j] > 0.0f )
|
||||
{
|
||||
v[j] = bounds[0][j];
|
||||
}
|
||||
else
|
||||
{
|
||||
v[j] = bounds[1][j];
|
||||
}
|
||||
}
|
||||
|
||||
planes[i].SetDist( planes[i].Dist() + v * -planes[i].Normal() );
|
||||
}
|
||||
|
||||
planes[numSplitPlanes + 0].SetDist( planes[numSplitPlanes + 0].Dist() + maxStepHeight );
|
||||
planes[numSplitPlanes + 1].SetDist( planes[numSplitPlanes + 1].Dist() + 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::ChopWinding
|
||||
============
|
||||
*/
|
||||
idWinding* idLedge::ChopWinding( const idWinding* winding ) const
|
||||
{
|
||||
int i;
|
||||
idWinding* w;
|
||||
|
||||
w = winding->Copy();
|
||||
for( i = 0; i < numPlanes && w; i++ )
|
||||
{
|
||||
w = w->Clip( -planes[i], ON_EPSILON, true );
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idLedge::PointBetweenBounds
|
||||
============
|
||||
*/
|
||||
bool idLedge::PointBetweenBounds( const idVec3& v ) const
|
||||
{
|
||||
return ( planes[2].Distance( v ) < LEDGE_EPSILON ) && ( planes[3].Distance( v ) < LEDGE_EPSILON );
|
||||
}
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idAASBuild
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::LedgeSubdivFlood_r
|
||||
============
|
||||
*/
|
||||
void idAASBuild::LedgeSubdivFlood_r( idBrushBSPNode* node, const idLedge* ledge )
|
||||
{
|
||||
int s1, i;
|
||||
idBrushBSPPortal* p1;
|
||||
idWinding* w;
|
||||
idList<idBrushBSPNode*> nodeList;
|
||||
|
||||
if( node->GetFlags() & NODE_VISITED )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if this is not already a ledge area
|
||||
if( !( node->GetFlags() & AREA_LEDGE ) )
|
||||
{
|
||||
for( p1 = node->GetPortals(); p1; p1 = p1->Next( s1 ) )
|
||||
{
|
||||
s1 = ( p1->GetNode( 1 ) == node );
|
||||
|
||||
if( !( p1->GetFlags() & FACE_FLOOR ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// split the area if some part of the floor portal is inside the expanded ledge
|
||||
w = ledge->ChopWinding( p1->GetWinding() );
|
||||
if( !w )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
delete w;
|
||||
|
||||
for( i = 0; i < ledge->numSplitPlanes; i++ )
|
||||
{
|
||||
if( node->PlaneSide( ledge->planes[i], 0.1f ) != SIDE_CROSS )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !node->Split( ledge->planes[i], -1 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
numLedgeSubdivisions++;
|
||||
DisplayRealTimeString( "\r%6d", numLedgeSubdivisions );
|
||||
node->GetChild( 0 )->SetFlag( NODE_VISITED );
|
||||
LedgeSubdivFlood_r( node->GetChild( 1 ), ledge );
|
||||
return;
|
||||
}
|
||||
|
||||
node->SetFlag( AREA_LEDGE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node->SetFlag( NODE_VISITED );
|
||||
|
||||
// get all nodes we might need to flood into
|
||||
for( p1 = node->GetPortals(); p1; p1 = p1->Next( s1 ) )
|
||||
{
|
||||
s1 = ( p1->GetNode( 1 ) == node );
|
||||
|
||||
if( p1->GetNode( !s1 )->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// flood through this portal if the portal is partly inside the expanded ledge
|
||||
w = ledge->ChopWinding( p1->GetWinding() );
|
||||
if( !w )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
delete w;
|
||||
// add to list, cannot flood directly cause portals might be split on the way
|
||||
nodeList.Append( p1->GetNode( !s1 ) );
|
||||
}
|
||||
|
||||
// flood into other nodes
|
||||
for( i = 0; i < nodeList.Num(); i++ )
|
||||
{
|
||||
LedgeSubdivLeafNodes_r( nodeList[i], ledge );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::LedgeSubdivLeafNodes_r
|
||||
|
||||
The node the ledge was originally part of might be split by other ledges.
|
||||
Here we recurse down the tree from the original node to find all the new leaf nodes the ledge might be part of.
|
||||
============
|
||||
*/
|
||||
void idAASBuild::LedgeSubdivLeafNodes_r( idBrushBSPNode* node, const idLedge* ledge )
|
||||
{
|
||||
if( !node )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
LedgeSubdivFlood_r( node, ledge );
|
||||
return;
|
||||
}
|
||||
LedgeSubdivLeafNodes_r( node->GetChild( 0 ), ledge );
|
||||
LedgeSubdivLeafNodes_r( node->GetChild( 1 ), ledge );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::LedgeSubdiv
|
||||
============
|
||||
*/
|
||||
void idAASBuild::LedgeSubdiv( idBrushBSPNode* root )
|
||||
{
|
||||
int i, j;
|
||||
idBrush* brush;
|
||||
idList<idBrushSide*> sideList;
|
||||
|
||||
// create ledge bevels and expand ledges
|
||||
for( i = 0; i < ledgeList.Num(); i++ )
|
||||
{
|
||||
|
||||
ledgeList[i].CreateBevels( aasSettings->gravityDir );
|
||||
ledgeList[i].Expand( aasSettings->boundingBoxes[0], aasSettings->maxStepHeight );
|
||||
|
||||
// if we should write out a ledge map
|
||||
if( ledgeMap )
|
||||
{
|
||||
sideList.SetNum( 0 );
|
||||
for( j = 0; j < ledgeList[i].numPlanes; j++ )
|
||||
{
|
||||
sideList.Append( new idBrushSide( ledgeList[i].planes[j], -1 ) );
|
||||
}
|
||||
|
||||
brush = new idBrush();
|
||||
brush->FromSides( sideList );
|
||||
|
||||
ledgeMap->WriteBrush( brush );
|
||||
|
||||
delete brush;
|
||||
}
|
||||
|
||||
// flood tree from the ledge node and subdivide areas with the ledge
|
||||
LedgeSubdivLeafNodes_r( ledgeList[i].node, &ledgeList[i] );
|
||||
|
||||
// remove the node visited flags
|
||||
ledgeList[i].node->RemoveFlagRecurseFlood( NODE_VISITED );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::IsLedgeSide_r
|
||||
============
|
||||
*/
|
||||
bool idAASBuild::IsLedgeSide_r( idBrushBSPNode* node, idFixedWinding* w, const idPlane& plane, const idVec3& normal, const idVec3& origin, const float radius )
|
||||
{
|
||||
int res, i;
|
||||
idFixedWinding back;
|
||||
float dist;
|
||||
|
||||
if( !node )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while( node->GetChild( 0 ) && node->GetChild( 1 ) )
|
||||
{
|
||||
dist = node->GetPlane().Distance( origin );
|
||||
if( dist > radius )
|
||||
{
|
||||
res = SIDE_FRONT;
|
||||
}
|
||||
else if( dist < -radius )
|
||||
{
|
||||
res = SIDE_BACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = w->Split( &back, node->GetPlane(), LEDGE_EPSILON );
|
||||
}
|
||||
if( res == SIDE_FRONT )
|
||||
{
|
||||
node = node->GetChild( 0 );
|
||||
}
|
||||
else if( res == SIDE_BACK )
|
||||
{
|
||||
node = node->GetChild( 1 );
|
||||
}
|
||||
else if( res == SIDE_ON )
|
||||
{
|
||||
// continue with the side the winding faces
|
||||
if( node->GetPlane().Normal() * normal > 0.0f )
|
||||
{
|
||||
node = node->GetChild( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->GetChild( 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( IsLedgeSide_r( node->GetChild( 1 ), &back, plane, normal, origin, radius ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
node = node->GetChild( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
{
|
||||
if( plane.Distance( ( *w )[i].ToVec3() ) > 0.0f )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::AddLedge
|
||||
============
|
||||
*/
|
||||
void idAASBuild::AddLedge( const idVec3& v1, const idVec3& v2, idBrushBSPNode* node )
|
||||
{
|
||||
int i, j, merged;
|
||||
|
||||
// first try to merge the ledge with existing ledges
|
||||
merged = -1;
|
||||
for( i = 0; i < ledgeList.Num(); i++ )
|
||||
{
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
if( idMath::Fabs( ledgeList[i].planes[j].Distance( v1 ) ) > LEDGE_EPSILON )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if( idMath::Fabs( ledgeList[i].planes[j].Distance( v2 ) ) > LEDGE_EPSILON )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j < 2 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !ledgeList[i].PointBetweenBounds( v1 ) &&
|
||||
!ledgeList[i].PointBetweenBounds( v2 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( merged == -1 )
|
||||
{
|
||||
ledgeList[i].AddPoint( v1 );
|
||||
ledgeList[i].AddPoint( v2 );
|
||||
merged = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
ledgeList[merged].AddPoint( ledgeList[i].start );
|
||||
ledgeList[merged].AddPoint( ledgeList[i].end );
|
||||
ledgeList.RemoveIndex( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if the ledge could not be merged
|
||||
if( merged == -1 )
|
||||
{
|
||||
ledgeList.Append( idLedge( v1, v2, aasSettings->gravityDir, node ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::FindLeafNodeLedges
|
||||
============
|
||||
*/
|
||||
void idAASBuild::FindLeafNodeLedges( idBrushBSPNode* root, idBrushBSPNode* node )
|
||||
{
|
||||
int s1, i;
|
||||
idBrushBSPPortal* p1;
|
||||
idWinding* w;
|
||||
idVec3 v1, v2, normal, origin;
|
||||
idFixedWinding winding;
|
||||
idBounds bounds;
|
||||
idPlane plane;
|
||||
float radius;
|
||||
|
||||
for( p1 = node->GetPortals(); p1; p1 = p1->Next( s1 ) )
|
||||
{
|
||||
s1 = ( p1->GetNode( 1 ) == node );
|
||||
|
||||
if( !( p1->GetFlags() & FACE_FLOOR ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( s1 )
|
||||
{
|
||||
plane = p1->GetPlane();
|
||||
w = p1->GetWinding()->Reverse();
|
||||
}
|
||||
else
|
||||
{
|
||||
plane = -p1->GetPlane();
|
||||
w = p1->GetWinding();
|
||||
}
|
||||
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
{
|
||||
|
||||
v1 = ( *w )[i].ToVec3();
|
||||
v2 = ( *w )[( i + 1 ) % w->GetNumPoints()].ToVec3();
|
||||
normal = ( v2 - v1 ).Cross( aasSettings->gravityDir );
|
||||
if( normal.Normalize() < 0.5f )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
winding.Clear();
|
||||
winding += v1 + normal * LEDGE_EPSILON * 0.5f;
|
||||
winding += v2 + normal * LEDGE_EPSILON * 0.5f;
|
||||
winding += winding[1].ToVec3() + ( aasSettings->maxStepHeight + 1.0f ) * aasSettings->gravityDir;
|
||||
winding += winding[0].ToVec3() + ( aasSettings->maxStepHeight + 1.0f ) * aasSettings->gravityDir;
|
||||
|
||||
winding.GetBounds( bounds );
|
||||
origin = ( bounds[1] - bounds[0] ) * 0.5f;
|
||||
radius = origin.Length() + LEDGE_EPSILON;
|
||||
origin = bounds[0] + origin;
|
||||
|
||||
plane.FitThroughPoint( v1 + aasSettings->maxStepHeight * aasSettings->gravityDir );
|
||||
|
||||
if( !IsLedgeSide_r( root, &winding, plane, normal, origin, radius ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddLedge( v1, v2, node );
|
||||
}
|
||||
|
||||
if( w != p1->GetWinding() )
|
||||
{
|
||||
delete w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::FindLedges_r
|
||||
============
|
||||
*/
|
||||
void idAASBuild::FindLedges_r( idBrushBSPNode* root, idBrushBSPNode* node )
|
||||
{
|
||||
if( !node )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
if( node->GetFlags() & NODE_VISITED )
|
||||
{
|
||||
return;
|
||||
}
|
||||
FindLeafNodeLedges( root, node );
|
||||
node->SetFlag( NODE_VISITED );
|
||||
return;
|
||||
}
|
||||
|
||||
FindLedges_r( root, node->GetChild( 0 ) );
|
||||
FindLedges_r( root, node->GetChild( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::WriteLedgeMap
|
||||
============
|
||||
*/
|
||||
void idAASBuild::WriteLedgeMap( const idStr& fileName, const idStr& ext )
|
||||
{
|
||||
ledgeMap = new idBrushMap( fileName, ext );
|
||||
ledgeMap->SetTexture( "textures/base_trim/bluetex4q_ed" );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::LedgeSubdivision
|
||||
|
||||
NOTE: this assumes the bounding box is higher than the maximum step height
|
||||
only ledges with vertical sides are considered
|
||||
============
|
||||
*/
|
||||
void idAASBuild::LedgeSubdivision( idBrushBSP& bsp )
|
||||
{
|
||||
numLedgeSubdivisions = 0;
|
||||
ledgeList.Clear();
|
||||
|
||||
common->Printf( "[Ledge Subdivision]\n" );
|
||||
|
||||
bsp.GetRootNode()->RemoveFlagRecurse( NODE_VISITED );
|
||||
FindLedges_r( bsp.GetRootNode(), bsp.GetRootNode() );
|
||||
bsp.GetRootNode()->RemoveFlagRecurse( NODE_VISITED );
|
||||
|
||||
common->Printf( "\r%6d ledges\n", ledgeList.Num() );
|
||||
|
||||
LedgeSubdiv( bsp.GetRootNode() );
|
||||
|
||||
common->Printf( "\r%6d subdivisions\n", numLedgeSubdivisions );
|
||||
}
|
152
neo/tools/compilers/aas/AASBuild_local.h
Normal file
152
neo/tools/compilers/aas/AASBuild_local.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __AASBUILD_LOCAL_H__
|
||||
#define __AASBUILD_LOCAL_H__
|
||||
|
||||
#include "..\..\aas\AASFile.h"
|
||||
#include "..\..\aas\AASFile_local.h"
|
||||
|
||||
#include "Brush.h"
|
||||
#include "BrushBSP.h"
|
||||
#include "AASReach.h"
|
||||
#include "AASCluster.h"
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idAASBuild
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
typedef struct aasProcNode_s
|
||||
{
|
||||
idPlane plane;
|
||||
int children[2]; // negative numbers are (-1 - areaNumber), 0 = solid
|
||||
} aasProcNode_t;
|
||||
|
||||
|
||||
class idLedge
|
||||
{
|
||||
|
||||
public:
|
||||
idVec3 start;
|
||||
idVec3 end;
|
||||
idBrushBSPNode* node;
|
||||
int numExpandedPlanes;
|
||||
int numSplitPlanes;
|
||||
int numPlanes;
|
||||
idPlane planes[8];
|
||||
|
||||
public:
|
||||
idLedge( void );
|
||||
idLedge( const idVec3& v1, const idVec3& v2, const idVec3& gravityDir, idBrushBSPNode* n );
|
||||
void AddPoint( const idVec3& v );
|
||||
void CreateBevels( const idVec3& gravityDir );
|
||||
void Expand( const idBounds& bounds, float maxStepHeight );
|
||||
idWinding* ChopWinding( const idWinding* winding ) const;
|
||||
bool PointBetweenBounds( const idVec3& v ) const;
|
||||
};
|
||||
|
||||
|
||||
class idAASBuild
|
||||
{
|
||||
|
||||
public:
|
||||
idAASBuild( void );
|
||||
~idAASBuild( void );
|
||||
bool Build( const idStr& fileName, const idAASSettings* settings );
|
||||
bool BuildReachability( const idStr& fileName, const idAASSettings* settings );
|
||||
void Shutdown( void );
|
||||
|
||||
private:
|
||||
const idAASSettings* aasSettings;
|
||||
idAASFileLocal* file;
|
||||
aasProcNode_t* procNodes;
|
||||
int numProcNodes;
|
||||
int numGravitationalSubdivisions;
|
||||
int numMergedLeafNodes;
|
||||
int numLedgeSubdivisions;
|
||||
idList<idLedge> ledgeList;
|
||||
idBrushMap* ledgeMap;
|
||||
|
||||
private: // map loading
|
||||
void ParseProcNodes( idLexer* src );
|
||||
bool LoadProcBSP( const char* name, ID_TIME_T minFileTime );
|
||||
void DeleteProcBSP( void );
|
||||
bool ChoppedAwayByProcBSP( int nodeNum, idFixedWinding* w, const idVec3& normal, const idVec3& origin, const float radius );
|
||||
void ClipBrushSidesWithProcBSP( idBrushList& brushList );
|
||||
int ContentsForAAS( int contents );
|
||||
idBrushList AddBrushesForMapBrush( const idMapBrush* mapBrush, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList );
|
||||
idBrushList AddBrushesForMapPatch( const idMapPatch* mapPatch, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList );
|
||||
idBrushList AddBrushesForMapEntity( const idMapEntity* mapEnt, int entityNum, idBrushList brushList );
|
||||
idBrushList AddBrushesForMapFile( const idMapFile* mapFile, idBrushList brushList );
|
||||
bool CheckForEntities( const idMapFile* mapFile, idStrList& entityClassNames ) const;
|
||||
void ChangeMultipleBoundingBoxContents_r( idBrushBSPNode* node, int mask );
|
||||
|
||||
private: // gravitational subdivision
|
||||
void SetPortalFlags_r( idBrushBSPNode* node );
|
||||
bool PortalIsGap( idBrushBSPPortal* portal, int side );
|
||||
void GravSubdivLeafNode( idBrushBSPNode* node );
|
||||
void GravSubdiv_r( idBrushBSPNode* node );
|
||||
void GravitationalSubdivision( idBrushBSP& bsp );
|
||||
|
||||
private: // ledge subdivision
|
||||
void LedgeSubdivFlood_r( idBrushBSPNode* node, const idLedge* ledge );
|
||||
void LedgeSubdivLeafNodes_r( idBrushBSPNode* node, const idLedge* ledge );
|
||||
void LedgeSubdiv( idBrushBSPNode* root );
|
||||
bool IsLedgeSide_r( idBrushBSPNode* node, idFixedWinding* w, const idPlane& plane, const idVec3& normal, const idVec3& origin, const float radius );
|
||||
void AddLedge( const idVec3& v1, const idVec3& v2, idBrushBSPNode* node );
|
||||
void FindLeafNodeLedges( idBrushBSPNode* root, idBrushBSPNode* node );
|
||||
void FindLedges_r( idBrushBSPNode* root, idBrushBSPNode* node );
|
||||
void LedgeSubdivision( idBrushBSP& bsp );
|
||||
void WriteLedgeMap( const idStr& fileName, const idStr& ext );
|
||||
|
||||
private: // merging
|
||||
bool AllGapsLeadToOtherNode( idBrushBSPNode* nodeWithGaps, idBrushBSPNode* otherNode );
|
||||
bool MergeWithAdjacentLeafNodes( idBrushBSP& bsp, idBrushBSPNode* node );
|
||||
void MergeLeafNodes_r( idBrushBSP& bsp, idBrushBSPNode* node );
|
||||
void MergeLeafNodes( idBrushBSP& bsp );
|
||||
|
||||
private: // storing file
|
||||
void SetupHash( void );
|
||||
void ShutdownHash( void );
|
||||
void ClearHash( const idBounds& bounds );
|
||||
int HashVec( const idVec3& vec );
|
||||
bool GetVertex( const idVec3& v, int* vertexNum );
|
||||
bool GetEdge( const idVec3& v1, const idVec3& v2, int* edgeNum, int v1num );
|
||||
bool GetFaceForPortal( idBrushBSPPortal* portal, int side, int* faceNum );
|
||||
bool GetAreaForLeafNode( idBrushBSPNode* node, int* areaNum );
|
||||
int StoreTree_r( idBrushBSPNode* node );
|
||||
void GetSizeEstimate_r( idBrushBSPNode* parent, idBrushBSPNode* node, struct sizeEstimate_s& size );
|
||||
void SetSizeEstimate( const idBrushBSP& bsp, idAASFileLocal* file );
|
||||
bool StoreFile( const idBrushBSP& bsp );
|
||||
|
||||
};
|
||||
|
||||
#endif /* !__AASBUILD_LOCAL_H__ */
|
188
neo/tools/compilers/aas/AASBuild_merge.cpp
Normal file
188
neo/tools/compilers/aas/AASBuild_merge.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASBuild_local.h"
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::AllGapsLeadToOtherNode
|
||||
============
|
||||
*/
|
||||
bool idAASBuild::AllGapsLeadToOtherNode( idBrushBSPNode* nodeWithGaps, idBrushBSPNode* otherNode )
|
||||
{
|
||||
int s;
|
||||
idBrushBSPPortal* p;
|
||||
|
||||
for( p = nodeWithGaps->GetPortals(); p; p = p->Next( s ) )
|
||||
{
|
||||
s = ( p->GetNode( 1 ) == nodeWithGaps );
|
||||
|
||||
if( !PortalIsGap( p, s ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( p->GetNode( !s ) != otherNode )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::MergeWithAdjacentLeafNodes
|
||||
============
|
||||
*/
|
||||
bool idAASBuild::MergeWithAdjacentLeafNodes( idBrushBSP& bsp, idBrushBSPNode* node )
|
||||
{
|
||||
int s, numMerges = 0, otherNodeFlags;
|
||||
idBrushBSPPortal* p;
|
||||
|
||||
do
|
||||
{
|
||||
for( p = node->GetPortals(); p; p = p->Next( s ) )
|
||||
{
|
||||
s = ( p->GetNode( 1 ) == node );
|
||||
|
||||
// both leaf nodes must have the same contents
|
||||
if( node->GetContents() != p->GetNode( !s )->GetContents() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// cannot merge leaf nodes if one is near a ledge and the other is not
|
||||
if( ( node->GetFlags() & AREA_LEDGE ) != ( p->GetNode( !s )->GetFlags() & AREA_LEDGE ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// cannot merge leaf nodes if one has a floor portal and the other a gap portal
|
||||
if( node->GetFlags() & AREA_FLOOR )
|
||||
{
|
||||
if( p->GetNode( !s )->GetFlags() & AREA_GAP )
|
||||
{
|
||||
if( !AllGapsLeadToOtherNode( p->GetNode( !s ), node ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( node->GetFlags() & AREA_GAP )
|
||||
{
|
||||
if( p->GetNode( !s )->GetFlags() & AREA_FLOOR )
|
||||
{
|
||||
if( !AllGapsLeadToOtherNode( node, p->GetNode( !s ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
otherNodeFlags = p->GetNode( !s )->GetFlags();
|
||||
|
||||
// try to merge the leaf nodes
|
||||
if( bsp.TryMergeLeafNodes( p, s ) )
|
||||
{
|
||||
node->SetFlag( otherNodeFlags );
|
||||
if( node->GetFlags() & AREA_FLOOR )
|
||||
{
|
||||
node->RemoveFlag( AREA_GAP );
|
||||
}
|
||||
numMerges++;
|
||||
DisplayRealTimeString( "\r%6d", ++numMergedLeafNodes );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while( p );
|
||||
|
||||
if( numMerges )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::MergeLeafNodes_r
|
||||
============
|
||||
*/
|
||||
void idAASBuild::MergeLeafNodes_r( idBrushBSP& bsp, idBrushBSPNode* node )
|
||||
{
|
||||
|
||||
if( !node )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( node->GetContents() & AREACONTENTS_SOLID )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( node->GetFlags() & NODE_DONE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !node->GetChild( 0 ) && !node->GetChild( 1 ) )
|
||||
{
|
||||
MergeWithAdjacentLeafNodes( bsp, node );
|
||||
node->SetFlag( NODE_DONE );
|
||||
return;
|
||||
}
|
||||
|
||||
MergeLeafNodes_r( bsp, node->GetChild( 0 ) );
|
||||
MergeLeafNodes_r( bsp, node->GetChild( 1 ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASBuild::MergeLeafNodes
|
||||
============
|
||||
*/
|
||||
void idAASBuild::MergeLeafNodes( idBrushBSP& bsp )
|
||||
{
|
||||
numMergedLeafNodes = 0;
|
||||
|
||||
common->Printf( "[Merge Leaf Nodes]\n" );
|
||||
|
||||
MergeLeafNodes_r( bsp, bsp.GetRootNode() );
|
||||
bsp.GetRootNode()->RemoveFlagRecurse( NODE_DONE );
|
||||
bsp.PruneMergedTree_r( bsp.GetRootNode() );
|
||||
|
||||
common->Printf( "\r%6d leaf nodes merged\n", numMergedLeafNodes );
|
||||
}
|
645
neo/tools/compilers/aas/AASCluster.cpp
Normal file
645
neo/tools/compilers/aas/AASCluster.cpp
Normal file
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "..\..\aas\AASFile.h"
|
||||
#include "..\..\aas\AASFile_local.h"
|
||||
#include "AASCluster.h"
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::UpdatePortal
|
||||
================
|
||||
*/
|
||||
bool idAASCluster::UpdatePortal( int areaNum, int clusterNum )
|
||||
{
|
||||
int portalNum;
|
||||
aasPortal_t* portal;
|
||||
|
||||
// find the portal for this area
|
||||
for( portalNum = 1; portalNum < file->portals.Num(); portalNum++ )
|
||||
{
|
||||
if( file->portals[portalNum].areaNum == areaNum )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( portalNum >= file->portals.Num() )
|
||||
{
|
||||
common->Error( "no portal for area %d", areaNum );
|
||||
return true;
|
||||
}
|
||||
|
||||
portal = &file->portals[portalNum];
|
||||
|
||||
// if the portal is already fully updated
|
||||
if( portal->clusters[0] == clusterNum )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if( portal->clusters[1] == clusterNum )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// if the portal has no front cluster yet
|
||||
if( !portal->clusters[0] )
|
||||
{
|
||||
portal->clusters[0] = clusterNum;
|
||||
}
|
||||
// if the portal has no back cluster yet
|
||||
else if( !portal->clusters[1] )
|
||||
{
|
||||
portal->clusters[1] = clusterNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove the cluster portal flag contents
|
||||
file->areas[areaNum].contents &= ~AREACONTENTS_CLUSTERPORTAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the area cluster number to the negative portal number
|
||||
file->areas[areaNum].cluster = -portalNum;
|
||||
|
||||
// add the portal to the cluster using the portal index
|
||||
file->portalIndex.Append( portalNum );
|
||||
file->clusters[clusterNum].numPortals++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::FloodClusterAreas_r
|
||||
================
|
||||
*/
|
||||
bool idAASCluster::FloodClusterAreas_r( int areaNum, int clusterNum )
|
||||
{
|
||||
aasArea_t* area;
|
||||
aasFace_t* face;
|
||||
int faceNum, i;
|
||||
idReachability* reach;
|
||||
|
||||
area = &file->areas[areaNum];
|
||||
|
||||
// if the area is already part of a cluster
|
||||
if( area->cluster > 0 )
|
||||
{
|
||||
if( area->cluster == clusterNum )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// there's a reachability going from one cluster to another only in one direction
|
||||
common->Error( "cluster %d touched cluster %d at area %d\r\n", clusterNum, file->areas[areaNum].cluster, areaNum );
|
||||
return false;
|
||||
}
|
||||
|
||||
// if this area is a cluster portal
|
||||
if( area->contents & AREACONTENTS_CLUSTERPORTAL )
|
||||
{
|
||||
return UpdatePortal( areaNum, clusterNum );
|
||||
}
|
||||
|
||||
// set the area cluster number
|
||||
area->cluster = clusterNum;
|
||||
|
||||
if( !noFaceFlood )
|
||||
{
|
||||
// use area faces to flood into adjacent areas
|
||||
for( i = 0; i < area->numFaces; i++ )
|
||||
{
|
||||
faceNum = abs( file->faceIndex[area->firstFace + i] );
|
||||
face = &file->faces[faceNum];
|
||||
if( face->areas[0] == areaNum )
|
||||
{
|
||||
if( face->areas[1] )
|
||||
{
|
||||
if( !FloodClusterAreas_r( face->areas[1], clusterNum ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( face->areas[0] )
|
||||
{
|
||||
if( !FloodClusterAreas_r( face->areas[0], clusterNum ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// use the reachabilities to flood into other areas
|
||||
for( reach = file->areas[areaNum].reach; reach; reach = reach->next )
|
||||
{
|
||||
if( !FloodClusterAreas_r( reach->toAreaNum, clusterNum ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// use the reversed reachabilities to flood into other areas
|
||||
for( reach = file->areas[areaNum].rev_reach; reach; reach = reach->rev_next )
|
||||
{
|
||||
if( !FloodClusterAreas_r( reach->fromAreaNum, clusterNum ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::RemoveAreaClusterNumbers
|
||||
================
|
||||
*/
|
||||
void idAASCluster::RemoveAreaClusterNumbers( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 1; i < file->areas.Num(); i++ )
|
||||
{
|
||||
file->areas[i].cluster = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::NumberClusterAreas
|
||||
================
|
||||
*/
|
||||
void idAASCluster::NumberClusterAreas( int clusterNum )
|
||||
{
|
||||
int i, portalNum;
|
||||
aasCluster_t* cluster;
|
||||
aasPortal_t* portal;
|
||||
|
||||
cluster = &file->clusters[clusterNum];
|
||||
cluster->numAreas = 0;
|
||||
cluster->numReachableAreas = 0;
|
||||
|
||||
// number all areas in this cluster WITH reachabilities
|
||||
for( i = 1; i < file->areas.Num(); i++ )
|
||||
{
|
||||
|
||||
if( file->areas[i].cluster != clusterNum )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !( file->areas[i].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
file->areas[i].clusterAreaNum = cluster->numAreas++;
|
||||
cluster->numReachableAreas++;
|
||||
}
|
||||
|
||||
// number all portals in this cluster WITH reachabilities
|
||||
for( i = 0; i < cluster->numPortals; i++ )
|
||||
{
|
||||
portalNum = file->portalIndex[cluster->firstPortal + i];
|
||||
portal = &file->portals[portalNum];
|
||||
|
||||
if( !( file->areas[portal->areaNum].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( portal->clusters[0] == clusterNum )
|
||||
{
|
||||
portal->clusterAreaNum[0] = cluster->numAreas++;
|
||||
}
|
||||
else
|
||||
{
|
||||
portal->clusterAreaNum[1] = cluster->numAreas++;
|
||||
}
|
||||
cluster->numReachableAreas++;
|
||||
}
|
||||
|
||||
// number all areas in this cluster WITHOUT reachabilities
|
||||
for( i = 1; i < file->areas.Num(); i++ )
|
||||
{
|
||||
|
||||
if( file->areas[i].cluster != clusterNum )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( file->areas[i].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
file->areas[i].clusterAreaNum = cluster->numAreas++;
|
||||
}
|
||||
|
||||
// number all portals in this cluster WITHOUT reachabilities
|
||||
for( i = 0; i < cluster->numPortals; i++ )
|
||||
{
|
||||
portalNum = file->portalIndex[cluster->firstPortal + i];
|
||||
portal = &file->portals[portalNum];
|
||||
|
||||
if( file->areas[portal->areaNum].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( portal->clusters[0] == clusterNum )
|
||||
{
|
||||
portal->clusterAreaNum[0] = cluster->numAreas++;
|
||||
}
|
||||
else
|
||||
{
|
||||
portal->clusterAreaNum[1] = cluster->numAreas++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::FindClusters
|
||||
================
|
||||
*/
|
||||
bool idAASCluster::FindClusters( void )
|
||||
{
|
||||
int i, clusterNum;
|
||||
aasCluster_t cluster;
|
||||
|
||||
RemoveAreaClusterNumbers();
|
||||
|
||||
for( i = 1; i < file->areas.Num(); i++ )
|
||||
{
|
||||
// if the area is already part of a cluster
|
||||
if( file->areas[i].cluster )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not flooding through faces only use areas that have reachabilities
|
||||
if( noFaceFlood )
|
||||
{
|
||||
if( !( file->areas[i].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if the area is a cluster portal
|
||||
if( file->areas[i].contents & AREACONTENTS_CLUSTERPORTAL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cluster.numAreas = 0;
|
||||
cluster.numReachableAreas = 0;
|
||||
cluster.firstPortal = file->portalIndex.Num();
|
||||
cluster.numPortals = 0;
|
||||
clusterNum = file->clusters.Num();
|
||||
file->clusters.Append( cluster );
|
||||
|
||||
// flood the areas in this cluster
|
||||
if( !FloodClusterAreas_r( i, clusterNum ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// number the cluster areas
|
||||
NumberClusterAreas( clusterNum );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::CreatePortals
|
||||
================
|
||||
*/
|
||||
void idAASCluster::CreatePortals( void )
|
||||
{
|
||||
int i;
|
||||
aasPortal_t portal;
|
||||
|
||||
for( i = 1; i < file->areas.Num(); i++ )
|
||||
{
|
||||
// if the area is a cluster portal
|
||||
if( file->areas[i].contents & AREACONTENTS_CLUSTERPORTAL )
|
||||
{
|
||||
portal.areaNum = i;
|
||||
portal.clusters[0] = portal.clusters[1] = 0;
|
||||
portal.maxAreaTravelTime = 0;
|
||||
file->portals.Append( portal );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::TestPortals
|
||||
================
|
||||
*/
|
||||
bool idAASCluster::TestPortals( void )
|
||||
{
|
||||
int i;
|
||||
aasPortal_t* portal, *portal2;
|
||||
aasArea_t* area, *area2;
|
||||
idReachability* reach;
|
||||
bool ok;
|
||||
|
||||
ok = true;
|
||||
for( i = 1; i < file->portals.Num(); i++ )
|
||||
{
|
||||
portal = &file->portals[i];
|
||||
area = &file->areas[portal->areaNum];
|
||||
|
||||
// if this portal was already removed
|
||||
if( !( area->contents & AREACONTENTS_CLUSTERPORTAL ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// may not removed this portal if it has a reachability to a removed portal
|
||||
for( reach = area->reach; reach; reach = reach->next )
|
||||
{
|
||||
area2 = &file->areas[ reach->toAreaNum ];
|
||||
if( area2->contents & AREACONTENTS_CLUSTERPORTAL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( area2->cluster < 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( reach )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// may not removed this portal if it has a reversed reachability to a removed portal
|
||||
for( reach = area->rev_reach; reach; reach = reach->rev_next )
|
||||
{
|
||||
area2 = &file->areas[ reach->toAreaNum ];
|
||||
if( area2->contents & AREACONTENTS_CLUSTERPORTAL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( area2->cluster < 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( reach )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// portal should have two clusters set
|
||||
if( !portal->clusters[0] )
|
||||
{
|
||||
area->contents &= ~AREACONTENTS_CLUSTERPORTAL;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
if( !portal->clusters[1] )
|
||||
{
|
||||
area->contents &= ~AREACONTENTS_CLUSTERPORTAL;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// this portal may not have reachabilities to a portal that doesn't seperate the same clusters
|
||||
for( reach = area->reach; reach; reach = reach->next )
|
||||
{
|
||||
area2 = &file->areas[ reach->toAreaNum ];
|
||||
|
||||
if( !( area2->contents & AREACONTENTS_CLUSTERPORTAL ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( area2->cluster > 0 )
|
||||
{
|
||||
area2->contents &= ~AREACONTENTS_CLUSTERPORTAL;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
portal2 = &file->portals[ -file->areas[ reach->toAreaNum ].cluster ];
|
||||
|
||||
if( ( portal2->clusters[0] != portal->clusters[0] && portal2->clusters[0] != portal->clusters[1] ) ||
|
||||
( portal2->clusters[1] != portal->clusters[0] && portal2->clusters[1] != portal->clusters[1] ) )
|
||||
{
|
||||
area2->contents &= ~AREACONTENTS_CLUSTERPORTAL;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::RemoveInvalidPortals
|
||||
================
|
||||
*/
|
||||
void idAASCluster::RemoveInvalidPortals( void )
|
||||
{
|
||||
int i, j, k, face1Num, face2Num, otherAreaNum, numOpenAreas, numInvalidPortals;
|
||||
aasFace_t* face1, *face2;
|
||||
|
||||
numInvalidPortals = 0;
|
||||
for( i = 0; i < file->areas.Num(); i++ )
|
||||
{
|
||||
if( !( file->areas[i].contents & AREACONTENTS_CLUSTERPORTAL ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numOpenAreas = 0;
|
||||
for( j = 0; j < file->areas[i].numFaces; j++ )
|
||||
{
|
||||
face1Num = file->faceIndex[ file->areas[i].firstFace + j ];
|
||||
face1 = &file->faces[ abs( face1Num ) ];
|
||||
otherAreaNum = face1->areas[ face1Num < 0 ];
|
||||
|
||||
if( !otherAreaNum )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for( k = 0; k < j; k++ )
|
||||
{
|
||||
face2Num = file->faceIndex[ file->areas[i].firstFace + k ];
|
||||
face2 = &file->faces[ abs( face2Num ) ];
|
||||
if( otherAreaNum == face2->areas[ face2Num < 0 ] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( k < j )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !( file->areas[otherAreaNum].contents & AREACONTENTS_CLUSTERPORTAL ) )
|
||||
{
|
||||
numOpenAreas++;
|
||||
}
|
||||
}
|
||||
|
||||
if( numOpenAreas <= 1 )
|
||||
{
|
||||
file->areas[i].contents &= AREACONTENTS_CLUSTERPORTAL;
|
||||
numInvalidPortals++;
|
||||
}
|
||||
}
|
||||
|
||||
common->Printf( "\r%6d invalid portals removed\n", numInvalidPortals );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::Build
|
||||
================
|
||||
*/
|
||||
bool idAASCluster::Build( idAASFileLocal* file )
|
||||
{
|
||||
|
||||
common->Printf( "[Clustering]\n" );
|
||||
|
||||
this->file = file;
|
||||
this->noFaceFlood = true;
|
||||
|
||||
RemoveInvalidPortals();
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
|
||||
// delete all existing clusters
|
||||
file->DeleteClusters();
|
||||
|
||||
// create the portals from the portal areas
|
||||
CreatePortals();
|
||||
|
||||
common->Printf( "\r%6d", file->portals.Num() );
|
||||
|
||||
// find the clusters
|
||||
if( !FindClusters() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// test the portals
|
||||
if( !TestPortals() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
common->Printf( "\r%6d portals\n", file->portals.Num() );
|
||||
common->Printf( "%6d clusters\n", file->clusters.Num() );
|
||||
|
||||
for( int i = 0; i < file->clusters.Num(); i++ )
|
||||
{
|
||||
common->Printf( "%6d reachable areas in cluster %d\n", file->clusters[i].numReachableAreas, i );
|
||||
}
|
||||
|
||||
file->ReportRoutingEfficiency();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASCluster::BuildSingleCluster
|
||||
================
|
||||
*/
|
||||
bool idAASCluster::BuildSingleCluster( idAASFileLocal* file )
|
||||
{
|
||||
int i, numAreas;
|
||||
aasCluster_t cluster;
|
||||
|
||||
common->Printf( "[Clustering]\n" );
|
||||
|
||||
this->file = file;
|
||||
|
||||
// delete all existing clusters
|
||||
file->DeleteClusters();
|
||||
|
||||
cluster.firstPortal = 0;
|
||||
cluster.numPortals = 0;
|
||||
cluster.numAreas = file->areas.Num();
|
||||
cluster.numReachableAreas = 0;
|
||||
// give all reachable areas in the cluster a number
|
||||
for( i = 0; i < file->areas.Num(); i++ )
|
||||
{
|
||||
file->areas[i].cluster = file->clusters.Num();
|
||||
if( file->areas[i].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) )
|
||||
{
|
||||
file->areas[i].clusterAreaNum = cluster.numReachableAreas++;
|
||||
}
|
||||
}
|
||||
// give the remaining areas a number within the cluster
|
||||
numAreas = cluster.numReachableAreas;
|
||||
for( i = 0; i < file->areas.Num(); i++ )
|
||||
{
|
||||
if( file->areas[i].flags & ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
file->areas[i].clusterAreaNum = numAreas++;
|
||||
}
|
||||
file->clusters.Append( cluster );
|
||||
|
||||
common->Printf( "%6d portals\n", file->portals.Num() );
|
||||
common->Printf( "%6d clusters\n", file->clusters.Num() );
|
||||
|
||||
for( i = 0; i < file->clusters.Num(); i++ )
|
||||
{
|
||||
common->Printf( "%6d reachable areas in cluster %d\n", file->clusters[i].numReachableAreas, i );
|
||||
}
|
||||
|
||||
file->ReportRoutingEfficiency();
|
||||
|
||||
return true;
|
||||
}
|
63
neo/tools/compilers/aas/AASCluster.h
Normal file
63
neo/tools/compilers/aas/AASCluster.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __AASCLUSTER_H__
|
||||
#define __AASCLUSTER_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Area Clustering
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idAASCluster
|
||||
{
|
||||
|
||||
public:
|
||||
bool Build( idAASFileLocal* file );
|
||||
bool BuildSingleCluster( idAASFileLocal* file );
|
||||
|
||||
private:
|
||||
idAASFileLocal* file;
|
||||
bool noFaceFlood;
|
||||
|
||||
private:
|
||||
bool UpdatePortal( int areaNum, int clusterNum );
|
||||
bool FloodClusterAreas_r( int areaNum, int clusterNum );
|
||||
void RemoveAreaClusterNumbers( void );
|
||||
void NumberClusterAreas( int clusterNum );
|
||||
bool FindClusters( void );
|
||||
void CreatePortals( void );
|
||||
bool TestPortals( void );
|
||||
void ReportEfficiency( void );
|
||||
void RemoveInvalidPortals( void );
|
||||
};
|
||||
|
||||
#endif /* !__AASCLUSTER_H__ */
|
1083
neo/tools/compilers/aas/AASReach.cpp
Normal file
1083
neo/tools/compilers/aas/AASReach.cpp
Normal file
File diff suppressed because it is too large
Load diff
68
neo/tools/compilers/aas/AASReach.h
Normal file
68
neo/tools/compilers/aas/AASReach.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __AASREACH_H__
|
||||
#define __AASREACH_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Reachabilities
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idAASReach
|
||||
{
|
||||
|
||||
public:
|
||||
bool Build( const idMapFile* mapFile, idAASFileLocal* file );
|
||||
|
||||
private:
|
||||
const idMapFile* mapFile;
|
||||
idAASFileLocal* file;
|
||||
int numReachabilities;
|
||||
bool allowSwimReachabilities;
|
||||
bool allowFlyReachabilities;
|
||||
|
||||
private: // reachability
|
||||
void FlagReachableAreas( idAASFileLocal* file );
|
||||
bool ReachabilityExists( int fromAreaNum, int toAreaNum );
|
||||
bool CanSwimInArea( int areaNum );
|
||||
bool AreaHasFloor( int areaNum );
|
||||
bool AreaIsClusterPortal( int areaNum );
|
||||
void AddReachabilityToArea( idReachability* reach, int areaNum );
|
||||
void Reachability_Fly( int areaNum );
|
||||
void Reachability_Swim( int areaNum );
|
||||
void Reachability_EqualFloorHeight( int areaNum );
|
||||
bool Reachability_Step_Barrier_WaterJump_WalkOffLedge( int fromAreaNum, int toAreaNum );
|
||||
void Reachability_WalkOffLedge( int areaNum );
|
||||
|
||||
};
|
||||
|
||||
#endif /* !__AASREACH_H__ */
|
1845
neo/tools/compilers/aas/Brush.cpp
Normal file
1845
neo/tools/compilers/aas/Brush.cpp
Normal file
File diff suppressed because it is too large
Load diff
320
neo/tools/compilers/aas/Brush.h
Normal file
320
neo/tools/compilers/aas/Brush.h
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __BRUSH_H__
|
||||
#define __BRUSH_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Brushes
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#define BRUSH_PLANESIDE_FRONT 1
|
||||
#define BRUSH_PLANESIDE_BACK 2
|
||||
#define BRUSH_PLANESIDE_BOTH ( BRUSH_PLANESIDE_FRONT | BRUSH_PLANESIDE_BACK )
|
||||
#define BRUSH_PLANESIDE_FACING 4
|
||||
|
||||
class idBrush;
|
||||
class idBrushList;
|
||||
|
||||
void DisplayRealTimeString( char* string, ... ) ID_STATIC_ATTRIBUTE_PRINTF( 1, 2 );
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrushSide
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
#define SFL_SPLIT 0x0001
|
||||
#define SFL_BEVEL 0x0002
|
||||
#define SFL_USED_SPLITTER 0x0004
|
||||
#define SFL_TESTED_SPLITTER 0x0008
|
||||
|
||||
class idBrushSide
|
||||
{
|
||||
|
||||
friend class idBrush;
|
||||
|
||||
public:
|
||||
idBrushSide( void );
|
||||
idBrushSide( const idPlane& plane, int planeNum );
|
||||
~idBrushSide( void );
|
||||
|
||||
int GetFlags( void ) const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
void SetFlag( int flag )
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
void RemoveFlag( int flag )
|
||||
{
|
||||
flags &= ~flag;
|
||||
}
|
||||
const idPlane& GetPlane( void ) const
|
||||
{
|
||||
return plane;
|
||||
}
|
||||
void SetPlaneNum( int num )
|
||||
{
|
||||
planeNum = num;
|
||||
}
|
||||
int GetPlaneNum( void )
|
||||
{
|
||||
return planeNum;
|
||||
}
|
||||
const idWinding* GetWinding( void ) const
|
||||
{
|
||||
return winding;
|
||||
}
|
||||
idBrushSide* Copy( void ) const;
|
||||
int Split( const idPlane& splitPlane, idBrushSide** front, idBrushSide** back ) const;
|
||||
|
||||
private:
|
||||
int flags;
|
||||
int planeNum;
|
||||
idPlane plane;
|
||||
idWinding* winding;
|
||||
};
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrush
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
#define BFL_NO_VALID_SPLITTERS 0x0001
|
||||
|
||||
class idBrush
|
||||
{
|
||||
|
||||
friend class idBrushList;
|
||||
|
||||
public:
|
||||
idBrush( void );
|
||||
~idBrush( void );
|
||||
|
||||
int GetFlags( void ) const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
void SetFlag( int flag )
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
void RemoveFlag( int flag )
|
||||
{
|
||||
flags &= ~flag;
|
||||
}
|
||||
void SetEntityNum( int num )
|
||||
{
|
||||
entityNum = num;
|
||||
}
|
||||
void SetPrimitiveNum( int num )
|
||||
{
|
||||
primitiveNum = num;
|
||||
}
|
||||
void SetContents( int contents )
|
||||
{
|
||||
this->contents = contents;
|
||||
}
|
||||
int GetContents( void ) const
|
||||
{
|
||||
return contents;
|
||||
}
|
||||
const idBounds& GetBounds( void ) const
|
||||
{
|
||||
return bounds;
|
||||
}
|
||||
float GetVolume( void ) const;
|
||||
int GetNumSides( void ) const
|
||||
{
|
||||
return sides.Num();
|
||||
}
|
||||
idBrushSide* GetSide( int i ) const
|
||||
{
|
||||
return sides[i];
|
||||
}
|
||||
void SetPlaneSide( int s )
|
||||
{
|
||||
planeSide = s;
|
||||
}
|
||||
void SavePlaneSide( void )
|
||||
{
|
||||
savedPlaneSide = planeSide;
|
||||
}
|
||||
int GetSavedPlaneSide( void ) const
|
||||
{
|
||||
return savedPlaneSide;
|
||||
}
|
||||
bool FromSides( idList<idBrushSide*>& sideList );
|
||||
bool FromWinding( const idWinding& w, const idPlane& windingPlane );
|
||||
bool FromBounds( const idBounds& bounds );
|
||||
void Transform( const idVec3& origin, const idMat3& axis );
|
||||
idBrush* Copy( void ) const;
|
||||
bool TryMerge( const idBrush* brush, const idPlaneSet& planeList );
|
||||
// returns true if the brushes did intersect
|
||||
bool Subtract( const idBrush* b, idBrushList& list ) const;
|
||||
// split the brush into a front and back brush
|
||||
int Split( const idPlane& plane, int planeNum, idBrush** front, idBrush** back ) const;
|
||||
// expand the brush for an axial bounding box
|
||||
void ExpandForAxialBox( const idBounds& bounds );
|
||||
// next brush in list
|
||||
idBrush* Next( void ) const
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable idBrush* next; // next brush in list
|
||||
int entityNum; // entity number in editor
|
||||
int primitiveNum; // primitive number in editor
|
||||
int flags; // brush flags
|
||||
bool windingsValid; // set when side windings are valid
|
||||
int contents; // contents of brush
|
||||
int planeSide; // side of a plane this brush is on
|
||||
int savedPlaneSide; // saved plane side
|
||||
idBounds bounds; // brush bounds
|
||||
idList<idBrushSide*> sides; // list with sides
|
||||
|
||||
private:
|
||||
bool CreateWindings( void );
|
||||
void BoundBrush( const idBrush* original = NULL );
|
||||
void AddBevelsForAxialBox( void );
|
||||
bool RemoveSidesWithoutWinding( void );
|
||||
};
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrushList
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
class idBrushList
|
||||
{
|
||||
public:
|
||||
idBrushList( void );
|
||||
~idBrushList( void );
|
||||
|
||||
int Num( void ) const
|
||||
{
|
||||
return numBrushes;
|
||||
}
|
||||
int NumSides( void ) const
|
||||
{
|
||||
return numBrushSides;
|
||||
}
|
||||
idBrush* Head( void ) const
|
||||
{
|
||||
return head;
|
||||
}
|
||||
idBrush* Tail( void ) const
|
||||
{
|
||||
return tail;
|
||||
}
|
||||
void Clear( void )
|
||||
{
|
||||
head = tail = NULL;
|
||||
numBrushes = 0;
|
||||
}
|
||||
bool IsEmpty( void ) const
|
||||
{
|
||||
return ( numBrushes == 0 );
|
||||
}
|
||||
idBounds GetBounds( void ) const;
|
||||
// add brush to the tail of the list
|
||||
void AddToTail( idBrush* brush );
|
||||
// add list to the tail of the list
|
||||
void AddToTail( idBrushList& list );
|
||||
// add brush to the front of the list
|
||||
void AddToFront( idBrush* brush );
|
||||
// add list to the front of the list
|
||||
void AddToFront( idBrushList& list );
|
||||
// remove the brush from the list
|
||||
void Remove( idBrush* brush );
|
||||
// remove the brush from the list and delete the brush
|
||||
void Delete( idBrush* brush );
|
||||
// returns a copy of the brush list
|
||||
idBrushList* Copy( void ) const;
|
||||
// delete all brushes in the list
|
||||
void Free( void );
|
||||
// split the brushes in the list into two lists
|
||||
void Split( const idPlane& plane, int planeNum, idBrushList& frontList, idBrushList& backList, bool useBrushSavedPlaneSide = false );
|
||||
// chop away all brush overlap
|
||||
void Chop( bool ( *ChopAllowed )( idBrush* b1, idBrush* b2 ) );
|
||||
// merge brushes
|
||||
void Merge( bool ( *MergeAllowed )( idBrush* b1, idBrush* b2 ) );
|
||||
// set the given flag on all brush sides facing the plane
|
||||
void SetFlagOnFacingBrushSides( const idPlane& plane, int flag );
|
||||
// get a list with planes for all brushes in the list
|
||||
void CreatePlaneList( idPlaneSet& planeList ) const;
|
||||
// write a brush map with the brushes in the list
|
||||
void WriteBrushMap( const idStr& fileName, const idStr& ext ) const;
|
||||
|
||||
private:
|
||||
idBrush* head;
|
||||
idBrush* tail;
|
||||
int numBrushes;
|
||||
int numBrushSides;
|
||||
};
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrushMap
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
class idBrushMap
|
||||
{
|
||||
|
||||
public:
|
||||
idBrushMap( const idStr& fileName, const idStr& ext );
|
||||
~idBrushMap( void );
|
||||
void SetTexture( const idStr& textureName )
|
||||
{
|
||||
texture = textureName;
|
||||
}
|
||||
void WriteBrush( const idBrush* brush );
|
||||
void WriteBrushList( const idBrushList& brushList );
|
||||
|
||||
private:
|
||||
idFile* fp;
|
||||
idStr texture;
|
||||
int brushCount;
|
||||
};
|
||||
|
||||
#endif /* !__BRUSH_H__ */
|
2462
neo/tools/compilers/aas/BrushBSP.cpp
Normal file
2462
neo/tools/compilers/aas/BrushBSP.cpp
Normal file
File diff suppressed because it is too large
Load diff
302
neo/tools/compilers/aas/BrushBSP.h
Normal file
302
neo/tools/compilers/aas/BrushBSP.h
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __BRUSHBSP_H__
|
||||
#define __BRUSHBSP_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
BrushBSP
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idBrushBSP;
|
||||
class idBrushBSPNode;
|
||||
class idBrushBSPPortal;
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrushBSPPortal
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
class idBrushBSPPortal
|
||||
{
|
||||
|
||||
friend class idBrushBSP;
|
||||
friend class idBrushBSPNode;
|
||||
|
||||
public:
|
||||
idBrushBSPPortal( void );
|
||||
~idBrushBSPPortal( void );
|
||||
void AddToNodes( idBrushBSPNode* front, idBrushBSPNode* back );
|
||||
void RemoveFromNode( idBrushBSPNode* l );
|
||||
void Flip( void );
|
||||
int Split( const idPlane& splitPlane, idBrushBSPPortal** front, idBrushBSPPortal** back );
|
||||
idWinding* GetWinding( void ) const
|
||||
{
|
||||
return winding;
|
||||
}
|
||||
const idPlane& GetPlane( void ) const
|
||||
{
|
||||
return plane;
|
||||
}
|
||||
void SetFaceNum( int num )
|
||||
{
|
||||
faceNum = num;
|
||||
}
|
||||
int GetFaceNum( void ) const
|
||||
{
|
||||
return faceNum;
|
||||
}
|
||||
int GetFlags( void ) const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
void SetFlag( int flag )
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
void RemoveFlag( int flag )
|
||||
{
|
||||
flags &= ~flag;
|
||||
}
|
||||
idBrushBSPPortal* Next( int side ) const
|
||||
{
|
||||
return next[side];
|
||||
}
|
||||
idBrushBSPNode* GetNode( int side ) const
|
||||
{
|
||||
return nodes[side];
|
||||
}
|
||||
|
||||
private:
|
||||
idPlane plane; // portal plane
|
||||
int planeNum; // number of plane this portal is on
|
||||
idWinding* winding; // portal winding
|
||||
idBrushBSPNode* nodes[2]; // nodes this portal seperates
|
||||
idBrushBSPPortal* next[2]; // next portal in list for both nodes
|
||||
int flags; // portal flags
|
||||
int faceNum; // number of the face created for this portal
|
||||
};
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrushBSPNode
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
#define NODE_VISITED BIT(30)
|
||||
#define NODE_DONE BIT(31)
|
||||
|
||||
class idBrushBSPNode
|
||||
{
|
||||
|
||||
friend class idBrushBSP;
|
||||
friend class idBrushBSPPortal;
|
||||
|
||||
public:
|
||||
idBrushBSPNode( void );
|
||||
~idBrushBSPNode( void );
|
||||
void SetContentsFromBrushes( void );
|
||||
idBounds GetPortalBounds( void );
|
||||
idBrushBSPNode* GetChild( int index ) const
|
||||
{
|
||||
return children[index];
|
||||
}
|
||||
idBrushBSPNode* GetParent( void ) const
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
void SetContents( int contents )
|
||||
{
|
||||
this->contents = contents;
|
||||
}
|
||||
int GetContents( void ) const
|
||||
{
|
||||
return contents;
|
||||
}
|
||||
const idPlane& GetPlane( void ) const
|
||||
{
|
||||
return plane;
|
||||
}
|
||||
idBrushBSPPortal* GetPortals( void ) const
|
||||
{
|
||||
return portals;
|
||||
}
|
||||
void SetAreaNum( int num )
|
||||
{
|
||||
areaNum = num;
|
||||
}
|
||||
int GetAreaNum( void ) const
|
||||
{
|
||||
return areaNum;
|
||||
}
|
||||
int GetFlags( void ) const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
void SetFlag( int flag )
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
void RemoveFlag( int flag )
|
||||
{
|
||||
flags &= ~flag;
|
||||
}
|
||||
bool TestLeafNode( void );
|
||||
// remove the flag from nodes found by flooding through portals to nodes with the flag set
|
||||
void RemoveFlagFlood( int flag );
|
||||
// recurse down the tree and remove the flag from all visited nodes
|
||||
void RemoveFlagRecurse( int flag );
|
||||
// first recurse down the tree and flood from there
|
||||
void RemoveFlagRecurseFlood( int flag );
|
||||
// returns side of the plane the node is on
|
||||
int PlaneSide( const idPlane& plane, float epsilon = ON_EPSILON ) const;
|
||||
// split the leaf node with a plane
|
||||
bool Split( const idPlane& splitPlane, int splitPlaneNum );
|
||||
|
||||
|
||||
private:
|
||||
idPlane plane; // split plane if this is not a leaf node
|
||||
idBrush* volume; // node volume
|
||||
int contents; // node contents
|
||||
idBrushList brushList; // list with brushes for this node
|
||||
idBrushBSPNode* parent; // parent of this node
|
||||
idBrushBSPNode* children[2]; // both are NULL if this is a leaf node
|
||||
idBrushBSPPortal* portals; // portals of this node
|
||||
int flags; // node flags
|
||||
int areaNum; // number of the area created for this node
|
||||
int occupied; // true when portal is occupied
|
||||
};
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idBrushBSP
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
class idBrushBSP
|
||||
{
|
||||
|
||||
public:
|
||||
idBrushBSP( void );
|
||||
~idBrushBSP( void );
|
||||
// build a bsp tree from a set of brushes
|
||||
void Build( idBrushList brushList, int skipContents,
|
||||
bool ( *ChopAllowed )( idBrush* b1, idBrush* b2 ),
|
||||
bool ( *MergeAllowed )( idBrush* b1, idBrush* b2 ) );
|
||||
// remove splits in subspaces with the given contents
|
||||
void PruneTree( int contents );
|
||||
// portalize the bsp tree
|
||||
void Portalize( void );
|
||||
// remove subspaces outside the map not reachable by entities
|
||||
bool RemoveOutside( const idMapFile* mapFile, int contents, const idStrList& classNames );
|
||||
// write file with a trace going through a leak
|
||||
void LeakFile( const idStr& fileName );
|
||||
// try to merge portals
|
||||
void MergePortals( int skipContents );
|
||||
// try to merge the two leaf nodes at either side of the portal
|
||||
bool TryMergeLeafNodes( idBrushBSPPortal* portal, int side );
|
||||
void PruneMergedTree_r( idBrushBSPNode* node );
|
||||
// melt portal windings
|
||||
void MeltPortals( int skipContents );
|
||||
// write a map file with a brush for every leaf node that has the given contents
|
||||
void WriteBrushMap( const idStr& fileName, const idStr& ext, int contents );
|
||||
// bounds for the whole tree
|
||||
const idBounds& GetTreeBounds( void ) const
|
||||
{
|
||||
return treeBounds;
|
||||
}
|
||||
// root node of the tree
|
||||
idBrushBSPNode* GetRootNode( void ) const
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
private:
|
||||
idBrushBSPNode* root;
|
||||
idBrushBSPNode* outside;
|
||||
idBounds treeBounds;
|
||||
idPlaneSet portalPlanes;
|
||||
int numGridCells;
|
||||
int numSplits;
|
||||
int numGridCellSplits;
|
||||
int numPrunedSplits;
|
||||
int numPortals;
|
||||
int solidLeafNodes;
|
||||
int outsideLeafNodes;
|
||||
int insideLeafNodes;
|
||||
int numMergedPortals;
|
||||
int numInsertedPoints;
|
||||
idVec3 leakOrigin;
|
||||
int brushMapContents;
|
||||
idBrushMap* brushMap;
|
||||
|
||||
bool ( *BrushChopAllowed )( idBrush* b1, idBrush* b2 );
|
||||
bool ( *BrushMergeAllowed )( idBrush* b1, idBrush* b2 );
|
||||
|
||||
private:
|
||||
void RemoveMultipleLeafNodeReferences_r( idBrushBSPNode* node );
|
||||
void Free_r( idBrushBSPNode* node );
|
||||
void IncreaseNumSplits( void );
|
||||
bool IsValidSplitter( const idBrushSide* side );
|
||||
int BrushSplitterStats( const idBrush* brush, int planeNum, const idPlaneSet& planeList, bool* testedPlanes, struct splitterStats_s& stats );
|
||||
int FindSplitter( idBrushBSPNode* node, const idPlaneSet& planeList, bool* testedPlanes, struct splitterStats_s& bestStats );
|
||||
void SetSplitterUsed( idBrushBSPNode* node, int planeNum );
|
||||
idBrushBSPNode* BuildBrushBSP_r( idBrushBSPNode* node, const idPlaneSet& planeList, bool* testedPlanes, int skipContents );
|
||||
idBrushBSPNode* ProcessGridCell( idBrushBSPNode* node, int skipContents );
|
||||
void BuildGrid_r( idList<idBrushBSPNode*>& gridCells, idBrushBSPNode* node );
|
||||
void PruneTree_r( idBrushBSPNode* node, int contents );
|
||||
void MakeOutsidePortals( void );
|
||||
idWinding* BaseWindingForNode( idBrushBSPNode* node );
|
||||
void MakeNodePortal( idBrushBSPNode* node );
|
||||
void SplitNodePortals( idBrushBSPNode* node );
|
||||
void MakeTreePortals_r( idBrushBSPNode* node );
|
||||
void FloodThroughPortals_r( idBrushBSPNode* node, int contents, int depth );
|
||||
bool FloodFromOrigin( const idVec3& origin, int contents );
|
||||
bool FloodFromEntities( const idMapFile* mapFile, int contents, const idStrList& classNames );
|
||||
void RemoveOutside_r( idBrushBSPNode* node, int contents );
|
||||
void SetPortalPlanes_r( idBrushBSPNode* node, idPlaneSet& planeList );
|
||||
void SetPortalPlanes( void );
|
||||
void MergePortals_r( idBrushBSPNode* node, int skipContents );
|
||||
void MergeLeafNodePortals( idBrushBSPNode* node, int skipContents );
|
||||
void UpdateTreeAfterMerge_r( idBrushBSPNode* node, const idBounds& bounds, idBrushBSPNode* oldNode, idBrushBSPNode* newNode );
|
||||
void RemoveLeafNodeColinearPoints( idBrushBSPNode* node );
|
||||
void RemoveColinearPoints_r( idBrushBSPNode* node, int skipContents );
|
||||
void MeltFlood_r( idBrushBSPNode* node, int skipContents, idBounds& bounds, idVectorSet<idVec3, 3>& vertexList );
|
||||
void MeltLeafNodePortals( idBrushBSPNode* node, int skipContents, idVectorSet<idVec3, 3>& vertexList );
|
||||
void MeltPortals_r( idBrushBSPNode* node, int skipContents, idVectorSet<idVec3, 3>& vertexList );
|
||||
};
|
||||
|
||||
#endif /* !__BRUSHBSP_H__ */
|
48
neo/tools/compilers/compiler_public.h
Normal file
48
neo/tools/compilers/compiler_public.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __COMPILER_PUBLIC_H__
|
||||
#define __COMPILER_PUBLIC_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Compilers for map, aas, etc. processing.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
// map processing (also see SuperOptimizeOccluders in tr_local.h)
|
||||
void Dmap_f( const idCmdArgs& args );
|
||||
|
||||
// AAS file compiler
|
||||
void RunAAS_f( const idCmdArgs& args );
|
||||
void RunAASDir_f( const idCmdArgs& args );
|
||||
void RunReach_f( const idCmdArgs& args );
|
||||
|
||||
#endif /* !__COMPILER_PUBLIC_H__ */
|
462
neo/tools/compilers/dmap/dmap.cpp
Normal file
462
neo/tools/compilers/dmap/dmap.cpp
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
dmapGlobals_t dmapGlobals;
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessModel
|
||||
============
|
||||
*/
|
||||
bool ProcessModel( uEntity_t* e, bool floodFill )
|
||||
{
|
||||
bspface_t* faces;
|
||||
|
||||
// build a bsp tree using all of the sides
|
||||
// of all of the structural brushes
|
||||
faces = MakeStructuralBspFaceList( e->primitives );
|
||||
e->tree = FaceBSP( faces );
|
||||
|
||||
// create portals at every leaf intersection
|
||||
// to allow flood filling
|
||||
MakeTreePortals( e->tree );
|
||||
|
||||
// classify the leafs as opaque or areaportal
|
||||
FilterBrushesIntoTree( e );
|
||||
|
||||
// see if the bsp is completely enclosed
|
||||
if( floodFill && !dmapGlobals.noFlood )
|
||||
{
|
||||
if( FloodEntities( e->tree ) )
|
||||
{
|
||||
// set the outside leafs to opaque
|
||||
FillOutside( e );
|
||||
}
|
||||
else
|
||||
{
|
||||
common->Printf( "**********************\n" );
|
||||
common->Warning( "******* leaked *******" );
|
||||
common->Printf( "**********************\n" );
|
||||
LeakFile( e->tree );
|
||||
// bail out here. If someone really wants to
|
||||
// process a map that leaks, they should use
|
||||
// -noFlood
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// get minimum convex hulls for each visible side
|
||||
// this must be done before creating area portals,
|
||||
// because the visible hull is used as the portal
|
||||
ClipSidesByTree( e );
|
||||
|
||||
// determine areas before clipping tris into the
|
||||
// tree, so tris will never cross area boundaries
|
||||
FloodAreas( e );
|
||||
|
||||
// we now have a BSP tree with solid and non-solid leafs marked with areas
|
||||
// all primitives will now be clipped into this, throwing away
|
||||
// fragments in the solid areas
|
||||
PutPrimitivesInAreas( e );
|
||||
|
||||
// now build shadow volumes for the lights and split
|
||||
// the optimize lists by the light beam trees
|
||||
// so there won't be unneeded overdraw in the static
|
||||
// case
|
||||
Prelight( e );
|
||||
|
||||
// optimizing is a superset of fixing tjunctions
|
||||
if( !dmapGlobals.noOptimize )
|
||||
{
|
||||
OptimizeEntity( e );
|
||||
}
|
||||
else if( !dmapGlobals.noTJunc )
|
||||
{
|
||||
FixEntityTjunctions( e );
|
||||
}
|
||||
|
||||
// now fix t junctions across areas
|
||||
FixGlobalTjunctions( e );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessModels
|
||||
============
|
||||
*/
|
||||
bool ProcessModels( void )
|
||||
{
|
||||
bool oldVerbose;
|
||||
uEntity_t* entity;
|
||||
|
||||
oldVerbose = dmapGlobals.verbose;
|
||||
|
||||
for( dmapGlobals.entityNum = 0 ; dmapGlobals.entityNum < dmapGlobals.num_entities ; dmapGlobals.entityNum++ )
|
||||
{
|
||||
|
||||
entity = &dmapGlobals.uEntities[dmapGlobals.entityNum];
|
||||
if( !entity->primitives )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
common->Printf( "############### entity %i ###############\n", dmapGlobals.entityNum );
|
||||
|
||||
// if we leaked, stop without any more processing
|
||||
if( !ProcessModel( entity, ( bool )( dmapGlobals.entityNum == 0 ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// we usually don't want to see output for submodels unless
|
||||
// something strange is going on
|
||||
if( !dmapGlobals.verboseentities )
|
||||
{
|
||||
dmapGlobals.verbose = false;
|
||||
}
|
||||
}
|
||||
|
||||
dmapGlobals.verbose = oldVerbose;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
DmapHelp
|
||||
============
|
||||
*/
|
||||
void DmapHelp( void )
|
||||
{
|
||||
common->Printf(
|
||||
|
||||
"Usage: dmap [options] mapfile\n"
|
||||
"Options:\n"
|
||||
"noCurves = don't process curves\n"
|
||||
"noCM = don't create collision map\n"
|
||||
"noAAS = don't create AAS files\n"
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ResetDmapGlobals
|
||||
============
|
||||
*/
|
||||
void ResetDmapGlobals( void )
|
||||
{
|
||||
dmapGlobals.mapFileBase[0] = '\0';
|
||||
dmapGlobals.dmapFile = NULL;
|
||||
dmapGlobals.mapPlanes.Clear();
|
||||
dmapGlobals.num_entities = 0;
|
||||
dmapGlobals.uEntities = NULL;
|
||||
dmapGlobals.entityNum = 0;
|
||||
dmapGlobals.mapLights.Clear();
|
||||
dmapGlobals.verbose = false;
|
||||
dmapGlobals.glview = false;
|
||||
dmapGlobals.noOptimize = false;
|
||||
dmapGlobals.verboseentities = false;
|
||||
dmapGlobals.noCurves = false;
|
||||
dmapGlobals.fullCarve = false;
|
||||
dmapGlobals.noModelBrushes = false;
|
||||
dmapGlobals.noTJunc = false;
|
||||
dmapGlobals.nomerge = false;
|
||||
dmapGlobals.noFlood = false;
|
||||
dmapGlobals.noClipSides = false;
|
||||
dmapGlobals.noLightCarve = false;
|
||||
dmapGlobals.noShadow = false;
|
||||
dmapGlobals.shadowOptLevel = SO_NONE;
|
||||
dmapGlobals.drawBounds.Clear();
|
||||
dmapGlobals.drawflag = false;
|
||||
dmapGlobals.totalShadowTriangles = 0;
|
||||
dmapGlobals.totalShadowVerts = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Dmap
|
||||
============
|
||||
*/
|
||||
void Dmap( const idCmdArgs& args )
|
||||
{
|
||||
int i;
|
||||
int start, end;
|
||||
char path[1024];
|
||||
idStr passedName;
|
||||
bool leaked = false;
|
||||
bool noCM = false;
|
||||
bool noAAS = false;
|
||||
|
||||
ResetDmapGlobals();
|
||||
|
||||
if( args.Argc() < 2 )
|
||||
{
|
||||
DmapHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
common->Printf( "---- dmap ----\n" );
|
||||
|
||||
dmapGlobals.fullCarve = true;
|
||||
dmapGlobals.shadowOptLevel = SO_MERGE_SURFACES; // create shadows by merging all surfaces, but no super optimization
|
||||
// dmapGlobals.shadowOptLevel = SO_CLIP_OCCLUDERS; // remove occluders that are completely covered
|
||||
// dmapGlobals.shadowOptLevel = SO_SIL_OPTIMIZE;
|
||||
// dmapGlobals.shadowOptLevel = SO_CULL_OCCLUDED;
|
||||
|
||||
dmapGlobals.noLightCarve = true;
|
||||
|
||||
for( i = 1 ; i < args.Argc() ; i++ )
|
||||
{
|
||||
const char* s;
|
||||
|
||||
s = args.Argv( i );
|
||||
if( s[0] == '-' )
|
||||
{
|
||||
s++;
|
||||
if( s[0] == '\0' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( !idStr::Icmp( s, "glview" ) )
|
||||
{
|
||||
dmapGlobals.glview = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "v" ) )
|
||||
{
|
||||
common->Printf( "verbose = true\n" );
|
||||
dmapGlobals.verbose = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "draw" ) )
|
||||
{
|
||||
common->Printf( "drawflag = true\n" );
|
||||
dmapGlobals.drawflag = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noFlood" ) )
|
||||
{
|
||||
common->Printf( "noFlood = true\n" );
|
||||
dmapGlobals.noFlood = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noLightCarve" ) )
|
||||
{
|
||||
common->Printf( "noLightCarve = true\n" );
|
||||
dmapGlobals.noLightCarve = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "lightCarve" ) )
|
||||
{
|
||||
common->Printf( "noLightCarve = false\n" );
|
||||
dmapGlobals.noLightCarve = false;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noOpt" ) )
|
||||
{
|
||||
common->Printf( "noOptimize = true\n" );
|
||||
dmapGlobals.noOptimize = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "verboseentities" ) )
|
||||
{
|
||||
common->Printf( "verboseentities = true\n" );
|
||||
dmapGlobals.verboseentities = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noCurves" ) )
|
||||
{
|
||||
common->Printf( "noCurves = true\n" );
|
||||
dmapGlobals.noCurves = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noModels" ) )
|
||||
{
|
||||
common->Printf( "noModels = true\n" );
|
||||
dmapGlobals.noModelBrushes = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noClipSides" ) )
|
||||
{
|
||||
common->Printf( "noClipSides = true\n" );
|
||||
dmapGlobals.noClipSides = true;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noCarve" ) )
|
||||
{
|
||||
common->Printf( "noCarve = true\n" );
|
||||
dmapGlobals.fullCarve = false;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "shadowOpt" ) )
|
||||
{
|
||||
dmapGlobals.shadowOptLevel = ( shadowOptLevel_t )atoi( args.Argv( i + 1 ) );
|
||||
common->Printf( "shadowOpt = %i\n", dmapGlobals.shadowOptLevel );
|
||||
i += 1;
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noTjunc" ) )
|
||||
{
|
||||
// triangle optimization won't work properly without tjunction fixing
|
||||
common->Printf( "noTJunc = true\n" );
|
||||
dmapGlobals.noTJunc = true;
|
||||
dmapGlobals.noOptimize = true;
|
||||
common->Printf( "forcing noOptimize = true\n" );
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noCM" ) )
|
||||
{
|
||||
noCM = true;
|
||||
common->Printf( "noCM = true\n" );
|
||||
}
|
||||
else if( !idStr::Icmp( s, "noAAS" ) )
|
||||
{
|
||||
noAAS = true;
|
||||
common->Printf( "noAAS = true\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i >= args.Argc() )
|
||||
{
|
||||
common->Error( "usage: dmap [options] mapfile" );
|
||||
}
|
||||
|
||||
passedName = args.Argv( i ); // may have an extension
|
||||
passedName.BackSlashesToSlashes();
|
||||
if( passedName.Icmpn( "maps/", 4 ) != 0 )
|
||||
{
|
||||
passedName = "maps/" + passedName;
|
||||
}
|
||||
|
||||
idStr stripped = passedName;
|
||||
stripped.StripFileExtension();
|
||||
idStr::Copynz( dmapGlobals.mapFileBase, stripped, sizeof( dmapGlobals.mapFileBase ) );
|
||||
|
||||
bool region = false;
|
||||
// if this isn't a regioned map, delete the last saved region map
|
||||
if( passedName.Right( 4 ) != ".reg" )
|
||||
{
|
||||
sprintf( path, "%s.reg", dmapGlobals.mapFileBase );
|
||||
fileSystem->RemoveFile( path );
|
||||
}
|
||||
else
|
||||
{
|
||||
region = true;
|
||||
}
|
||||
|
||||
|
||||
passedName = stripped;
|
||||
|
||||
// delete any old line leak files
|
||||
sprintf( path, "%s.lin", dmapGlobals.mapFileBase );
|
||||
fileSystem->RemoveFile( path );
|
||||
|
||||
// delete any old generated binary proc files
|
||||
idStr generated = va( "generated/%s.bproc", dmapGlobals.mapFileBase );
|
||||
fileSystem->RemoveFile( generated.c_str() );
|
||||
|
||||
//
|
||||
// start from scratch
|
||||
//
|
||||
start = Sys_Milliseconds();
|
||||
|
||||
if( !LoadDMapFile( passedName ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( ProcessModels() )
|
||||
{
|
||||
WriteOutputFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
leaked = true;
|
||||
}
|
||||
|
||||
FreeDMapFile();
|
||||
|
||||
common->Printf( "%i total shadow triangles\n", dmapGlobals.totalShadowTriangles );
|
||||
common->Printf( "%i total shadow verts\n", dmapGlobals.totalShadowVerts );
|
||||
|
||||
end = Sys_Milliseconds();
|
||||
common->Printf( "-----------------------\n" );
|
||||
common->Printf( "%5.0f seconds for dmap\n", ( end - start ) * 0.001f );
|
||||
|
||||
if( !leaked )
|
||||
{
|
||||
|
||||
if( !noCM )
|
||||
{
|
||||
|
||||
// make sure the collision model manager is not used by the game
|
||||
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "disconnect" );
|
||||
|
||||
// create the collision map
|
||||
start = Sys_Milliseconds();
|
||||
|
||||
collisionModelManager->LoadMap( dmapGlobals.dmapFile );
|
||||
collisionModelManager->FreeMap();
|
||||
|
||||
end = Sys_Milliseconds();
|
||||
common->Printf( "-------------------------------------\n" );
|
||||
common->Printf( "%5.0f seconds to create collision map\n", ( end - start ) * 0.001f );
|
||||
}
|
||||
|
||||
if( !noAAS && !region )
|
||||
{
|
||||
// create AAS files
|
||||
RunAAS_f( args );
|
||||
}
|
||||
}
|
||||
|
||||
// free the common .map representation
|
||||
delete dmapGlobals.dmapFile;
|
||||
|
||||
// clear the map plane list
|
||||
dmapGlobals.mapPlanes.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Dmap_f
|
||||
============
|
||||
*/
|
||||
void Dmap_f( const idCmdArgs& args )
|
||||
{
|
||||
|
||||
common->ClearWarnings( "running dmap" );
|
||||
|
||||
// refresh the screen each time we print so it doesn't look
|
||||
// like it is hung
|
||||
common->SetRefreshOnPrint( true );
|
||||
Dmap( args );
|
||||
common->SetRefreshOnPrint( false );
|
||||
|
||||
common->PrintWarnings();
|
||||
}
|
508
neo/tools/compilers/dmap/dmap.h
Normal file
508
neo/tools/compilers/dmap/dmap.h
Normal file
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../../renderer/tr_local.h"
|
||||
|
||||
|
||||
typedef struct primitive_s
|
||||
{
|
||||
struct primitive_s* next;
|
||||
|
||||
// only one of these will be non-NULL
|
||||
struct bspbrush_s* brush;
|
||||
struct mapTri_s* tris;
|
||||
} primitive_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct optimizeGroup_s* groups;
|
||||
// we might want to add other fields later
|
||||
} uArea_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
idMapEntity* mapEntity; // points into mapFile_t data
|
||||
|
||||
idVec3 origin;
|
||||
primitive_t* primitives;
|
||||
struct tree_s* tree;
|
||||
|
||||
int numAreas;
|
||||
uArea_t* areas;
|
||||
} uEntity_t;
|
||||
|
||||
|
||||
// chains of mapTri_t are the general unit of processing
|
||||
typedef struct mapTri_s
|
||||
{
|
||||
struct mapTri_s* next;
|
||||
|
||||
const idMaterial* material;
|
||||
void* mergeGroup; // we want to avoid merging triangles
|
||||
// from different fixed groups, like guiSurfs and mirrors
|
||||
int planeNum; // not set universally, just in some areas
|
||||
|
||||
idDrawVert v[3];
|
||||
const struct hashVert_s* hashVert[3];
|
||||
struct optVertex_s* optVert[3];
|
||||
} mapTri_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
idDrawVert* verts;
|
||||
} mesh_t;
|
||||
|
||||
|
||||
#define MAX_PATCH_SIZE 32
|
||||
|
||||
#define PLANENUM_LEAF -1
|
||||
|
||||
typedef struct parseMesh_s
|
||||
{
|
||||
struct parseMesh_s* next;
|
||||
mesh_t mesh;
|
||||
const idMaterial* material;
|
||||
} parseMesh_t;
|
||||
|
||||
typedef struct bspface_s
|
||||
{
|
||||
struct bspface_s* next;
|
||||
int planenum;
|
||||
bool portal; // all portals will be selected before
|
||||
// any non-portals
|
||||
bool checked; // used by SelectSplitPlaneNum()
|
||||
idWinding* w;
|
||||
} bspface_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
idVec4 v[2]; // the offset value will always be in the 0.0 to 1.0 range
|
||||
} textureVectors_t;
|
||||
|
||||
typedef struct side_s
|
||||
{
|
||||
int planenum;
|
||||
|
||||
const idMaterial* material;
|
||||
textureVectors_t texVec;
|
||||
|
||||
idWinding* winding; // only clipped to the other sides of the brush
|
||||
idWinding* visibleHull; // also clipped to the solid parts of the world
|
||||
} side_t;
|
||||
|
||||
|
||||
typedef struct bspbrush_s
|
||||
{
|
||||
struct bspbrush_s* next;
|
||||
struct bspbrush_s* original; // chopped up brushes will reference the originals
|
||||
|
||||
int entitynum; // editor numbering for messages
|
||||
int brushnum; // editor numbering for messages
|
||||
|
||||
const idMaterial* contentShader; // one face's shader will determine the volume attributes
|
||||
|
||||
int contents;
|
||||
bool opaque;
|
||||
int outputNumber; // set when the brush is written to the file list
|
||||
|
||||
idBounds bounds;
|
||||
int numsides;
|
||||
side_t sides[6]; // variably sized
|
||||
} uBrush_t;
|
||||
|
||||
|
||||
typedef struct drawSurfRef_s
|
||||
{
|
||||
struct drawSurfRef_s* nextRef;
|
||||
int outputNumber;
|
||||
} drawSurfRef_t;
|
||||
|
||||
|
||||
typedef struct node_s
|
||||
{
|
||||
// both leafs and nodes
|
||||
int planenum; // -1 = leaf node
|
||||
struct node_s* parent;
|
||||
idBounds bounds; // valid after portalization
|
||||
|
||||
// nodes only
|
||||
side_t* side; // the side that created the node
|
||||
struct node_s* children[2];
|
||||
int nodeNumber; // set after pruning
|
||||
|
||||
// leafs only
|
||||
bool opaque; // view can never be inside
|
||||
|
||||
uBrush_t* brushlist; // fragments of all brushes in this leaf
|
||||
// needed for FindSideForPortal
|
||||
|
||||
int area; // determined by flood filling up to areaportals
|
||||
int occupied; // 1 or greater can reach entity
|
||||
uEntity_t* occupant; // for leak file testing
|
||||
|
||||
struct uPortal_s* portals; // also on nodes during construction
|
||||
} node_t;
|
||||
|
||||
|
||||
typedef struct uPortal_s
|
||||
{
|
||||
idPlane plane;
|
||||
node_t* onnode; // NULL = outside box
|
||||
node_t* nodes[2]; // [0] = front side of plane
|
||||
struct uPortal_s* next[2];
|
||||
idWinding* winding;
|
||||
} uPortal_t;
|
||||
|
||||
// a tree_t is created by FaceBSP()
|
||||
typedef struct tree_s
|
||||
{
|
||||
node_t* headnode;
|
||||
node_t outside_node;
|
||||
idBounds bounds;
|
||||
} tree_t;
|
||||
|
||||
#define MAX_QPATH 256 // max length of a game pathname
|
||||
|
||||
typedef struct
|
||||
{
|
||||
idRenderLightLocal def;
|
||||
char name[MAX_QPATH]; // for naming the shadow volume surface and interactions
|
||||
srfTriangles_t* shadowTris;
|
||||
} mapLight_t;
|
||||
|
||||
#define MAX_GROUP_LIGHTS 16
|
||||
|
||||
typedef struct optimizeGroup_s
|
||||
{
|
||||
struct optimizeGroup_s* nextGroup;
|
||||
|
||||
idBounds bounds; // set in CarveGroupsByLight
|
||||
|
||||
// all of these must match to add a triangle to the triList
|
||||
bool smoothed; // curves will never merge with brushes
|
||||
int planeNum;
|
||||
int areaNum;
|
||||
const idMaterial* material;
|
||||
int numGroupLights;
|
||||
mapLight_t* groupLights[MAX_GROUP_LIGHTS]; // lights effecting this list
|
||||
void* mergeGroup; // if this differs (guiSurfs, mirrors, etc), the
|
||||
// groups will not be combined into model surfaces
|
||||
// after optimization
|
||||
textureVectors_t texVec;
|
||||
|
||||
bool surfaceEmited;
|
||||
|
||||
mapTri_t* triList;
|
||||
mapTri_t* regeneratedTris; // after each island optimization
|
||||
idVec3 axis[2]; // orthogonal to the plane, so optimization can be 2D
|
||||
} optimizeGroup_t;
|
||||
|
||||
// all primitives from the map are added to optimzeGroups, creating new ones as needed
|
||||
// each optimizeGroup is then split into the map areas, creating groups in each area
|
||||
// each optimizeGroup is then divided by each light, creating more groups
|
||||
// the final list of groups is then tjunction fixed against all groups, then optimized internally
|
||||
// multiple optimizeGroups will be merged together into .proc surfaces, but no further optimization
|
||||
// is done on them
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// dmap.cpp
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SO_NONE, // 0
|
||||
SO_MERGE_SURFACES, // 1
|
||||
SO_CULL_OCCLUDED, // 2
|
||||
SO_CLIP_OCCLUDERS, // 3
|
||||
SO_CLIP_SILS, // 4
|
||||
SO_SIL_OPTIMIZE // 5
|
||||
} shadowOptLevel_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// mapFileBase will contain the qpath without any extension: "maps/test_box"
|
||||
char mapFileBase[1024];
|
||||
|
||||
idMapFile* dmapFile;
|
||||
|
||||
idPlaneSet mapPlanes;
|
||||
|
||||
int num_entities;
|
||||
uEntity_t* uEntities;
|
||||
|
||||
int entityNum;
|
||||
|
||||
idList<mapLight_t*> mapLights;
|
||||
|
||||
bool verbose;
|
||||
|
||||
bool glview;
|
||||
bool noOptimize;
|
||||
bool verboseentities;
|
||||
bool noCurves;
|
||||
bool fullCarve;
|
||||
bool noModelBrushes;
|
||||
bool noTJunc;
|
||||
bool nomerge;
|
||||
bool noFlood;
|
||||
bool noClipSides; // don't cut sides by solid leafs, use the entire thing
|
||||
bool noLightCarve; // extra triangle subdivision by light frustums
|
||||
shadowOptLevel_t shadowOptLevel;
|
||||
bool noShadow; // don't create optimized shadow volumes
|
||||
|
||||
idBounds drawBounds;
|
||||
bool drawflag;
|
||||
|
||||
int totalShadowTriangles;
|
||||
int totalShadowVerts;
|
||||
} dmapGlobals_t;
|
||||
|
||||
extern dmapGlobals_t dmapGlobals;
|
||||
|
||||
int FindFloatPlane( const idPlane& plane, bool* fixedDegeneracies = NULL );
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// brush.cpp
|
||||
|
||||
#ifndef CLIP_EPSILON
|
||||
#define CLIP_EPSILON 0.1f
|
||||
#endif
|
||||
|
||||
#define PSIDE_FRONT 1
|
||||
#define PSIDE_BACK 2
|
||||
#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK)
|
||||
#define PSIDE_FACING 4
|
||||
|
||||
int CountBrushList( uBrush_t* brushes );
|
||||
uBrush_t* AllocBrush( int numsides );
|
||||
void FreeBrush( uBrush_t* brushes );
|
||||
void FreeBrushList( uBrush_t* brushes );
|
||||
uBrush_t* CopyBrush( uBrush_t* brush );
|
||||
void DrawBrushList( uBrush_t* brush );
|
||||
void PrintBrush( uBrush_t* brush );
|
||||
bool BoundBrush( uBrush_t* brush );
|
||||
bool CreateBrushWindings( uBrush_t* brush );
|
||||
uBrush_t* BrushFromBounds( const idBounds& bounds );
|
||||
float BrushVolume( uBrush_t* brush );
|
||||
void WriteBspBrushMap( const char* name, uBrush_t* list );
|
||||
|
||||
void FilterBrushesIntoTree( uEntity_t* e );
|
||||
|
||||
void SplitBrush( uBrush_t* brush, int planenum, uBrush_t** front, uBrush_t** back );
|
||||
node_t* AllocNode( void );
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// map.cpp
|
||||
|
||||
bool LoadDMapFile( const char* filename );
|
||||
void FreeOptimizeGroupList( optimizeGroup_t* groups );
|
||||
void FreeDMapFile( void );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// draw.cpp -- draw debug views either directly, or through glserv.exe
|
||||
|
||||
void Draw_ClearWindow( void );
|
||||
void DrawWinding( const idWinding* w );
|
||||
void DrawAuxWinding( const idWinding* w );
|
||||
|
||||
void DrawLine( idVec3 v1, idVec3 v2, int color );
|
||||
|
||||
void GLS_BeginScene( void );
|
||||
void GLS_Winding( const idWinding* w, int code );
|
||||
void GLS_Triangle( const mapTri_t* tri, int code );
|
||||
void GLS_EndScene( void );
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// portals.cpp
|
||||
|
||||
#define MAX_INTER_AREA_PORTALS 1024
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int area0, area1;
|
||||
side_t* side;
|
||||
} interAreaPortal_t;
|
||||
|
||||
extern interAreaPortal_t interAreaPortals[MAX_INTER_AREA_PORTALS];
|
||||
extern int numInterAreaPortals;
|
||||
|
||||
bool FloodEntities( tree_t* tree );
|
||||
void FillOutside( uEntity_t* e );
|
||||
void FloodAreas( uEntity_t* e );
|
||||
void MakeTreePortals( tree_t* tree );
|
||||
void FreePortal( uPortal_t* p );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// glfile.cpp -- write a debug file to be viewd with glview.exe
|
||||
|
||||
void OutputWinding( idWinding* w, idFile* glview );
|
||||
void WriteGLView( tree_t* tree, char* source );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// leakfile.cpp
|
||||
|
||||
void LeakFile( tree_t* tree );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// facebsp.cpp
|
||||
|
||||
tree_t* AllocTree( void );
|
||||
|
||||
void FreeTree( tree_t* tree );
|
||||
|
||||
void FreeTree_r( node_t* node );
|
||||
void FreeTreePortals_r( node_t* node );
|
||||
|
||||
|
||||
bspface_t* MakeStructuralBspFaceList( primitive_t* list );
|
||||
bspface_t* MakeVisibleBspFaceList( primitive_t* list );
|
||||
tree_t* FaceBSP( bspface_t* list );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// surface.cpp
|
||||
|
||||
mapTri_t* CullTrisInOpaqueLeafs( mapTri_t* triList, tree_t* tree );
|
||||
void ClipSidesByTree( uEntity_t* e );
|
||||
void SplitTrisToSurfaces( mapTri_t* triList, tree_t* tree );
|
||||
void PutPrimitivesInAreas( uEntity_t* e );
|
||||
void Prelight( uEntity_t* e );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// tritjunction.cpp
|
||||
|
||||
struct hashVert_s* GetHashVert( idVec3& v );
|
||||
void HashTriangles( optimizeGroup_t* groupList );
|
||||
void FreeTJunctionHash( void );
|
||||
int CountGroupListTris( const optimizeGroup_t* groupList );
|
||||
void FixEntityTjunctions( uEntity_t* e );
|
||||
void FixAreaGroupsTjunctions( optimizeGroup_t* groupList );
|
||||
void FixGlobalTjunctions( uEntity_t* e );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// optimize.cpp -- trianlge mesh reoptimization
|
||||
|
||||
// the shadow volume optimizer call internal optimizer routines, normal triangles
|
||||
// will just be done by OptimizeEntity()
|
||||
|
||||
|
||||
typedef struct optVertex_s
|
||||
{
|
||||
idDrawVert v;
|
||||
idVec3 pv; // projected against planar axis, third value is 0
|
||||
struct optEdge_s* edges;
|
||||
struct optVertex_s* islandLink;
|
||||
bool addedToIsland;
|
||||
bool emited; // when regenerating triangles
|
||||
} optVertex_t;
|
||||
|
||||
typedef struct optEdge_s
|
||||
{
|
||||
optVertex_t* v1, *v2;
|
||||
struct optEdge_s* islandLink;
|
||||
bool addedToIsland;
|
||||
bool created; // not one of the original edges
|
||||
bool combined; // combined from two or more colinear edges
|
||||
struct optTri_s* frontTri, *backTri;
|
||||
struct optEdge_s* v1link, *v2link;
|
||||
} optEdge_t;
|
||||
|
||||
typedef struct optTri_s
|
||||
{
|
||||
struct optTri_s* next;
|
||||
idVec3 midpoint;
|
||||
optVertex_t* v[3];
|
||||
bool filled;
|
||||
} optTri_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
optimizeGroup_t* group;
|
||||
optVertex_t* verts;
|
||||
optEdge_t* edges;
|
||||
optTri_t* tris;
|
||||
} optIsland_t;
|
||||
|
||||
|
||||
void OptimizeEntity( uEntity_t* e );
|
||||
void OptimizeGroupList( optimizeGroup_t* groupList );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// tritools.cpp
|
||||
|
||||
mapTri_t* AllocTri( void );
|
||||
void FreeTri( mapTri_t* tri );
|
||||
int CountTriList( const mapTri_t* list );
|
||||
mapTri_t* MergeTriLists( mapTri_t* a, mapTri_t* b );
|
||||
mapTri_t* CopyTriList( const mapTri_t* a );
|
||||
void FreeTriList( mapTri_t* a );
|
||||
mapTri_t* CopyMapTri( const mapTri_t* tri );
|
||||
float MapTriArea( const mapTri_t* tri );
|
||||
mapTri_t* RemoveBadTris( const mapTri_t* tri );
|
||||
void BoundTriList( const mapTri_t* list, idBounds& b );
|
||||
void DrawTri( const mapTri_t* tri );
|
||||
void FlipTriList( mapTri_t* tris );
|
||||
void TriVertsFromOriginal( mapTri_t* tri, const mapTri_t* original );
|
||||
void PlaneForTri( const mapTri_t* tri, idPlane& plane );
|
||||
idWinding* WindingForTri( const mapTri_t* tri );
|
||||
mapTri_t* WindingToTriList( const idWinding* w, const mapTri_t* originalTri );
|
||||
void ClipTriList( const mapTri_t* list, const idPlane& plane, float epsilon, mapTri_t** front, mapTri_t** back );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// output.cpp
|
||||
|
||||
srfTriangles_t* ShareMapTriVerts( const mapTri_t* tris );
|
||||
void WriteOutputFile( void );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// shadowopt.cpp
|
||||
|
||||
srfTriangles_t* CreateLightShadow( optimizeGroup_t* shadowerGroups, const mapLight_t* light );
|
||||
void FreeBeamTree( struct beamTree_s* beamTree );
|
||||
|
||||
void CarveTriByBeamTree( const struct beamTree_s* beamTree, const mapTri_t* tri, mapTri_t** lit, mapTri_t** unLit );
|
563
neo/tools/compilers/dmap/facebsp.cpp
Normal file
563
neo/tools/compilers/dmap/facebsp.cpp
Normal file
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
int c_faceLeafs;
|
||||
|
||||
|
||||
extern int c_nodes;
|
||||
|
||||
void RemovePortalFromNode( uPortal_t* portal, node_t* l );
|
||||
|
||||
node_t* NodeForPoint( node_t* node, idVec3 origin )
|
||||
{
|
||||
float d;
|
||||
|
||||
while( node->planenum != PLANENUM_LEAF )
|
||||
{
|
||||
idPlane& plane = dmapGlobals.mapPlanes[node->planenum];
|
||||
d = plane.Distance( origin );
|
||||
if( d >= 0 )
|
||||
{
|
||||
node = node->children[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->children[1];
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTreePortals_r
|
||||
=============
|
||||
*/
|
||||
void FreeTreePortals_r( node_t* node )
|
||||
{
|
||||
uPortal_t* p, *nextp;
|
||||
int s;
|
||||
|
||||
// free children
|
||||
if( node->planenum != PLANENUM_LEAF )
|
||||
{
|
||||
FreeTreePortals_r( node->children[0] );
|
||||
FreeTreePortals_r( node->children[1] );
|
||||
}
|
||||
|
||||
// free portals
|
||||
for( p = node->portals ; p ; p = nextp )
|
||||
{
|
||||
s = ( p->nodes[1] == node );
|
||||
nextp = p->next[s];
|
||||
|
||||
RemovePortalFromNode( p, p->nodes[!s] );
|
||||
FreePortal( p );
|
||||
}
|
||||
node->portals = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTree_r
|
||||
=============
|
||||
*/
|
||||
void FreeTree_r( node_t* node )
|
||||
{
|
||||
// free children
|
||||
if( node->planenum != PLANENUM_LEAF )
|
||||
{
|
||||
FreeTree_r( node->children[0] );
|
||||
FreeTree_r( node->children[1] );
|
||||
}
|
||||
|
||||
// free brushes
|
||||
FreeBrushList( node->brushlist );
|
||||
|
||||
// free the node
|
||||
c_nodes--;
|
||||
Mem_Free( node );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTree
|
||||
=============
|
||||
*/
|
||||
void FreeTree( tree_t* tree )
|
||||
{
|
||||
if( !tree )
|
||||
{
|
||||
return;
|
||||
}
|
||||
FreeTreePortals_r( tree->headnode );
|
||||
FreeTree_r( tree->headnode );
|
||||
Mem_Free( tree );
|
||||
}
|
||||
|
||||
//===============================================================
|
||||
|
||||
void PrintTree_r( node_t* node, int depth )
|
||||
{
|
||||
int i;
|
||||
uBrush_t* bb;
|
||||
|
||||
for( i = 0 ; i < depth ; i++ )
|
||||
common->Printf( " " );
|
||||
if( node->planenum == PLANENUM_LEAF )
|
||||
{
|
||||
if( !node->brushlist )
|
||||
common->Printf( "NULL\n" );
|
||||
else
|
||||
{
|
||||
for( bb = node->brushlist ; bb ; bb = bb->next )
|
||||
common->Printf( "%i ", bb->original->brushnum );
|
||||
common->Printf( "\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
idPlane& plane = dmapGlobals.mapPlanes[node->planenum];
|
||||
common->Printf( "#%i (%5.2f %5.2f %5.2f %5.2f)\n", node->planenum,
|
||||
plane[0], plane[1], plane[2], plane[3] );
|
||||
PrintTree_r( node->children[0], depth + 1 );
|
||||
PrintTree_r( node->children[1], depth + 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
AllocBspFace
|
||||
================
|
||||
*/
|
||||
bspface_t* AllocBspFace( void )
|
||||
{
|
||||
bspface_t* f;
|
||||
|
||||
f = ( bspface_t* )Mem_Alloc( sizeof( *f ), TAG_TOOLS );
|
||||
memset( f, 0, sizeof( *f ) );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FreeBspFace
|
||||
================
|
||||
*/
|
||||
void FreeBspFace( bspface_t* f )
|
||||
{
|
||||
if( f->w )
|
||||
{
|
||||
delete f->w;
|
||||
}
|
||||
Mem_Free( f );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SelectSplitPlaneNum
|
||||
================
|
||||
*/
|
||||
#define BLOCK_SIZE 1024
|
||||
int SelectSplitPlaneNum( node_t* node, bspface_t* list )
|
||||
{
|
||||
bspface_t* split;
|
||||
bspface_t* check;
|
||||
bspface_t* bestSplit;
|
||||
int splits, facing, front, back;
|
||||
int side;
|
||||
idPlane* mapPlane;
|
||||
int value, bestValue;
|
||||
idPlane plane;
|
||||
int planenum;
|
||||
bool havePortals;
|
||||
float dist;
|
||||
idVec3 halfSize;
|
||||
|
||||
// if it is crossing a 1k block boundary, force a split
|
||||
// this prevents epsilon problems from extending an
|
||||
// arbitrary distance across the map
|
||||
|
||||
halfSize = ( node->bounds[1] - node->bounds[0] ) * 0.5f;
|
||||
for( int axis = 0; axis < 3; axis++ )
|
||||
{
|
||||
if( halfSize[axis] > BLOCK_SIZE )
|
||||
{
|
||||
dist = BLOCK_SIZE * ( floor( ( node->bounds[0][axis] + halfSize[axis] ) / BLOCK_SIZE ) + 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
dist = BLOCK_SIZE * ( floor( node->bounds[0][axis] / BLOCK_SIZE ) + 1.0f );
|
||||
}
|
||||
if( dist > node->bounds[0][axis] + 1.0f && dist < node->bounds[1][axis] - 1.0f )
|
||||
{
|
||||
plane[0] = plane[1] = plane[2] = 0.0f;
|
||||
plane[axis] = 1.0f;
|
||||
plane[3] = -dist;
|
||||
planenum = FindFloatPlane( plane );
|
||||
return planenum;
|
||||
}
|
||||
}
|
||||
|
||||
// pick one of the face planes
|
||||
// if we have any portal faces at all, only
|
||||
// select from them, otherwise select from
|
||||
// all faces
|
||||
bestValue = -999999;
|
||||
bestSplit = list;
|
||||
|
||||
havePortals = false;
|
||||
for( split = list ; split ; split = split->next )
|
||||
{
|
||||
split->checked = false;
|
||||
if( split->portal )
|
||||
{
|
||||
havePortals = true;
|
||||
}
|
||||
}
|
||||
|
||||
for( split = list ; split ; split = split->next )
|
||||
{
|
||||
if( split->checked )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( havePortals != split->portal )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
mapPlane = &dmapGlobals.mapPlanes[ split->planenum ];
|
||||
splits = 0;
|
||||
facing = 0;
|
||||
front = 0;
|
||||
back = 0;
|
||||
for( check = list ; check ; check = check->next )
|
||||
{
|
||||
if( check->planenum == split->planenum )
|
||||
{
|
||||
facing++;
|
||||
check->checked = true; // won't need to test this plane again
|
||||
continue;
|
||||
}
|
||||
side = check->w->PlaneSide( *mapPlane );
|
||||
if( side == SIDE_CROSS )
|
||||
{
|
||||
splits++;
|
||||
}
|
||||
else if( side == SIDE_FRONT )
|
||||
{
|
||||
front++;
|
||||
}
|
||||
else if( side == SIDE_BACK )
|
||||
{
|
||||
back++;
|
||||
}
|
||||
}
|
||||
value = 5 * facing - 5 * splits; // - abs(front-back);
|
||||
if( mapPlane->Type() < PLANETYPE_TRUEAXIAL )
|
||||
{
|
||||
value += 5; // axial is better
|
||||
}
|
||||
|
||||
if( value > bestValue )
|
||||
{
|
||||
bestValue = value;
|
||||
bestSplit = split;
|
||||
}
|
||||
}
|
||||
|
||||
if( bestValue == -999999 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return bestSplit->planenum;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
BuildFaceTree_r
|
||||
================
|
||||
*/
|
||||
void BuildFaceTree_r( node_t* node, bspface_t* list )
|
||||
{
|
||||
bspface_t* split;
|
||||
bspface_t* next;
|
||||
int side;
|
||||
bspface_t* newFace;
|
||||
bspface_t* childLists[2];
|
||||
idWinding* frontWinding, *backWinding;
|
||||
int i;
|
||||
int splitPlaneNum;
|
||||
|
||||
splitPlaneNum = SelectSplitPlaneNum( node, list );
|
||||
// if we don't have any more faces, this is a node
|
||||
if( splitPlaneNum == -1 )
|
||||
{
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
c_faceLeafs++;
|
||||
return;
|
||||
}
|
||||
|
||||
// partition the list
|
||||
node->planenum = splitPlaneNum;
|
||||
idPlane& plane = dmapGlobals.mapPlanes[ splitPlaneNum ];
|
||||
childLists[0] = NULL;
|
||||
childLists[1] = NULL;
|
||||
for( split = list ; split ; split = next )
|
||||
{
|
||||
next = split->next;
|
||||
|
||||
if( split->planenum == node->planenum )
|
||||
{
|
||||
FreeBspFace( split );
|
||||
continue;
|
||||
}
|
||||
|
||||
side = split->w->PlaneSide( plane );
|
||||
|
||||
if( side == SIDE_CROSS )
|
||||
{
|
||||
split->w->Split( plane, CLIP_EPSILON * 2, &frontWinding, &backWinding );
|
||||
if( frontWinding )
|
||||
{
|
||||
newFace = AllocBspFace();
|
||||
newFace->w = frontWinding;
|
||||
newFace->next = childLists[0];
|
||||
newFace->planenum = split->planenum;
|
||||
childLists[0] = newFace;
|
||||
}
|
||||
if( backWinding )
|
||||
{
|
||||
newFace = AllocBspFace();
|
||||
newFace->w = backWinding;
|
||||
newFace->next = childLists[1];
|
||||
newFace->planenum = split->planenum;
|
||||
childLists[1] = newFace;
|
||||
}
|
||||
FreeBspFace( split );
|
||||
}
|
||||
else if( side == SIDE_FRONT )
|
||||
{
|
||||
split->next = childLists[0];
|
||||
childLists[0] = split;
|
||||
}
|
||||
else if( side == SIDE_BACK )
|
||||
{
|
||||
split->next = childLists[1];
|
||||
childLists[1] = split;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// recursively process children
|
||||
for( i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
node->children[i] = AllocNode();
|
||||
node->children[i]->parent = node;
|
||||
node->children[i]->bounds = node->bounds;
|
||||
}
|
||||
|
||||
// split the bounds if we have a nice axial plane
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
if( idMath::Fabs( plane[i] - 1.0 ) < 0.001 )
|
||||
{
|
||||
node->children[0]->bounds[0][i] = plane.Dist();
|
||||
node->children[1]->bounds[1][i] = plane.Dist();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
BuildFaceTree_r( node->children[i], childLists[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FaceBSP
|
||||
|
||||
List will be freed before returning
|
||||
================
|
||||
*/
|
||||
tree_t* FaceBSP( bspface_t* list )
|
||||
{
|
||||
tree_t* tree;
|
||||
bspface_t* face;
|
||||
int i;
|
||||
int count;
|
||||
int start, end;
|
||||
|
||||
start = Sys_Milliseconds();
|
||||
|
||||
common->Printf( "--- FaceBSP ---\n" );
|
||||
|
||||
tree = AllocTree();
|
||||
|
||||
count = 0;
|
||||
tree->bounds.Clear();
|
||||
for( face = list ; face ; face = face->next )
|
||||
{
|
||||
count++;
|
||||
for( i = 0 ; i < face->w->GetNumPoints() ; i++ )
|
||||
{
|
||||
tree->bounds.AddPoint( ( *face->w )[i].ToVec3() );
|
||||
}
|
||||
}
|
||||
common->Printf( "%5i faces\n", count );
|
||||
|
||||
tree->headnode = AllocNode();
|
||||
tree->headnode->bounds = tree->bounds;
|
||||
c_faceLeafs = 0;
|
||||
|
||||
BuildFaceTree_r( tree->headnode, list );
|
||||
|
||||
common->Printf( "%5i leafs\n", c_faceLeafs );
|
||||
|
||||
end = Sys_Milliseconds();
|
||||
|
||||
common->Printf( "%5.1f seconds faceBsp\n", ( end - start ) / 1000.0 );
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
||||
/*
|
||||
=================
|
||||
MakeStructuralBspFaceList
|
||||
=================
|
||||
*/
|
||||
bspface_t* MakeStructuralBspFaceList( primitive_t* list )
|
||||
{
|
||||
uBrush_t* b;
|
||||
int i;
|
||||
side_t* s;
|
||||
idWinding* w;
|
||||
bspface_t* f, *flist;
|
||||
|
||||
flist = NULL;
|
||||
for( ; list ; list = list->next )
|
||||
{
|
||||
b = list->brush;
|
||||
if( !b )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !b->opaque && !( b->contents & CONTENTS_AREAPORTAL ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for( i = 0 ; i < b->numsides ; i++ )
|
||||
{
|
||||
s = &b->sides[i];
|
||||
w = s->winding;
|
||||
if( !w )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( ( b->contents & CONTENTS_AREAPORTAL ) && !( s->material->GetContentFlags() & CONTENTS_AREAPORTAL ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
f = AllocBspFace();
|
||||
if( s->material->GetContentFlags() & CONTENTS_AREAPORTAL )
|
||||
{
|
||||
f->portal = true;
|
||||
}
|
||||
f->w = w->Copy();
|
||||
f->planenum = s->planenum & ~1;
|
||||
f->next = flist;
|
||||
flist = f;
|
||||
}
|
||||
}
|
||||
|
||||
return flist;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
MakeVisibleBspFaceList
|
||||
=================
|
||||
*/
|
||||
bspface_t* MakeVisibleBspFaceList( primitive_t* list )
|
||||
{
|
||||
uBrush_t* b;
|
||||
int i;
|
||||
side_t* s;
|
||||
idWinding* w;
|
||||
bspface_t* f, *flist;
|
||||
|
||||
flist = NULL;
|
||||
for( ; list ; list = list->next )
|
||||
{
|
||||
b = list->brush;
|
||||
if( !b )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !b->opaque && !( b->contents & CONTENTS_AREAPORTAL ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for( i = 0 ; i < b->numsides ; i++ )
|
||||
{
|
||||
s = &b->sides[i];
|
||||
w = s->visibleHull;
|
||||
if( !w )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
f = AllocBspFace();
|
||||
if( s->material->GetContentFlags() & CONTENTS_AREAPORTAL )
|
||||
{
|
||||
f->portal = true;
|
||||
}
|
||||
f->w = w->Copy();
|
||||
f->planenum = s->planenum & ~1;
|
||||
f->next = flist;
|
||||
flist = f;
|
||||
}
|
||||
}
|
||||
|
||||
return flist;
|
||||
}
|
||||
|
320
neo/tools/compilers/dmap/gldraw.cpp
Normal file
320
neo/tools/compilers/dmap/gldraw.cpp
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
#if 0
|
||||
#include <windows.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
//#include <GL/glaux.h>
|
||||
|
||||
#define WIN_SIZE 1024
|
||||
|
||||
void Draw_ClearWindow( void )
|
||||
{
|
||||
|
||||
if( !dmapGlobals.drawflag )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glDrawBuffer( GL_FRONT );
|
||||
|
||||
GL_Set2D();
|
||||
|
||||
glClearColor( 0.5, 0.5, 0.5, 0 );
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
|
||||
#if 0
|
||||
int w, h, g;
|
||||
float mx, my;
|
||||
|
||||
w = ( dmapGlobals.drawBounds.b[1][0] - dmapGlobals.drawBounds.b[0][0] );
|
||||
h = ( dmapGlobals.drawBounds.b[1][1] - dmapGlobals.drawBounds.b[0][1] );
|
||||
|
||||
mx = dmapGlobals.drawBounds.b[0][0] + w / 2;
|
||||
my = dmapGlobals.drawBounds.b[1][1] + h / 2;
|
||||
|
||||
g = w > h ? w : h;
|
||||
|
||||
glLoadIdentity();
|
||||
gluPerspective( 90, 1, 2, 16384 );
|
||||
gluLookAt( mx, my, draw_maxs[2] + g / 2, mx , my, draw_maxs[2], 0, 1, 0 );
|
||||
#else
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
glOrtho( dmapGlobals.drawBounds[0][0], dmapGlobals.drawBounds[1][0],
|
||||
dmapGlobals.drawBounds[0][1], dmapGlobals.drawBounds[1][1],
|
||||
-1, 1 );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
#endif
|
||||
glColor3f( 0, 0, 0 );
|
||||
// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
// glEnable (GL_BLEND);
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
#if 0
|
||||
//glColor4f (1,0,0,0.5);
|
||||
// glBegin( GL_LINE_LOOP );
|
||||
glBegin( GL_QUADS );
|
||||
|
||||
glVertex2f( dmapGlobals.drawBounds.b[0][0] + 20, dmapGlobals.drawBounds.b[0][1] + 20 );
|
||||
glVertex2f( dmapGlobals.drawBounds.b[1][0] - 20, dmapGlobals.drawBounds.b[0][1] + 20 );
|
||||
glVertex2f( dmapGlobals.drawBounds.b[1][0] - 20, dmapGlobals.drawBounds.b[1][1] - 20 );
|
||||
glVertex2f( dmapGlobals.drawBounds.b[0][0] + 20, dmapGlobals.drawBounds.b[1][1] - 20 );
|
||||
|
||||
glEnd();
|
||||
#endif
|
||||
|
||||
glFlush();
|
||||
|
||||
}
|
||||
|
||||
void Draw_SetRed( void )
|
||||
{
|
||||
if( !dmapGlobals.drawflag )
|
||||
return;
|
||||
|
||||
glColor3f( 1, 0, 0 );
|
||||
}
|
||||
|
||||
void Draw_SetGrey( void )
|
||||
{
|
||||
if( !dmapGlobals.drawflag )
|
||||
return;
|
||||
|
||||
glColor3f( 0.5f, 0.5f, 0.5f );
|
||||
}
|
||||
|
||||
void Draw_SetBlack( void )
|
||||
{
|
||||
if( !dmapGlobals.drawflag )
|
||||
return;
|
||||
|
||||
glColor3f( 0.0f, 0.0f, 0.0f );
|
||||
}
|
||||
|
||||
void DrawWinding( const idWinding* w )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !dmapGlobals.drawflag )
|
||||
return;
|
||||
|
||||
glColor3f( 0.3f, 0.0f, 0.0f );
|
||||
glBegin( GL_POLYGON );
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
glVertex3f( ( *w )[i][0], ( *w )[i][1], ( *w )[i][2] );
|
||||
glEnd();
|
||||
|
||||
glColor3f( 1, 0, 0 );
|
||||
glBegin( GL_LINE_LOOP );
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
glVertex3f( ( *w )[i][0], ( *w )[i][1], ( *w )[i][2] );
|
||||
glEnd();
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void DrawAuxWinding( const idWinding* w )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !dmapGlobals.drawflag )
|
||||
return;
|
||||
|
||||
glColor3f( 0.0f, 0.3f, 0.0f );
|
||||
glBegin( GL_POLYGON );
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
glVertex3f( ( *w )[i][0], ( *w )[i][1], ( *w )[i][2] );
|
||||
glEnd();
|
||||
|
||||
glColor3f( 0.0f, 1.0f, 0.0f );
|
||||
glBegin( GL_LINE_LOOP );
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
glVertex3f( ( *w )[i][0], ( *w )[i][1], ( *w )[i][2] );
|
||||
glEnd();
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void DrawLine( idVec3 v1, idVec3 v2, int color )
|
||||
{
|
||||
if( !dmapGlobals.drawflag )
|
||||
return;
|
||||
|
||||
switch( color )
|
||||
{
|
||||
case 0:
|
||||
glColor3f( 0, 0, 0 );
|
||||
break;
|
||||
case 1:
|
||||
glColor3f( 0, 0, 1 );
|
||||
break;
|
||||
case 2:
|
||||
glColor3f( 0, 1, 0 );
|
||||
break;
|
||||
case 3:
|
||||
glColor3f( 0, 1, 1 );
|
||||
break;
|
||||
case 4:
|
||||
glColor3f( 1, 0, 0 );
|
||||
break;
|
||||
case 5:
|
||||
glColor3f( 1, 0, 1 );
|
||||
break;
|
||||
case 6:
|
||||
glColor3f( 1, 1, 0 );
|
||||
break;
|
||||
case 7:
|
||||
glColor3f( 1, 1, 1 );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
glBegin( GL_LINES );
|
||||
|
||||
glVertex3fv( v1.ToFloatPtr() );
|
||||
glVertex3fv( v2.ToFloatPtr() );
|
||||
|
||||
glEnd();
|
||||
glFlush();
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
#define GLSERV_PORT 25001
|
||||
|
||||
bool wins_init;
|
||||
int draw_socket;
|
||||
|
||||
void GLS_BeginScene( void )
|
||||
{
|
||||
WSADATA winsockdata;
|
||||
WORD wVersionRequested;
|
||||
struct sockaddr_in address;
|
||||
int r;
|
||||
|
||||
if( !wins_init )
|
||||
{
|
||||
wins_init = true;
|
||||
|
||||
wVersionRequested = MAKEWORD( 1, 1 );
|
||||
|
||||
r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
|
||||
|
||||
if( r )
|
||||
common->Error( "Winsock initialization failed." );
|
||||
|
||||
}
|
||||
|
||||
// connect a socket to the server
|
||||
|
||||
draw_socket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if( draw_socket == -1 )
|
||||
common->Error( "draw_socket failed" );
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
|
||||
address.sin_port = GLSERV_PORT;
|
||||
r = connect( draw_socket, ( struct sockaddr* )&address, sizeof( address ) );
|
||||
if( r == -1 )
|
||||
{
|
||||
closesocket( draw_socket );
|
||||
draw_socket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GLS_Winding( const idWinding* w, int code )
|
||||
{
|
||||
byte buf[1024];
|
||||
int i, j;
|
||||
|
||||
if( !draw_socket )
|
||||
return;
|
||||
|
||||
( ( int* )buf )[0] = w->GetNumPoints();
|
||||
( ( int* )buf )[1] = code;
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
for( j = 0 ; j < 3 ; j++ )
|
||||
( ( float* )buf )[2 + i * 3 + j] = ( *w )[i][j];
|
||||
|
||||
send( draw_socket, ( const char* )buf, w->GetNumPoints() * 12 + 8, 0 );
|
||||
}
|
||||
|
||||
void GLS_Triangle( const mapTri_t* tri, int code )
|
||||
{
|
||||
idWinding w;
|
||||
|
||||
w.SetNumPoints( 3 );
|
||||
w[0] = tri->v[0].xyz;
|
||||
w[1] = tri->v[1].xyz;
|
||||
w[2] = tri->v[2].xyz;
|
||||
GLS_Winding( &w, code );
|
||||
}
|
||||
|
||||
void GLS_EndScene( void )
|
||||
{
|
||||
closesocket( draw_socket );
|
||||
draw_socket = 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void Draw_ClearWindow( void )
|
||||
{
|
||||
}
|
||||
|
||||
void DrawWinding( const idWinding* w )
|
||||
{
|
||||
}
|
||||
|
||||
void DrawAuxWinding( const idWinding* w )
|
||||
{
|
||||
}
|
||||
|
||||
void GLS_Winding( const idWinding* w, int code )
|
||||
{
|
||||
}
|
||||
|
||||
void GLS_BeginScene( void )
|
||||
{
|
||||
}
|
||||
|
||||
void GLS_EndScene( void )
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
165
neo/tools/compilers/dmap/glfile.cpp
Normal file
165
neo/tools/compilers/dmap/glfile.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
int c_glfaces;
|
||||
|
||||
int PortalVisibleSides( uPortal_t* p )
|
||||
{
|
||||
int fcon, bcon;
|
||||
|
||||
if( !p->onnode )
|
||||
return 0; // outside
|
||||
|
||||
fcon = p->nodes[0]->opaque;
|
||||
bcon = p->nodes[1]->opaque;
|
||||
|
||||
// same contents never create a face
|
||||
if( fcon == bcon )
|
||||
return 0;
|
||||
|
||||
if( !fcon )
|
||||
return 1;
|
||||
if( !bcon )
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OutputWinding( idWinding* w, idFile* glview )
|
||||
{
|
||||
static int level = 128;
|
||||
float light;
|
||||
int i;
|
||||
|
||||
glview->WriteFloatString( "%i\n", w->GetNumPoints() );
|
||||
level += 28;
|
||||
light = ( level & 255 ) / 255.0;
|
||||
for( i = 0; i < w->GetNumPoints(); i++ )
|
||||
{
|
||||
glview->WriteFloatString( "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
|
||||
( *w )[i][0],
|
||||
( *w )[i][1],
|
||||
( *w )[i][2],
|
||||
light,
|
||||
light,
|
||||
light );
|
||||
}
|
||||
glview->WriteFloatString( "\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
OutputPortal
|
||||
=============
|
||||
*/
|
||||
void OutputPortal( uPortal_t* p, idFile* glview )
|
||||
{
|
||||
idWinding* w;
|
||||
int sides;
|
||||
|
||||
sides = PortalVisibleSides( p );
|
||||
if( !sides )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
c_glfaces++;
|
||||
|
||||
w = p->winding;
|
||||
|
||||
if( sides == 2 ) // back side
|
||||
{
|
||||
w = w->Reverse();
|
||||
}
|
||||
|
||||
OutputWinding( w, glview );
|
||||
|
||||
if( sides == 2 )
|
||||
{
|
||||
delete w;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGLView_r
|
||||
=============
|
||||
*/
|
||||
void WriteGLView_r( node_t* node, idFile* glview )
|
||||
{
|
||||
uPortal_t* p, *nextp;
|
||||
|
||||
if( node->planenum != PLANENUM_LEAF )
|
||||
{
|
||||
WriteGLView_r( node->children[0], glview );
|
||||
WriteGLView_r( node->children[1], glview );
|
||||
return;
|
||||
}
|
||||
|
||||
// write all the portals
|
||||
for( p = node->portals; p; p = nextp )
|
||||
{
|
||||
if( p->nodes[0] == node )
|
||||
{
|
||||
OutputPortal( p, glview );
|
||||
nextp = p->next[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
nextp = p->next[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGLView
|
||||
=============
|
||||
*/
|
||||
void WriteGLView( tree_t* tree, char* source )
|
||||
{
|
||||
idFile* glview;
|
||||
|
||||
c_glfaces = 0;
|
||||
common->Printf( "Writing %s\n", source );
|
||||
|
||||
glview = fileSystem->OpenExplicitFileWrite( source );
|
||||
if( !glview )
|
||||
{
|
||||
common->Error( "Couldn't open %s", source );
|
||||
}
|
||||
WriteGLView_r( tree->headnode, glview );
|
||||
fileSystem->CloseFile( glview );
|
||||
|
||||
common->Printf( "%5i c_glfaces\n", c_glfaces );
|
||||
}
|
||||
|
113
neo/tools/compilers/dmap/leakfile.cpp
Normal file
113
neo/tools/compilers/dmap/leakfile.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
LEAF FILE GENERATION
|
||||
|
||||
Save out name.line for qe3 to read
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
LeakFile
|
||||
|
||||
Finds the shortest possible chain of portals
|
||||
that leads from the outside leaf to a specifically
|
||||
occupied leaf
|
||||
=============
|
||||
*/
|
||||
void LeakFile( tree_t* tree )
|
||||
{
|
||||
idVec3 mid;
|
||||
FILE* linefile;
|
||||
idStr filename;
|
||||
idStr ospath;
|
||||
node_t* node;
|
||||
int count;
|
||||
|
||||
if( !tree->outside_node.occupied )
|
||||
return;
|
||||
|
||||
common->Printf( "--- LeakFile ---\n" );
|
||||
|
||||
//
|
||||
// write the points to the file
|
||||
//
|
||||
sprintf( filename, "%s.lin", dmapGlobals.mapFileBase );
|
||||
ospath = fileSystem->RelativePathToOSPath( filename );
|
||||
linefile = fopen( ospath, "w" );
|
||||
if( !linefile )
|
||||
{
|
||||
common->Error( "Couldn't open %s\n", filename.c_str() );
|
||||
}
|
||||
|
||||
count = 0;
|
||||
node = &tree->outside_node;
|
||||
while( node->occupied > 1 )
|
||||
{
|
||||
int next;
|
||||
uPortal_t* p, *nextportal = NULL;
|
||||
node_t* nextnode = NULL;
|
||||
int s;
|
||||
|
||||
// find the best portal exit
|
||||
next = node->occupied;
|
||||
for( p = node->portals ; p ; p = p->next[!s] )
|
||||
{
|
||||
s = ( p->nodes[0] == node );
|
||||
if( p->nodes[s]->occupied
|
||||
&& p->nodes[s]->occupied < next )
|
||||
{
|
||||
nextportal = p;
|
||||
nextnode = p->nodes[s];
|
||||
next = nextnode->occupied;
|
||||
}
|
||||
}
|
||||
node = nextnode;
|
||||
mid = nextportal->winding->GetCenter();
|
||||
fprintf( linefile, "%f %f %f\n", mid[0], mid[1], mid[2] );
|
||||
count++;
|
||||
}
|
||||
// add the occupant center
|
||||
node->occupant->mapEntity->epairs.GetVector( "origin", "", mid );
|
||||
|
||||
fprintf( linefile, "%f %f %f\n", mid[0], mid[1], mid[2] );
|
||||
common->Printf( "%5i point linefile\n", count + 1 );
|
||||
|
||||
fclose( linefile );
|
||||
}
|
||||
|
676
neo/tools/compilers/dmap/map.cpp
Normal file
676
neo/tools/compilers/dmap/map.cpp
Normal file
|
@ -0,0 +1,676 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
/*
|
||||
|
||||
After parsing, there will be a list of entities that each has
|
||||
a list of primitives.
|
||||
|
||||
Primitives are either brushes, triangle soups, or model references.
|
||||
|
||||
Curves are tesselated to triangle soups at load time, but model
|
||||
references are
|
||||
Brushes will have
|
||||
|
||||
brushes, each of which has a side definition.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// private declarations
|
||||
//
|
||||
|
||||
#define MAX_BUILD_SIDES 300
|
||||
|
||||
static int entityPrimitive; // to track editor brush numbers
|
||||
static int c_numMapPatches;
|
||||
static int c_areaportals;
|
||||
|
||||
static uEntity_t* uEntity;
|
||||
|
||||
// brushes are parsed into a temporary array of sides,
|
||||
// which will have duplicates removed before the final brush is allocated
|
||||
static uBrush_t* buildBrush;
|
||||
|
||||
|
||||
#define NORMAL_EPSILON 0.00001f
|
||||
#define DIST_EPSILON 0.01f
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
FindFloatPlane
|
||||
===========
|
||||
*/
|
||||
int FindFloatPlane( const idPlane& plane, bool* fixedDegeneracies )
|
||||
{
|
||||
idPlane p = plane;
|
||||
bool fixed = p.FixDegeneracies( DIST_EPSILON );
|
||||
if( fixed && fixedDegeneracies )
|
||||
{
|
||||
*fixedDegeneracies = true;
|
||||
}
|
||||
return dmapGlobals.mapPlanes.FindPlane( p, NORMAL_EPSILON, DIST_EPSILON );
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
SetBrushContents
|
||||
|
||||
The contents on all sides of a brush should be the same
|
||||
Sets contentsShader, contents, opaque
|
||||
===========
|
||||
*/
|
||||
static void SetBrushContents( uBrush_t* b )
|
||||
{
|
||||
int contents, c2;
|
||||
side_t* s;
|
||||
int i;
|
||||
bool mixed;
|
||||
|
||||
s = &b->sides[0];
|
||||
contents = s->material->GetContentFlags();
|
||||
|
||||
b->contentShader = s->material;
|
||||
mixed = false;
|
||||
|
||||
// a brush is only opaque if all sides are opaque
|
||||
b->opaque = true;
|
||||
|
||||
for( i = 1 ; i < b->numsides ; i++, s++ )
|
||||
{
|
||||
s = &b->sides[i];
|
||||
|
||||
if( !s->material )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c2 = s->material->GetContentFlags();
|
||||
if( c2 != contents )
|
||||
{
|
||||
mixed = true;
|
||||
contents |= c2;
|
||||
}
|
||||
|
||||
if( s->material->Coverage() != MC_OPAQUE )
|
||||
{
|
||||
b->opaque = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( contents & CONTENTS_AREAPORTAL )
|
||||
{
|
||||
c_areaportals++;
|
||||
}
|
||||
|
||||
b->contents = contents;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
FreeBuildBrush
|
||||
===============
|
||||
*/
|
||||
static void FreeBuildBrush( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0 ; i < buildBrush->numsides ; i++ )
|
||||
{
|
||||
if( buildBrush->sides[i].winding )
|
||||
{
|
||||
delete buildBrush->sides[i].winding;
|
||||
}
|
||||
}
|
||||
buildBrush->numsides = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
FinishBrush
|
||||
|
||||
Produces a final brush based on the buildBrush->sides array
|
||||
and links it to the current entity
|
||||
===============
|
||||
*/
|
||||
static uBrush_t* FinishBrush( void )
|
||||
{
|
||||
uBrush_t* b;
|
||||
primitive_t* prim;
|
||||
|
||||
// create windings for sides and bounds for brush
|
||||
if( !CreateBrushWindings( buildBrush ) )
|
||||
{
|
||||
// don't keep this brush
|
||||
FreeBuildBrush();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( buildBrush->contents & CONTENTS_AREAPORTAL )
|
||||
{
|
||||
if( dmapGlobals.num_entities != 1 )
|
||||
{
|
||||
common->Printf( "Entity %i, Brush %i: areaportals only allowed in world\n"
|
||||
, dmapGlobals.num_entities - 1, entityPrimitive );
|
||||
FreeBuildBrush();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// keep it
|
||||
b = CopyBrush( buildBrush );
|
||||
|
||||
FreeBuildBrush();
|
||||
|
||||
b->entitynum = dmapGlobals.num_entities - 1;
|
||||
b->brushnum = entityPrimitive;
|
||||
|
||||
b->original = b;
|
||||
|
||||
prim = ( primitive_t* )Mem_Alloc( sizeof( *prim ), TAG_TOOLS );
|
||||
memset( prim, 0, sizeof( *prim ) );
|
||||
prim->next = uEntity->primitives;
|
||||
uEntity->primitives = prim;
|
||||
|
||||
prim->brush = b;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
RemoveDuplicateBrushPlanes
|
||||
|
||||
Returns false if the brush has a mirrored set of planes,
|
||||
meaning it encloses no volume.
|
||||
Also removes planes without any normal
|
||||
=================
|
||||
*/
|
||||
static bool RemoveDuplicateBrushPlanes( uBrush_t* b )
|
||||
{
|
||||
int i, j, k;
|
||||
side_t* sides;
|
||||
|
||||
sides = b->sides;
|
||||
|
||||
for( i = 1 ; i < b->numsides ; i++ )
|
||||
{
|
||||
|
||||
// check for a degenerate plane
|
||||
if( sides[i].planenum == -1 )
|
||||
{
|
||||
common->Printf( "Entity %i, Brush %i: degenerate plane\n"
|
||||
, b->entitynum, b->brushnum );
|
||||
// remove it
|
||||
for( k = i + 1 ; k < b->numsides ; k++ )
|
||||
{
|
||||
sides[k - 1] = sides[k];
|
||||
}
|
||||
b->numsides--;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for duplication and mirroring
|
||||
for( j = 0 ; j < i ; j++ )
|
||||
{
|
||||
if( sides[i].planenum == sides[j].planenum )
|
||||
{
|
||||
common->Printf( "Entity %i, Brush %i: duplicate plane\n"
|
||||
, b->entitynum, b->brushnum );
|
||||
// remove the second duplicate
|
||||
for( k = i + 1 ; k < b->numsides ; k++ )
|
||||
{
|
||||
sides[k - 1] = sides[k];
|
||||
}
|
||||
b->numsides--;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
if( sides[i].planenum == ( sides[j].planenum ^ 1 ) )
|
||||
{
|
||||
// mirror plane, brush is invalid
|
||||
common->Printf( "Entity %i, Brush %i: mirrored plane\n"
|
||||
, b->entitynum, b->brushnum );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
ParseBrush
|
||||
=================
|
||||
*/
|
||||
static void ParseBrush( const idMapBrush* mapBrush, int primitiveNum )
|
||||
{
|
||||
uBrush_t* b;
|
||||
side_t* s;
|
||||
const idMapBrushSide* ms;
|
||||
int i;
|
||||
bool fixedDegeneracies = false;
|
||||
|
||||
buildBrush->entitynum = dmapGlobals.num_entities - 1;
|
||||
buildBrush->brushnum = entityPrimitive;
|
||||
buildBrush->numsides = mapBrush->GetNumSides();
|
||||
for( i = 0 ; i < mapBrush->GetNumSides() ; i++ )
|
||||
{
|
||||
s = &buildBrush->sides[i];
|
||||
ms = mapBrush->GetSide( i );
|
||||
|
||||
memset( s, 0, sizeof( *s ) );
|
||||
s->planenum = FindFloatPlane( ms->GetPlane(), &fixedDegeneracies );
|
||||
s->material = declManager->FindMaterial( ms->GetMaterial() );
|
||||
ms->GetTextureVectors( s->texVec.v );
|
||||
// remove any integral shift, which will help with grouping
|
||||
s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
|
||||
s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
|
||||
}
|
||||
|
||||
// if there are mirrored planes, the entire brush is invalid
|
||||
if( !RemoveDuplicateBrushPlanes( buildBrush ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the content for the entire brush
|
||||
SetBrushContents( buildBrush );
|
||||
|
||||
b = FinishBrush();
|
||||
if( !b )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( fixedDegeneracies && dmapGlobals.verboseentities )
|
||||
{
|
||||
common->Warning( "brush %d has degenerate plane equations", primitiveNum );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
ParseSurface
|
||||
================
|
||||
*/
|
||||
static void ParseSurface( const idMapPatch* patch, const idSurface* surface, const idMaterial* material )
|
||||
{
|
||||
int i;
|
||||
mapTri_t* tri;
|
||||
primitive_t* prim;
|
||||
|
||||
prim = ( primitive_t* )Mem_Alloc( sizeof( *prim ), TAG_TOOLS );
|
||||
memset( prim, 0, sizeof( *prim ) );
|
||||
prim->next = uEntity->primitives;
|
||||
uEntity->primitives = prim;
|
||||
|
||||
for( i = 0; i < surface->GetNumIndexes(); i += 3 )
|
||||
{
|
||||
tri = AllocTri();
|
||||
tri->v[2] = ( *surface )[surface->GetIndexes()[i + 0]];
|
||||
tri->v[1] = ( *surface )[surface->GetIndexes()[i + 2]];
|
||||
tri->v[0] = ( *surface )[surface->GetIndexes()[i + 1]];
|
||||
tri->material = material;
|
||||
tri->next = prim->tris;
|
||||
prim->tris = tri;
|
||||
}
|
||||
|
||||
// set merge groups if needed, to prevent multiple sides from being
|
||||
// merged into a single surface in the case of gui shaders, mirrors, and autosprites
|
||||
if( material->IsDiscrete() )
|
||||
{
|
||||
for( tri = prim->tris ; tri ; tri = tri->next )
|
||||
{
|
||||
tri->mergeGroup = ( void* )patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
ParsePatch
|
||||
================
|
||||
*/
|
||||
static void ParsePatch( const idMapPatch* patch, int primitiveNum )
|
||||
{
|
||||
const idMaterial* mat;
|
||||
|
||||
if( dmapGlobals.noCurves )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
c_numMapPatches++;
|
||||
|
||||
mat = declManager->FindMaterial( patch->GetMaterial() );
|
||||
|
||||
idSurface_Patch* cp = new idSurface_Patch( *patch );
|
||||
|
||||
if( patch->GetExplicitlySubdivided() )
|
||||
{
|
||||
cp->SubdivideExplicit( patch->GetHorzSubdivisions(), patch->GetVertSubdivisions(), true );
|
||||
}
|
||||
else
|
||||
{
|
||||
cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
|
||||
}
|
||||
|
||||
ParseSurface( patch, cp, mat );
|
||||
|
||||
delete cp;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
ProcessMapEntity
|
||||
================
|
||||
*/
|
||||
static bool ProcessMapEntity( idMapEntity* mapEnt )
|
||||
{
|
||||
idMapPrimitive* prim;
|
||||
|
||||
uEntity = &dmapGlobals.uEntities[dmapGlobals.num_entities];
|
||||
memset( uEntity, 0, sizeof( *uEntity ) );
|
||||
uEntity->mapEntity = mapEnt;
|
||||
dmapGlobals.num_entities++;
|
||||
|
||||
for( entityPrimitive = 0; entityPrimitive < mapEnt->GetNumPrimitives(); entityPrimitive++ )
|
||||
{
|
||||
prim = mapEnt->GetPrimitive( entityPrimitive );
|
||||
|
||||
if( prim->GetType() == idMapPrimitive::TYPE_BRUSH )
|
||||
{
|
||||
ParseBrush( static_cast<idMapBrush*>( prim ), entityPrimitive );
|
||||
}
|
||||
else if( prim->GetType() == idMapPrimitive::TYPE_PATCH )
|
||||
{
|
||||
ParsePatch( static_cast<idMapPatch*>( prim ), entityPrimitive );
|
||||
}
|
||||
}
|
||||
|
||||
// never put an origin on the world, even if the editor left one there
|
||||
if( dmapGlobals.num_entities != 1 )
|
||||
{
|
||||
uEntity->mapEntity->epairs.GetVector( "origin", "", uEntity->origin );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
/*
|
||||
==============
|
||||
CreateMapLight
|
||||
|
||||
==============
|
||||
*/
|
||||
static void CreateMapLight( const idMapEntity* mapEnt )
|
||||
{
|
||||
mapLight_t* light;
|
||||
bool dynamic;
|
||||
|
||||
// designers can add the "noPrelight" flag to signal that
|
||||
// the lights will move around, so we don't want
|
||||
// to bother chopping up the surfaces under it or creating
|
||||
// shadow volumes
|
||||
mapEnt->epairs.GetBool( "noPrelight", "0", dynamic );
|
||||
if( dynamic )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
light = new mapLight_t;
|
||||
light->name[0] = '\0';
|
||||
light->shadowTris = NULL;
|
||||
|
||||
// parse parms exactly as the game do
|
||||
// use the game's epair parsing code so
|
||||
// we can use the same renderLight generation
|
||||
gameEdit->ParseSpawnArgsToRenderLight( &mapEnt->epairs, &light->def.parms );
|
||||
|
||||
R_DeriveLightData( &light->def );
|
||||
|
||||
// get the name for naming the shadow surfaces
|
||||
const char* name;
|
||||
|
||||
mapEnt->epairs.GetString( "name", "", &name );
|
||||
|
||||
idStr::Copynz( light->name, name, sizeof( light->name ) );
|
||||
if( !light->name[0] )
|
||||
{
|
||||
common->Error( "Light at (%f,%f,%f) didn't have a name",
|
||||
light->def.parms.origin[0], light->def.parms.origin[1], light->def.parms.origin[2] );
|
||||
}
|
||||
#if 0
|
||||
// use the renderer code to get the bounding planes for the light
|
||||
// based on all the parameters
|
||||
R_RenderLightFrustum( light->parms, light->frustum );
|
||||
light->lightShader = light->parms.shader;
|
||||
#endif
|
||||
|
||||
dmapGlobals.mapLights.Append( light );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CreateMapLights
|
||||
|
||||
==============
|
||||
*/
|
||||
static void CreateMapLights( const idMapFile* dmapFile )
|
||||
{
|
||||
int i;
|
||||
const idMapEntity* mapEnt;
|
||||
const char* value;
|
||||
|
||||
for( i = 0 ; i < dmapFile->GetNumEntities() ; i++ )
|
||||
{
|
||||
mapEnt = dmapFile->GetEntity( i );
|
||||
mapEnt->epairs.GetString( "classname", "", &value );
|
||||
if( !idStr::Icmp( value, "light" ) )
|
||||
{
|
||||
CreateMapLight( mapEnt );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
LoadDMapFile
|
||||
================
|
||||
*/
|
||||
bool LoadDMapFile( const char* filename )
|
||||
{
|
||||
primitive_t* prim;
|
||||
idBounds mapBounds;
|
||||
int brushes, triSurfs;
|
||||
int i;
|
||||
int size;
|
||||
|
||||
common->Printf( "--- LoadDMapFile ---\n" );
|
||||
common->Printf( "loading %s\n", filename );
|
||||
|
||||
// load and parse the map file into canonical form
|
||||
dmapGlobals.dmapFile = new idMapFile();
|
||||
if( !dmapGlobals.dmapFile->Parse( filename ) )
|
||||
{
|
||||
delete dmapGlobals.dmapFile;
|
||||
dmapGlobals.dmapFile = NULL;
|
||||
common->Warning( "Couldn't load map file: '%s'", filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
dmapGlobals.mapPlanes.Clear();
|
||||
dmapGlobals.mapPlanes.SetGranularity( 1024 );
|
||||
|
||||
// process the canonical form into utility form
|
||||
dmapGlobals.num_entities = 0;
|
||||
c_numMapPatches = 0;
|
||||
c_areaportals = 0;
|
||||
|
||||
size = dmapGlobals.dmapFile->GetNumEntities() * sizeof( dmapGlobals.uEntities[0] );
|
||||
dmapGlobals.uEntities = ( uEntity_t* )Mem_Alloc( size, TAG_TOOLS );
|
||||
memset( dmapGlobals.uEntities, 0, size );
|
||||
|
||||
// allocate a very large temporary brush for building
|
||||
// the brushes as they are loaded
|
||||
buildBrush = AllocBrush( MAX_BUILD_SIDES );
|
||||
|
||||
for( i = 0 ; i < dmapGlobals.dmapFile->GetNumEntities() ; i++ )
|
||||
{
|
||||
ProcessMapEntity( dmapGlobals.dmapFile->GetEntity( i ) );
|
||||
}
|
||||
|
||||
CreateMapLights( dmapGlobals.dmapFile );
|
||||
|
||||
brushes = 0;
|
||||
triSurfs = 0;
|
||||
|
||||
mapBounds.Clear();
|
||||
for( prim = dmapGlobals.uEntities[0].primitives ; prim ; prim = prim->next )
|
||||
{
|
||||
if( prim->brush )
|
||||
{
|
||||
brushes++;
|
||||
mapBounds.AddBounds( prim->brush->bounds );
|
||||
}
|
||||
else if( prim->tris )
|
||||
{
|
||||
triSurfs++;
|
||||
}
|
||||
}
|
||||
|
||||
common->Printf( "%5i total world brushes\n", brushes );
|
||||
common->Printf( "%5i total world triSurfs\n", triSurfs );
|
||||
common->Printf( "%5i patches\n", c_numMapPatches );
|
||||
common->Printf( "%5i entities\n", dmapGlobals.num_entities );
|
||||
common->Printf( "%5i planes\n", dmapGlobals.mapPlanes.Num() );
|
||||
common->Printf( "%5i areaportals\n", c_areaportals );
|
||||
common->Printf( "size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", mapBounds[0][0], mapBounds[0][1], mapBounds[0][2],
|
||||
mapBounds[1][0], mapBounds[1][1], mapBounds[1][2] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FreeOptimizeGroupList
|
||||
================
|
||||
*/
|
||||
void FreeOptimizeGroupList( optimizeGroup_t* groups )
|
||||
{
|
||||
optimizeGroup_t* next;
|
||||
|
||||
for( ; groups ; groups = next )
|
||||
{
|
||||
next = groups->nextGroup;
|
||||
FreeTriList( groups->triList );
|
||||
Mem_Free( groups );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FreeDMapFile
|
||||
================
|
||||
*/
|
||||
void FreeDMapFile( void )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
FreeBrush( buildBrush );
|
||||
buildBrush = NULL;
|
||||
|
||||
// free the entities and brushes
|
||||
for( i = 0 ; i < dmapGlobals.num_entities ; i++ )
|
||||
{
|
||||
uEntity_t* ent;
|
||||
primitive_t* prim, *nextPrim;
|
||||
|
||||
ent = &dmapGlobals.uEntities[i];
|
||||
|
||||
FreeTree( ent->tree );
|
||||
|
||||
// free primitives
|
||||
for( prim = ent->primitives ; prim ; prim = nextPrim )
|
||||
{
|
||||
nextPrim = prim->next;
|
||||
if( prim->brush )
|
||||
{
|
||||
FreeBrush( prim->brush );
|
||||
}
|
||||
if( prim->tris )
|
||||
{
|
||||
FreeTriList( prim->tris );
|
||||
}
|
||||
Mem_Free( prim );
|
||||
}
|
||||
|
||||
// free area surfaces
|
||||
if( ent->areas )
|
||||
{
|
||||
for( j = 0 ; j < ent->numAreas ; j++ )
|
||||
{
|
||||
uArea_t* area;
|
||||
|
||||
area = &ent->areas[j];
|
||||
FreeOptimizeGroupList( area->groups );
|
||||
|
||||
}
|
||||
Mem_Free( ent->areas );
|
||||
}
|
||||
}
|
||||
|
||||
Mem_Free( dmapGlobals.uEntities );
|
||||
|
||||
dmapGlobals.num_entities = 0;
|
||||
|
||||
// free the map lights
|
||||
for( i = 0; i < dmapGlobals.mapLights.Num(); i++ )
|
||||
{
|
||||
R_FreeLightDefDerivedData( &dmapGlobals.mapLights[i]->def );
|
||||
}
|
||||
dmapGlobals.mapLights.DeleteContents( true );
|
||||
}
|
2223
neo/tools/compilers/dmap/optimize.cpp
Normal file
2223
neo/tools/compilers/dmap/optimize.cpp
Normal file
File diff suppressed because it is too large
Load diff
708
neo/tools/compilers/dmap/output.cpp
Normal file
708
neo/tools/compilers/dmap/output.cpp
Normal file
|
@ -0,0 +1,708 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
//=================================================================================
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
should we try and snap values very close to 0.5, 0.25, 0.125, etc ?
|
||||
|
||||
do we write out normals, or just a "smooth shade" flag ?
|
||||
resolved : normals. otherwise adjacent facet shaded surfaces get their
|
||||
vertexes merged, and they would have to be split apart before drawing
|
||||
|
||||
do we save out "wings" for shadow silhouette info ?
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
static idFile* procFile;
|
||||
|
||||
#define AREANUM_DIFFERENT -2
|
||||
/*
|
||||
=============
|
||||
PruneNodes_r
|
||||
|
||||
Any nodes that have all children with the same
|
||||
area can be combined into a single leaf node
|
||||
|
||||
Returns the area number of all children, or
|
||||
AREANUM_DIFFERENT if not the same.
|
||||
=============
|
||||
*/
|
||||
int PruneNodes_r( node_t* node )
|
||||
{
|
||||
int a1, a2;
|
||||
|
||||
if( node->planenum == PLANENUM_LEAF )
|
||||
{
|
||||
return node->area;
|
||||
}
|
||||
|
||||
a1 = PruneNodes_r( node->children[0] );
|
||||
a2 = PruneNodes_r( node->children[1] );
|
||||
|
||||
if( a1 != a2 || a1 == AREANUM_DIFFERENT )
|
||||
{
|
||||
return AREANUM_DIFFERENT;
|
||||
}
|
||||
|
||||
// free all the nodes below this point
|
||||
FreeTreePortals_r( node->children[0] );
|
||||
FreeTreePortals_r( node->children[1] );
|
||||
FreeTree_r( node->children[0] );
|
||||
FreeTree_r( node->children[1] );
|
||||
|
||||
// change this node to a leaf
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->area = a1;
|
||||
|
||||
return a1;
|
||||
}
|
||||
|
||||
static void WriteFloat( idFile* f, float v )
|
||||
{
|
||||
if( idMath::Fabs( v - idMath::Rint( v ) ) < 0.001 )
|
||||
{
|
||||
f->WriteFloatString( "%i ", ( int )idMath::Rint( v ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
f->WriteFloatString( "%f ", v );
|
||||
}
|
||||
}
|
||||
|
||||
void Write1DMatrix( idFile* f, int x, float* m )
|
||||
{
|
||||
int i;
|
||||
|
||||
f->WriteFloatString( "( " );
|
||||
|
||||
for( i = 0; i < x; i++ )
|
||||
{
|
||||
WriteFloat( f, m[i] );
|
||||
}
|
||||
|
||||
f->WriteFloatString( ") " );
|
||||
}
|
||||
|
||||
static int CountUniqueShaders( optimizeGroup_t* groups )
|
||||
{
|
||||
optimizeGroup_t* a, *b;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
for( a = groups ; a ; a = a->nextGroup )
|
||||
{
|
||||
if( !a->triList ) // ignore groups with no tris
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for( b = groups ; b != a ; b = b->nextGroup )
|
||||
{
|
||||
if( !b->triList )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( a->material != b->material )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( a->mergeGroup != b->mergeGroup )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( a == b )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
MatchVert
|
||||
==============
|
||||
*/
|
||||
#define XYZ_EPSILON 0.01
|
||||
#define ST_EPSILON 0.001
|
||||
#define COSINE_EPSILON 0.999
|
||||
|
||||
static bool MatchVert( const idDrawVert* a, const idDrawVert* b )
|
||||
{
|
||||
if( idMath::Fabs( a->xyz[0] - b->xyz[0] ) > XYZ_EPSILON )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( idMath::Fabs( a->xyz[1] - b->xyz[1] ) > XYZ_EPSILON )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( idMath::Fabs( a->xyz[2] - b->xyz[2] ) > XYZ_EPSILON )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( idMath::Fabs( a->GetTexCoordS() - b->GetTexCoordS() ) > ST_EPSILON )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( idMath::Fabs( a->GetTexCoordT() - b->GetTexCoordT() ) > ST_EPSILON )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the normal is 0 (smoothed normals), consider it a match
|
||||
if( a->GetNormal() == idVec3( 0, 0, 0 ) || b->GetNormal() == idVec3( 0, 0, 0 ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise do a dot-product cosine check
|
||||
if( a->GetNormal() * b->GetNormal() < COSINE_EPSILON )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
ShareMapTriVerts
|
||||
|
||||
Converts independent triangles to shared vertex triangles
|
||||
====================
|
||||
*/
|
||||
srfTriangles_t* ShareMapTriVerts( const mapTri_t* tris )
|
||||
{
|
||||
const mapTri_t* step;
|
||||
int count;
|
||||
int i, j;
|
||||
int numVerts;
|
||||
int numIndexes;
|
||||
srfTriangles_t* uTri;
|
||||
|
||||
// unique the vertexes
|
||||
count = CountTriList( tris );
|
||||
|
||||
uTri = R_AllocStaticTriSurf();
|
||||
R_AllocStaticTriSurfVerts( uTri, count * 3 );
|
||||
R_AllocStaticTriSurfIndexes( uTri, count * 3 );
|
||||
|
||||
numVerts = 0;
|
||||
numIndexes = 0;
|
||||
|
||||
for( step = tris ; step ; step = step->next )
|
||||
{
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
const idDrawVert* dv;
|
||||
|
||||
dv = &step->v[i];
|
||||
|
||||
// search for a match
|
||||
for( j = 0 ; j < numVerts ; j++ )
|
||||
{
|
||||
if( MatchVert( &uTri->verts[j], dv ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j == numVerts )
|
||||
{
|
||||
numVerts++;
|
||||
uTri->verts[j].xyz = dv->xyz;
|
||||
//uTri->verts[j].SetNormal( dv->normal[0], dv->normal[1], dv->normal[2] );
|
||||
uTri->verts[j].SetNormal( dv->GetNormal() );
|
||||
uTri->verts[j].SetTexCoordS( dv->GetTexCoordS() );
|
||||
uTri->verts[j].SetTexCoordT( dv->GetTexCoordT() );
|
||||
}
|
||||
|
||||
uTri->indexes[numIndexes++] = j;
|
||||
}
|
||||
}
|
||||
|
||||
uTri->numVerts = numVerts;
|
||||
uTri->numIndexes = numIndexes;
|
||||
|
||||
return uTri;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CleanupUTriangles
|
||||
==================
|
||||
*/
|
||||
static void CleanupUTriangles( srfTriangles_t* tri )
|
||||
{
|
||||
// perform cleanup operations
|
||||
|
||||
R_RangeCheckIndexes( tri );
|
||||
R_CreateSilIndexes( tri );
|
||||
// R_RemoveDuplicatedTriangles( tri ); // this may remove valid overlapped transparent triangles
|
||||
R_RemoveDegenerateTriangles( tri );
|
||||
// R_RemoveUnusedVerts( tri );
|
||||
|
||||
R_FreeStaticTriSurfSilIndexes( tri );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
WriteUTriangles
|
||||
|
||||
Writes text verts and indexes to procfile
|
||||
====================
|
||||
*/
|
||||
static void WriteUTriangles( const srfTriangles_t* uTris )
|
||||
{
|
||||
int col;
|
||||
int i;
|
||||
|
||||
// emit this chain
|
||||
procFile->WriteFloatString( "/* numVerts = */ %i /* numIndexes = */ %i\n",
|
||||
uTris->numVerts, uTris->numIndexes );
|
||||
|
||||
// verts
|
||||
col = 0;
|
||||
for( i = 0 ; i < uTris->numVerts ; i++ )
|
||||
{
|
||||
float vec[8];
|
||||
const idDrawVert* dv;
|
||||
|
||||
dv = &uTris->verts[i];
|
||||
|
||||
vec[0] = dv->xyz[0];
|
||||
vec[1] = dv->xyz[1];
|
||||
vec[2] = dv->xyz[2];
|
||||
|
||||
idVec2 st = dv->GetTexCoord();
|
||||
vec[3] = st.x;
|
||||
vec[4] = st.y;
|
||||
|
||||
idVec3 normal = dv->GetNormal();
|
||||
vec[5] = normal.x;
|
||||
vec[6] = normal.y;
|
||||
vec[7] = normal.z;
|
||||
|
||||
Write1DMatrix( procFile, 8, vec );
|
||||
|
||||
if( ++col == 3 )
|
||||
{
|
||||
col = 0;
|
||||
procFile->WriteFloatString( "\n" );
|
||||
}
|
||||
}
|
||||
if( col != 0 )
|
||||
{
|
||||
procFile->WriteFloatString( "\n" );
|
||||
}
|
||||
|
||||
// indexes
|
||||
col = 0;
|
||||
for( i = 0 ; i < uTris->numIndexes ; i++ )
|
||||
{
|
||||
procFile->WriteFloatString( "%i ", uTris->indexes[i] );
|
||||
|
||||
if( ++col == 18 )
|
||||
{
|
||||
col = 0;
|
||||
procFile->WriteFloatString( "\n" );
|
||||
}
|
||||
}
|
||||
if( col != 0 )
|
||||
{
|
||||
procFile->WriteFloatString( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
GroupsAreSurfaceCompatible
|
||||
|
||||
Planes, texcoords, and groupLights can differ,
|
||||
but the material and mergegroup must match
|
||||
=======================
|
||||
*/
|
||||
static bool GroupsAreSurfaceCompatible( const optimizeGroup_t* a, const optimizeGroup_t* b )
|
||||
{
|
||||
if( a->material != b->material )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( a->mergeGroup != b->mergeGroup )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
WriteOutputSurfaces
|
||||
====================
|
||||
*/
|
||||
static void WriteOutputSurfaces( int entityNum, int areaNum )
|
||||
{
|
||||
mapTri_t* ambient, *copy;
|
||||
int surfaceNum;
|
||||
int numSurfaces;
|
||||
idMapEntity* entity;
|
||||
uArea_t* area;
|
||||
optimizeGroup_t* group, *groupStep;
|
||||
int i; // , j;
|
||||
// int col;
|
||||
srfTriangles_t* uTri;
|
||||
// mapTri_t *tri;
|
||||
typedef struct interactionTris_s
|
||||
{
|
||||
struct interactionTris_s* next;
|
||||
mapTri_t* triList;
|
||||
mapLight_t* light;
|
||||
} interactionTris_t;
|
||||
|
||||
interactionTris_t* interactions, *checkInter; //, *nextInter;
|
||||
|
||||
|
||||
area = &dmapGlobals.uEntities[entityNum].areas[areaNum];
|
||||
entity = dmapGlobals.uEntities[entityNum].mapEntity;
|
||||
|
||||
numSurfaces = CountUniqueShaders( area->groups );
|
||||
|
||||
|
||||
if( entityNum == 0 )
|
||||
{
|
||||
procFile->WriteFloatString( "model { /* name = */ \"_area%i\" /* numSurfaces = */ %i\n\n",
|
||||
areaNum, numSurfaces );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* name;
|
||||
|
||||
entity->epairs.GetString( "name", "", &name );
|
||||
if( !name[0] )
|
||||
{
|
||||
common->Error( "Entity %i has surfaces, but no name key", entityNum );
|
||||
}
|
||||
procFile->WriteFloatString( "model { /* name = */ \"%s\" /* numSurfaces = */ %i\n\n",
|
||||
name, numSurfaces );
|
||||
}
|
||||
|
||||
surfaceNum = 0;
|
||||
for( group = area->groups ; group ; group = group->nextGroup )
|
||||
{
|
||||
if( group->surfaceEmited )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// combine all groups compatible with this one
|
||||
// usually several optimizeGroup_t can be combined into a single
|
||||
// surface, even though they couldn't be merged together to save
|
||||
// vertexes because they had different planes, texture coordinates, or lights.
|
||||
// Different mergeGroups will stay in separate surfaces.
|
||||
ambient = NULL;
|
||||
|
||||
// each light that illuminates any of the groups in the surface will
|
||||
// get its own list of indexes out of the original surface
|
||||
interactions = NULL;
|
||||
|
||||
for( groupStep = group ; groupStep ; groupStep = groupStep->nextGroup )
|
||||
{
|
||||
if( groupStep->surfaceEmited )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !GroupsAreSurfaceCompatible( group, groupStep ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy it out to the ambient list
|
||||
copy = CopyTriList( groupStep->triList );
|
||||
ambient = MergeTriLists( ambient, copy );
|
||||
groupStep->surfaceEmited = true;
|
||||
|
||||
// duplicate it into an interaction for each groupLight
|
||||
for( i = 0 ; i < groupStep->numGroupLights ; i++ )
|
||||
{
|
||||
for( checkInter = interactions ; checkInter ; checkInter = checkInter->next )
|
||||
{
|
||||
if( checkInter->light == groupStep->groupLights[i] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !checkInter )
|
||||
{
|
||||
// create a new interaction
|
||||
checkInter = ( interactionTris_t* )Mem_ClearedAlloc( sizeof( *checkInter ), TAG_TOOLS );
|
||||
checkInter->light = groupStep->groupLights[i];
|
||||
checkInter->next = interactions;
|
||||
interactions = checkInter;
|
||||
}
|
||||
copy = CopyTriList( groupStep->triList );
|
||||
checkInter->triList = MergeTriLists( checkInter->triList, copy );
|
||||
}
|
||||
}
|
||||
|
||||
if( !ambient )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( surfaceNum >= numSurfaces )
|
||||
{
|
||||
common->Error( "WriteOutputSurfaces: surfaceNum >= numSurfaces" );
|
||||
}
|
||||
|
||||
procFile->WriteFloatString( "/* surface %i */ { ", surfaceNum );
|
||||
surfaceNum++;
|
||||
procFile->WriteFloatString( "\"%s\" ", ambient->material->GetName() );
|
||||
|
||||
uTri = ShareMapTriVerts( ambient );
|
||||
FreeTriList( ambient );
|
||||
|
||||
CleanupUTriangles( uTri );
|
||||
WriteUTriangles( uTri );
|
||||
R_FreeStaticTriSurf( uTri );
|
||||
|
||||
procFile->WriteFloatString( "}\n\n" );
|
||||
}
|
||||
|
||||
procFile->WriteFloatString( "}\n\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
WriteNode_r
|
||||
|
||||
===============
|
||||
*/
|
||||
static void WriteNode_r( node_t* node )
|
||||
{
|
||||
int child[2];
|
||||
int i;
|
||||
idPlane* plane;
|
||||
|
||||
if( node->planenum == PLANENUM_LEAF )
|
||||
{
|
||||
// we shouldn't get here unless the entire world
|
||||
// was a single leaf
|
||||
procFile->WriteFloatString( "/* node 0 */ ( 0 0 0 0 ) -1 -1\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
for( i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
if( node->children[i]->planenum == PLANENUM_LEAF )
|
||||
{
|
||||
child[i] = -1 - node->children[i]->area;
|
||||
}
|
||||
else
|
||||
{
|
||||
child[i] = node->children[i]->nodeNumber;
|
||||
}
|
||||
}
|
||||
|
||||
plane = &dmapGlobals.mapPlanes[node->planenum];
|
||||
|
||||
procFile->WriteFloatString( "/* node %i */ ", node->nodeNumber );
|
||||
Write1DMatrix( procFile, 4, plane->ToFloatPtr() );
|
||||
procFile->WriteFloatString( "%i %i\n", child[0], child[1] );
|
||||
|
||||
if( child[0] > 0 )
|
||||
{
|
||||
WriteNode_r( node->children[0] );
|
||||
}
|
||||
if( child[1] > 0 )
|
||||
{
|
||||
WriteNode_r( node->children[1] );
|
||||
}
|
||||
}
|
||||
|
||||
static int NumberNodes_r( node_t* node, int nextNumber )
|
||||
{
|
||||
if( node->planenum == PLANENUM_LEAF )
|
||||
{
|
||||
return nextNumber;
|
||||
}
|
||||
node->nodeNumber = nextNumber;
|
||||
nextNumber++;
|
||||
nextNumber = NumberNodes_r( node->children[0], nextNumber );
|
||||
nextNumber = NumberNodes_r( node->children[1], nextNumber );
|
||||
|
||||
return nextNumber;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
WriteOutputNodes
|
||||
====================
|
||||
*/
|
||||
static void WriteOutputNodes( node_t* node )
|
||||
{
|
||||
int numNodes;
|
||||
|
||||
// prune unneeded nodes and count
|
||||
PruneNodes_r( node );
|
||||
numNodes = NumberNodes_r( node, 0 );
|
||||
|
||||
// output
|
||||
procFile->WriteFloatString( "nodes { /* numNodes = */ %i\n\n", numNodes );
|
||||
procFile->WriteFloatString( "/* node format is: ( planeVector ) positiveChild negativeChild */\n" );
|
||||
procFile->WriteFloatString( "/* a child number of 0 is an opaque, solid area */\n" );
|
||||
procFile->WriteFloatString( "/* negative child numbers are areas: (-1-child) */\n" );
|
||||
|
||||
WriteNode_r( node );
|
||||
|
||||
procFile->WriteFloatString( "}\n\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
WriteOutputPortals
|
||||
====================
|
||||
*/
|
||||
static void WriteOutputPortals( uEntity_t* e )
|
||||
{
|
||||
int i, j;
|
||||
interAreaPortal_t* iap;
|
||||
idWinding* w;
|
||||
|
||||
procFile->WriteFloatString( "interAreaPortals { /* numAreas = */ %i /* numIAP = */ %i\n\n",
|
||||
e->numAreas, numInterAreaPortals );
|
||||
procFile->WriteFloatString( "/* interAreaPortal format is: numPoints positiveSideArea negativeSideArea ( point) ... */\n" );
|
||||
for( i = 0 ; i < numInterAreaPortals ; i++ )
|
||||
{
|
||||
iap = &interAreaPortals[i];
|
||||
w = iap->side->winding;
|
||||
procFile->WriteFloatString( "/* iap %i */ %i %i %i ", i, w->GetNumPoints(), iap->area0, iap->area1 );
|
||||
for( j = 0 ; j < w->GetNumPoints() ; j++ )
|
||||
{
|
||||
Write1DMatrix( procFile, 3, ( *w )[j].ToFloatPtr() );
|
||||
}
|
||||
procFile->WriteFloatString( "\n" );
|
||||
}
|
||||
|
||||
procFile->WriteFloatString( "}\n\n" );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
WriteOutputEntity
|
||||
====================
|
||||
*/
|
||||
static void WriteOutputEntity( int entityNum )
|
||||
{
|
||||
int i;
|
||||
uEntity_t* e;
|
||||
|
||||
e = &dmapGlobals.uEntities[entityNum];
|
||||
|
||||
if( entityNum != 0 )
|
||||
{
|
||||
// entities may have enclosed, empty areas that we don't need to write out
|
||||
if( e->numAreas > 1 )
|
||||
{
|
||||
e->numAreas = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0 ; i < e->numAreas ; i++ )
|
||||
{
|
||||
WriteOutputSurfaces( entityNum, i );
|
||||
}
|
||||
|
||||
// we will completely skip the portals and nodes if it is a single area
|
||||
if( entityNum == 0 && e->numAreas > 1 )
|
||||
{
|
||||
// output the area portals
|
||||
WriteOutputPortals( e );
|
||||
|
||||
// output the nodes
|
||||
WriteOutputNodes( e->tree->headnode );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
WriteOutputFile
|
||||
====================
|
||||
*/
|
||||
void WriteOutputFile( void )
|
||||
{
|
||||
int i;
|
||||
uEntity_t* entity;
|
||||
idStr qpath;
|
||||
|
||||
// write the file
|
||||
common->Printf( "----- WriteOutputFile -----\n" );
|
||||
|
||||
sprintf( qpath, "%s." PROC_FILE_EXT, dmapGlobals.mapFileBase );
|
||||
|
||||
common->Printf( "writing %s\n", qpath.c_str() );
|
||||
// _D3XP used fs_cdpath
|
||||
procFile = fileSystem->OpenFileWrite( qpath, "fs_basepath" );
|
||||
if( !procFile )
|
||||
{
|
||||
common->Error( "Error opening %s", qpath.c_str() );
|
||||
}
|
||||
|
||||
procFile->WriteFloatString( "%s\n\n", PROC_FILE_ID );
|
||||
|
||||
// write the entity models and information, writing entities first
|
||||
for( i = dmapGlobals.num_entities - 1 ; i >= 0 ; i-- )
|
||||
{
|
||||
entity = &dmapGlobals.uEntities[i];
|
||||
|
||||
if( !entity->primitives )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
WriteOutputEntity( i );
|
||||
}
|
||||
|
||||
fileSystem->CloseFile( procFile );
|
||||
}
|
1113
neo/tools/compilers/dmap/portals.cpp
Normal file
1113
neo/tools/compilers/dmap/portals.cpp
Normal file
File diff suppressed because it is too large
Load diff
751
neo/tools/compilers/dmap/tritjunction.cpp
Normal file
751
neo/tools/compilers/dmap/tritjunction.cpp
Normal file
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
/*
|
||||
|
||||
T junction fixing never creates more xyz points, but
|
||||
new vertexes will be created when different surfaces
|
||||
cause a fix
|
||||
|
||||
The vertex cleaning accomplishes two goals: removing extranious low order
|
||||
bits to avoid numbers like 1.000001233, and grouping nearby vertexes
|
||||
together. Straight truncation accomplishes the first foal, but two vertexes
|
||||
only a tiny epsilon apart could still be spread to different snap points.
|
||||
To avoid this, we allow the merge test to group points together that
|
||||
snapped to neighboring integer coordinates.
|
||||
|
||||
Snaping verts can drag some triangles backwards or collapse them to points,
|
||||
which will cause them to be removed.
|
||||
|
||||
|
||||
When snapping to ints, a point can move a maximum of sqrt(3)/2 distance
|
||||
Two points that were an epsilon apart can then become sqrt(3) apart
|
||||
|
||||
A case that causes recursive overflow with point to triangle fixing:
|
||||
|
||||
A
|
||||
C D
|
||||
B
|
||||
|
||||
Triangle ABC tests against point D and splits into triangles ADC and DBC
|
||||
Triangle DBC then tests against point A again and splits into ABC and ADB
|
||||
infinite recursive loop
|
||||
|
||||
|
||||
For a given source triangle
|
||||
init the no-check list to hold the three triangle hashVerts
|
||||
|
||||
recursiveFixTriAgainstHash
|
||||
|
||||
recursiveFixTriAgainstHashVert_r
|
||||
if hashVert is on the no-check list
|
||||
exit
|
||||
if the hashVert should split the triangle
|
||||
add to the no-check list
|
||||
recursiveFixTriAgainstHash(a)
|
||||
recursiveFixTriAgainstHash(b)
|
||||
|
||||
*/
|
||||
|
||||
#define SNAP_FRACTIONS 32
|
||||
//#define SNAP_FRACTIONS 8
|
||||
//#define SNAP_FRACTIONS 1
|
||||
|
||||
#define VERTEX_EPSILON ( 1.0 / SNAP_FRACTIONS )
|
||||
|
||||
#define COLINEAR_EPSILON ( 1.8 * VERTEX_EPSILON )
|
||||
|
||||
#define HASH_BINS 16
|
||||
|
||||
typedef struct hashVert_s
|
||||
{
|
||||
struct hashVert_s* next;
|
||||
idVec3 v;
|
||||
int iv[3];
|
||||
} hashVert_t;
|
||||
|
||||
static idBounds hashBounds;
|
||||
static idVec3 hashScale;
|
||||
static hashVert_t* hashVerts[HASH_BINS][HASH_BINS][HASH_BINS];
|
||||
static int numHashVerts, numTotalVerts;
|
||||
static int hashIntMins[3], hashIntScale[3];
|
||||
|
||||
/*
|
||||
===============
|
||||
GetHashVert
|
||||
|
||||
Also modifies the original vert to the snapped value
|
||||
===============
|
||||
*/
|
||||
struct hashVert_s* GetHashVert( idVec3& v )
|
||||
{
|
||||
int iv[3];
|
||||
int block[3];
|
||||
int i;
|
||||
hashVert_t* hv;
|
||||
|
||||
numTotalVerts++;
|
||||
|
||||
// snap the vert to integral values
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
iv[i] = floor( ( v[i] + 0.5 / SNAP_FRACTIONS ) * SNAP_FRACTIONS );
|
||||
block[i] = ( iv[i] - hashIntMins[i] ) / hashIntScale[i];
|
||||
if( block[i] < 0 )
|
||||
{
|
||||
block[i] = 0;
|
||||
}
|
||||
else if( block[i] >= HASH_BINS )
|
||||
{
|
||||
block[i] = HASH_BINS - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// see if a vertex near enough already exists
|
||||
// this could still fail to find a near neighbor right at the hash block boundary
|
||||
for( hv = hashVerts[block[0]][block[1]][block[2]] ; hv ; hv = hv->next )
|
||||
{
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
int d;
|
||||
d = hv->iv[i] - iv[i];
|
||||
if( d < -1 || d > 1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i == 3 )
|
||||
{
|
||||
v = hv->v;
|
||||
return hv;
|
||||
}
|
||||
}
|
||||
|
||||
// create a new one
|
||||
hv = ( hashVert_t* )Mem_Alloc( sizeof( *hv ), TAG_TOOLS );
|
||||
|
||||
hv->next = hashVerts[block[0]][block[1]][block[2]];
|
||||
hashVerts[block[0]][block[1]][block[2]] = hv;
|
||||
|
||||
hv->iv[0] = iv[0];
|
||||
hv->iv[1] = iv[1];
|
||||
hv->iv[2] = iv[2];
|
||||
|
||||
hv->v[0] = ( float )iv[0] / SNAP_FRACTIONS;
|
||||
hv->v[1] = ( float )iv[1] / SNAP_FRACTIONS;
|
||||
hv->v[2] = ( float )iv[2] / SNAP_FRACTIONS;
|
||||
|
||||
v = hv->v;
|
||||
|
||||
numHashVerts++;
|
||||
|
||||
return hv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
HashBlocksForTri
|
||||
|
||||
Returns an inclusive bounding box of hash
|
||||
bins that should hold the triangle
|
||||
==================
|
||||
*/
|
||||
static void HashBlocksForTri( const mapTri_t* tri, int blocks[2][3] )
|
||||
{
|
||||
idBounds bounds;
|
||||
int i;
|
||||
|
||||
bounds.Clear();
|
||||
bounds.AddPoint( tri->v[0].xyz );
|
||||
bounds.AddPoint( tri->v[1].xyz );
|
||||
bounds.AddPoint( tri->v[2].xyz );
|
||||
|
||||
// add a 1.0 slop margin on each side
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
blocks[0][i] = ( bounds[0][i] - 1.0 - hashBounds[0][i] ) / hashScale[i];
|
||||
if( blocks[0][i] < 0 )
|
||||
{
|
||||
blocks[0][i] = 0;
|
||||
}
|
||||
else if( blocks[0][i] >= HASH_BINS )
|
||||
{
|
||||
blocks[0][i] = HASH_BINS - 1;
|
||||
}
|
||||
|
||||
blocks[1][i] = ( bounds[1][i] + 1.0 - hashBounds[0][i] ) / hashScale[i];
|
||||
if( blocks[1][i] < 0 )
|
||||
{
|
||||
blocks[1][i] = 0;
|
||||
}
|
||||
else if( blocks[1][i] >= HASH_BINS )
|
||||
{
|
||||
blocks[1][i] = HASH_BINS - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
HashTriangles
|
||||
|
||||
Removes triangles that are degenerated or flipped backwards
|
||||
=================
|
||||
*/
|
||||
void HashTriangles( optimizeGroup_t* groupList )
|
||||
{
|
||||
mapTri_t* a;
|
||||
int vert;
|
||||
int i;
|
||||
optimizeGroup_t* group;
|
||||
|
||||
// clear the hash tables
|
||||
memset( hashVerts, 0, sizeof( hashVerts ) );
|
||||
|
||||
numHashVerts = 0;
|
||||
numTotalVerts = 0;
|
||||
|
||||
// bound all the triangles to determine the bucket size
|
||||
hashBounds.Clear();
|
||||
for( group = groupList ; group ; group = group->nextGroup )
|
||||
{
|
||||
for( a = group->triList ; a ; a = a->next )
|
||||
{
|
||||
hashBounds.AddPoint( a->v[0].xyz );
|
||||
hashBounds.AddPoint( a->v[1].xyz );
|
||||
hashBounds.AddPoint( a->v[2].xyz );
|
||||
}
|
||||
}
|
||||
|
||||
// spread the bounds so it will never have a zero size
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
hashBounds[0][i] = floor( hashBounds[0][i] - 1 );
|
||||
hashBounds[1][i] = ceil( hashBounds[1][i] + 1 );
|
||||
hashIntMins[i] = hashBounds[0][i] * SNAP_FRACTIONS;
|
||||
|
||||
hashScale[i] = ( hashBounds[1][i] - hashBounds[0][i] ) / HASH_BINS;
|
||||
hashIntScale[i] = hashScale[i] * SNAP_FRACTIONS;
|
||||
if( hashIntScale[i] < 1 )
|
||||
{
|
||||
hashIntScale[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// add all the points to the hash buckets
|
||||
for( group = groupList ; group ; group = group->nextGroup )
|
||||
{
|
||||
// don't create tjunctions against discrete surfaces (blood decals, etc)
|
||||
if( group->material != NULL && group->material->IsDiscrete() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for( a = group->triList ; a ; a = a->next )
|
||||
{
|
||||
for( vert = 0 ; vert < 3 ; vert++ )
|
||||
{
|
||||
a->hashVert[vert] = GetHashVert( a->v[vert].xyz );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
FreeTJunctionHash
|
||||
|
||||
The optimizer may add some more crossing verts
|
||||
after t junction processing
|
||||
=================
|
||||
*/
|
||||
void FreeTJunctionHash( void )
|
||||
{
|
||||
int i, j, k;
|
||||
hashVert_t* hv, *next;
|
||||
|
||||
for( i = 0 ; i < HASH_BINS ; i++ )
|
||||
{
|
||||
for( j = 0 ; j < HASH_BINS ; j++ )
|
||||
{
|
||||
for( k = 0 ; k < HASH_BINS ; k++ )
|
||||
{
|
||||
for( hv = hashVerts[i][j][k] ; hv ; hv = next )
|
||||
{
|
||||
next = hv->next;
|
||||
Mem_Free( hv );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memset( hashVerts, 0, sizeof( hashVerts ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
FixTriangleAgainstHashVert
|
||||
|
||||
Returns a list of two new mapTri if the hashVert is
|
||||
on an edge of the given mapTri, otherwise returns NULL.
|
||||
==================
|
||||
*/
|
||||
static mapTri_t* FixTriangleAgainstHashVert( const mapTri_t* a, const hashVert_t* hv )
|
||||
{
|
||||
int i;
|
||||
const idDrawVert* v1, *v2, *v3;
|
||||
idDrawVert split;
|
||||
idVec3 dir;
|
||||
float len;
|
||||
float frac;
|
||||
mapTri_t* new1, *new2;
|
||||
idVec3 temp;
|
||||
float d, off;
|
||||
const idVec3* v;
|
||||
idPlane plane1, plane2;
|
||||
|
||||
v = &hv->v;
|
||||
|
||||
// if the triangle already has this hashVert as a vert,
|
||||
// it can't be split by it
|
||||
if( a->hashVert[0] == hv || a->hashVert[1] == hv || a->hashVert[2] == hv )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// we probably should find the edge that the vertex is closest to.
|
||||
// it is possible to be < 1 unit away from multiple
|
||||
// edges, but we only want to split by one of them
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
v1 = &a->v[i];
|
||||
v2 = &a->v[( i + 1 ) % 3];
|
||||
v3 = &a->v[( i + 2 ) % 3];
|
||||
dir = v2->xyz - v1->xyz;
|
||||
|
||||
len = dir.Normalize();
|
||||
|
||||
// if it is close to one of the edge vertexes, skip it
|
||||
temp = *v - v1->xyz;
|
||||
d = temp * dir;
|
||||
if( d <= 0 || d >= len )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// make sure it is on the line
|
||||
VectorMA( v1->xyz, d, dir, temp );
|
||||
temp = *v - temp;
|
||||
off = temp.Length();
|
||||
if( off <= -COLINEAR_EPSILON || off >= COLINEAR_EPSILON )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// take the x/y/z from the splitter,
|
||||
// but interpolate everything else from the original tri
|
||||
split.xyz = *v;
|
||||
frac = d / len;
|
||||
|
||||
idVec2 st;
|
||||
st.x = v1->GetTexCoordS() + frac * ( v2->GetTexCoordS() - v1->GetTexCoordS() );
|
||||
st.y = v1->GetTexCoordT() + frac * ( v2->GetTexCoordT() - v1->GetTexCoordT() );
|
||||
split.SetTexCoord( st );
|
||||
idVec3 splitNormal;
|
||||
idVec3 v1Normal = v1->GetNormal();
|
||||
idVec3 v2Normal = v2->GetNormal();
|
||||
splitNormal[0] = v1Normal[0] + frac * ( v2Normal[0] - v1Normal[0] );
|
||||
splitNormal[1] = v1Normal[1] + frac * ( v2Normal[1] - v1Normal[1] );
|
||||
splitNormal[2] = v1Normal[2] + frac * ( v2Normal[2] - v1Normal[2] );
|
||||
splitNormal.Normalize();
|
||||
split.SetNormal( splitNormal );
|
||||
|
||||
// split the tri
|
||||
new1 = CopyMapTri( a );
|
||||
new1->v[( i + 1 ) % 3] = split;
|
||||
new1->hashVert[( i + 1 ) % 3] = hv;
|
||||
new1->next = NULL;
|
||||
|
||||
new2 = CopyMapTri( a );
|
||||
new2->v[i] = split;
|
||||
new2->hashVert[i] = hv;
|
||||
new2->next = new1;
|
||||
|
||||
plane1.FromPoints( new1->hashVert[0]->v, new1->hashVert[1]->v, new1->hashVert[2]->v );
|
||||
plane2.FromPoints( new2->hashVert[0]->v, new2->hashVert[1]->v, new2->hashVert[2]->v );
|
||||
|
||||
d = plane1.ToVec4() * plane2.ToVec4();
|
||||
|
||||
// if the two split triangle's normals don't face the same way,
|
||||
// it should not be split
|
||||
if( d <= 0 )
|
||||
{
|
||||
FreeTriList( new2 );
|
||||
continue;
|
||||
}
|
||||
|
||||
return new2;
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
FixTriangleAgainstHash
|
||||
|
||||
Potentially splits a triangle into a list of triangles based on tjunctions
|
||||
==================
|
||||
*/
|
||||
static mapTri_t* FixTriangleAgainstHash( const mapTri_t* tri )
|
||||
{
|
||||
mapTri_t* fixed;
|
||||
mapTri_t* a;
|
||||
mapTri_t* test, *next;
|
||||
int blocks[2][3];
|
||||
int i, j, k;
|
||||
hashVert_t* hv;
|
||||
|
||||
// if this triangle is degenerate after point snapping,
|
||||
// do nothing (this shouldn't happen, because they should
|
||||
// be removed as they are hashed)
|
||||
if( tri->hashVert[0] == tri->hashVert[1]
|
||||
|| tri->hashVert[0] == tri->hashVert[2]
|
||||
|| tri->hashVert[1] == tri->hashVert[2] )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fixed = CopyMapTri( tri );
|
||||
fixed->next = NULL;
|
||||
|
||||
HashBlocksForTri( tri, blocks );
|
||||
for( i = blocks[0][0] ; i <= blocks[1][0] ; i++ )
|
||||
{
|
||||
for( j = blocks[0][1] ; j <= blocks[1][1] ; j++ )
|
||||
{
|
||||
for( k = blocks[0][2] ; k <= blocks[1][2] ; k++ )
|
||||
{
|
||||
for( hv = hashVerts[i][j][k] ; hv ; hv = hv->next )
|
||||
{
|
||||
// fix all triangles in the list against this point
|
||||
test = fixed;
|
||||
fixed = NULL;
|
||||
for( ; test ; test = next )
|
||||
{
|
||||
next = test->next;
|
||||
a = FixTriangleAgainstHashVert( test, hv );
|
||||
if( a )
|
||||
{
|
||||
// cut into two triangles
|
||||
a->next->next = fixed;
|
||||
fixed = a;
|
||||
FreeTri( test );
|
||||
}
|
||||
else
|
||||
{
|
||||
test->next = fixed;
|
||||
fixed = test;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fixed;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CountGroupListTris
|
||||
==================
|
||||
*/
|
||||
int CountGroupListTris( const optimizeGroup_t* groupList )
|
||||
{
|
||||
int c;
|
||||
|
||||
c = 0;
|
||||
for( ; groupList ; groupList = groupList->nextGroup )
|
||||
{
|
||||
c += CountTriList( groupList->triList );
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
FixAreaGroupsTjunctions
|
||||
==================
|
||||
*/
|
||||
void FixAreaGroupsTjunctions( optimizeGroup_t* groupList )
|
||||
{
|
||||
const mapTri_t* tri;
|
||||
mapTri_t* newList;
|
||||
mapTri_t* fixed;
|
||||
int startCount, endCount;
|
||||
optimizeGroup_t* group;
|
||||
|
||||
if( dmapGlobals.noTJunc )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !groupList )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
startCount = CountGroupListTris( groupList );
|
||||
|
||||
if( dmapGlobals.verbose )
|
||||
{
|
||||
common->Printf( "----- FixAreaGroupsTjunctions -----\n" );
|
||||
common->Printf( "%6i triangles in\n", startCount );
|
||||
}
|
||||
|
||||
HashTriangles( groupList );
|
||||
|
||||
for( group = groupList ; group ; group = group->nextGroup )
|
||||
{
|
||||
// don't touch discrete surfaces
|
||||
if( group->material != NULL && group->material->IsDiscrete() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newList = NULL;
|
||||
for( tri = group->triList ; tri ; tri = tri->next )
|
||||
{
|
||||
fixed = FixTriangleAgainstHash( tri );
|
||||
newList = MergeTriLists( newList, fixed );
|
||||
}
|
||||
FreeTriList( group->triList );
|
||||
group->triList = newList;
|
||||
}
|
||||
|
||||
endCount = CountGroupListTris( groupList );
|
||||
if( dmapGlobals.verbose )
|
||||
{
|
||||
common->Printf( "%6i triangles out\n", endCount );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
FixEntityTjunctions
|
||||
==================
|
||||
*/
|
||||
void FixEntityTjunctions( uEntity_t* e )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0 ; i < e->numAreas ; i++ )
|
||||
{
|
||||
FixAreaGroupsTjunctions( e->areas[i].groups );
|
||||
FreeTJunctionHash();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
FixGlobalTjunctions
|
||||
==================
|
||||
*/
|
||||
void FixGlobalTjunctions( uEntity_t* e )
|
||||
{
|
||||
mapTri_t* a;
|
||||
int vert;
|
||||
int i;
|
||||
optimizeGroup_t* group;
|
||||
int areaNum;
|
||||
|
||||
common->Printf( "----- FixGlobalTjunctions -----\n" );
|
||||
|
||||
// clear the hash tables
|
||||
memset( hashVerts, 0, sizeof( hashVerts ) );
|
||||
|
||||
numHashVerts = 0;
|
||||
numTotalVerts = 0;
|
||||
|
||||
// bound all the triangles to determine the bucket size
|
||||
hashBounds.Clear();
|
||||
for( areaNum = 0 ; areaNum < e->numAreas ; areaNum++ )
|
||||
{
|
||||
for( group = e->areas[areaNum].groups ; group ; group = group->nextGroup )
|
||||
{
|
||||
for( a = group->triList ; a ; a = a->next )
|
||||
{
|
||||
hashBounds.AddPoint( a->v[0].xyz );
|
||||
hashBounds.AddPoint( a->v[1].xyz );
|
||||
hashBounds.AddPoint( a->v[2].xyz );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spread the bounds so it will never have a zero size
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
hashBounds[0][i] = floor( hashBounds[0][i] - 1 );
|
||||
hashBounds[1][i] = ceil( hashBounds[1][i] + 1 );
|
||||
hashIntMins[i] = hashBounds[0][i] * SNAP_FRACTIONS;
|
||||
|
||||
hashScale[i] = ( hashBounds[1][i] - hashBounds[0][i] ) / HASH_BINS;
|
||||
hashIntScale[i] = hashScale[i] * SNAP_FRACTIONS;
|
||||
if( hashIntScale[i] < 1 )
|
||||
{
|
||||
hashIntScale[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// add all the points to the hash buckets
|
||||
for( areaNum = 0 ; areaNum < e->numAreas ; areaNum++ )
|
||||
{
|
||||
for( group = e->areas[areaNum].groups ; group ; group = group->nextGroup )
|
||||
{
|
||||
// don't touch discrete surfaces
|
||||
if( group->material != NULL && group->material->IsDiscrete() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for( a = group->triList ; a ; a = a->next )
|
||||
{
|
||||
for( vert = 0 ; vert < 3 ; vert++ )
|
||||
{
|
||||
a->hashVert[vert] = GetHashVert( a->v[vert].xyz );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add all the func_static model vertexes to the hash buckets
|
||||
// optionally inline some of the func_static models
|
||||
if( dmapGlobals.entityNum == 0 )
|
||||
{
|
||||
for( int eNum = 1 ; eNum < dmapGlobals.num_entities ; eNum++ )
|
||||
{
|
||||
uEntity_t* entity = &dmapGlobals.uEntities[eNum];
|
||||
const char* className = entity->mapEntity->epairs.GetString( "classname" );
|
||||
if( idStr::Icmp( className, "func_static" ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const char* modelName = entity->mapEntity->epairs.GetString( "model" );
|
||||
if( !modelName )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !strstr( modelName, ".lwo" ) && !strstr( modelName, ".ase" ) && !strstr( modelName, ".ma" ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
idRenderModel* model = renderModelManager->FindModel( modelName );
|
||||
|
||||
// common->Printf( "adding T junction verts for %s.\n", entity->mapEntity->epairs.GetString( "name" ) );
|
||||
|
||||
idMat3 axis;
|
||||
// get the rotation matrix in either full form, or single angle form
|
||||
if( !entity->mapEntity->epairs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", axis ) )
|
||||
{
|
||||
float angle = entity->mapEntity->epairs.GetFloat( "angle" );
|
||||
if( angle != 0.0f )
|
||||
{
|
||||
axis = idAngles( 0.0f, angle, 0.0f ).ToMat3();
|
||||
}
|
||||
else
|
||||
{
|
||||
axis.Identity();
|
||||
}
|
||||
}
|
||||
|
||||
idVec3 origin = entity->mapEntity->epairs.GetVector( "origin" );
|
||||
|
||||
for( i = 0 ; i < model->NumSurfaces() ; i++ )
|
||||
{
|
||||
const modelSurface_t* surface = model->Surface( i );
|
||||
const srfTriangles_t* tri = surface->geometry;
|
||||
|
||||
mapTri_t mapTri;
|
||||
memset( &mapTri, 0, sizeof( mapTri ) );
|
||||
mapTri.material = surface->shader;
|
||||
// don't let discretes (autosprites, etc) merge together
|
||||
if( mapTri.material->IsDiscrete() )
|
||||
{
|
||||
mapTri.mergeGroup = ( void* )surface;
|
||||
}
|
||||
for( int j = 0 ; j < tri->numVerts ; j += 3 )
|
||||
{
|
||||
idVec3 v = tri->verts[j].xyz * axis + origin;
|
||||
GetHashVert( v );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// now fix each area
|
||||
for( areaNum = 0 ; areaNum < e->numAreas ; areaNum++ )
|
||||
{
|
||||
for( group = e->areas[areaNum].groups ; group ; group = group->nextGroup )
|
||||
{
|
||||
// don't touch discrete surfaces
|
||||
if( group->material != NULL && group->material->IsDiscrete() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mapTri_t* newList = NULL;
|
||||
for( mapTri_t* tri = group->triList ; tri ; tri = tri->next )
|
||||
{
|
||||
mapTri_t* fixed = FixTriangleAgainstHash( tri );
|
||||
newList = MergeTriLists( newList, fixed );
|
||||
}
|
||||
FreeTriList( group->triList );
|
||||
group->triList = newList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// done
|
||||
FreeTJunctionHash();
|
||||
}
|
428
neo/tools/compilers/dmap/tritools.cpp
Normal file
428
neo/tools/compilers/dmap/tritools.cpp
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
/*
|
||||
|
||||
All triangle list functions should behave reasonably with NULL lists.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
AllocTri
|
||||
===============
|
||||
*/
|
||||
mapTri_t* AllocTri( void )
|
||||
{
|
||||
mapTri_t* tri;
|
||||
|
||||
tri = ( mapTri_t* )Mem_Alloc( sizeof( *tri ), TAG_TOOLS );
|
||||
memset( tri, 0, sizeof( *tri ) );
|
||||
return tri;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
FreeTri
|
||||
===============
|
||||
*/
|
||||
void FreeTri( mapTri_t* tri )
|
||||
{
|
||||
Mem_Free( tri );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
MergeTriLists
|
||||
|
||||
This does not copy any tris, it just relinks them
|
||||
===============
|
||||
*/
|
||||
mapTri_t* MergeTriLists( mapTri_t* a, mapTri_t* b )
|
||||
{
|
||||
mapTri_t** prev;
|
||||
|
||||
prev = &a;
|
||||
while( *prev )
|
||||
{
|
||||
prev = &( *prev )->next;
|
||||
}
|
||||
|
||||
*prev = b;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
FreeTriList
|
||||
===============
|
||||
*/
|
||||
void FreeTriList( mapTri_t* a )
|
||||
{
|
||||
mapTri_t* next;
|
||||
|
||||
for( ; a ; a = next )
|
||||
{
|
||||
next = a->next;
|
||||
Mem_Free( a );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CopyTriList
|
||||
===============
|
||||
*/
|
||||
mapTri_t* CopyTriList( const mapTri_t* a )
|
||||
{
|
||||
mapTri_t* testList;
|
||||
const mapTri_t* tri;
|
||||
|
||||
testList = NULL;
|
||||
for( tri = a ; tri ; tri = tri->next )
|
||||
{
|
||||
mapTri_t* copy;
|
||||
|
||||
copy = CopyMapTri( tri );
|
||||
copy ->next = testList;
|
||||
testList = copy;
|
||||
}
|
||||
|
||||
return testList;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
CountTriList
|
||||
=============
|
||||
*/
|
||||
int CountTriList( const mapTri_t* tri )
|
||||
{
|
||||
int c;
|
||||
|
||||
c = 0;
|
||||
while( tri )
|
||||
{
|
||||
c++;
|
||||
tri = tri->next;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CopyMapTri
|
||||
===============
|
||||
*/
|
||||
mapTri_t* CopyMapTri( const mapTri_t* tri )
|
||||
{
|
||||
mapTri_t* t;
|
||||
|
||||
t = ( mapTri_t* )Mem_Alloc( sizeof( *t ), TAG_TOOLS );
|
||||
*t = *tri;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
MapTriArea
|
||||
===============
|
||||
*/
|
||||
float MapTriArea( const mapTri_t* tri )
|
||||
{
|
||||
return idWinding::TriangleArea( tri->v[0].xyz, tri->v[1].xyz, tri->v[2].xyz );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
RemoveBadTris
|
||||
|
||||
Return a new list with any zero or negative area triangles removed
|
||||
===============
|
||||
*/
|
||||
mapTri_t* RemoveBadTris( const mapTri_t* list )
|
||||
{
|
||||
mapTri_t* newList;
|
||||
mapTri_t* copy;
|
||||
const mapTri_t* tri;
|
||||
|
||||
newList = NULL;
|
||||
|
||||
for( tri = list ; tri ; tri = tri->next )
|
||||
{
|
||||
if( MapTriArea( tri ) > 0 )
|
||||
{
|
||||
copy = CopyMapTri( tri );
|
||||
copy->next = newList;
|
||||
newList = copy;
|
||||
}
|
||||
}
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
BoundTriList
|
||||
================
|
||||
*/
|
||||
void BoundTriList( const mapTri_t* list, idBounds& b )
|
||||
{
|
||||
b.Clear();
|
||||
for( ; list ; list = list->next )
|
||||
{
|
||||
b.AddPoint( list->v[0].xyz );
|
||||
b.AddPoint( list->v[1].xyz );
|
||||
b.AddPoint( list->v[2].xyz );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
DrawTri
|
||||
================
|
||||
*/
|
||||
void DrawTri( const mapTri_t* tri )
|
||||
{
|
||||
idWinding w;
|
||||
|
||||
w.SetNumPoints( 3 );
|
||||
w[0] = tri->v[0].xyz;
|
||||
w[1] = tri->v[1].xyz;
|
||||
w[2] = tri->v[2].xyz;
|
||||
DrawWinding( &w );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FlipTriList
|
||||
|
||||
Swaps the vertex order
|
||||
================
|
||||
*/
|
||||
void FlipTriList( mapTri_t* tris )
|
||||
{
|
||||
mapTri_t* tri;
|
||||
|
||||
for( tri = tris ; tri ; tri = tri->next )
|
||||
{
|
||||
idDrawVert v;
|
||||
const struct hashVert_s* hv;
|
||||
struct optVertex_s* ov;
|
||||
|
||||
v = tri->v[0];
|
||||
tri->v[0] = tri->v[2];
|
||||
tri->v[2] = v;
|
||||
|
||||
hv = tri->hashVert[0];
|
||||
tri->hashVert[0] = tri->hashVert[2];
|
||||
tri->hashVert[2] = hv;
|
||||
|
||||
ov = tri->optVert[0];
|
||||
tri->optVert[0] = tri->optVert[2];
|
||||
tri->optVert[2] = ov;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
WindingForTri
|
||||
================
|
||||
*/
|
||||
idWinding* WindingForTri( const mapTri_t* tri )
|
||||
{
|
||||
idWinding* w;
|
||||
|
||||
w = new idWinding( 3 );
|
||||
w->SetNumPoints( 3 );
|
||||
( *w )[0] = tri->v[0].xyz;
|
||||
( *w )[1] = tri->v[1].xyz;
|
||||
( *w )[2] = tri->v[2].xyz;
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
TriVertsFromOriginal
|
||||
|
||||
Regenerate the texcoords and colors on a fragmented tri from the plane equations
|
||||
================
|
||||
*/
|
||||
void TriVertsFromOriginal( mapTri_t* tri, const mapTri_t* original )
|
||||
{
|
||||
int i, j;
|
||||
float denom;
|
||||
|
||||
denom = idWinding::TriangleArea( original->v[0].xyz, original->v[1].xyz, original->v[2].xyz );
|
||||
if( denom == 0 )
|
||||
{
|
||||
return; // original was degenerate, so it doesn't matter
|
||||
}
|
||||
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
float a, b, c;
|
||||
|
||||
// find the barycentric coordinates
|
||||
a = idWinding::TriangleArea( tri->v[i].xyz, original->v[1].xyz, original->v[2].xyz ) / denom;
|
||||
b = idWinding::TriangleArea( tri->v[i].xyz, original->v[2].xyz, original->v[0].xyz ) / denom;
|
||||
c = idWinding::TriangleArea( tri->v[i].xyz, original->v[0].xyz, original->v[1].xyz ) / denom;
|
||||
|
||||
// regenerate the interpolated values
|
||||
tri->v[i].SetTexCoordS( a * original->v[0].GetTexCoordS()
|
||||
+ b * original->v[1].GetTexCoordS() + c * original->v[2].GetTexCoordS() );
|
||||
tri->v[i].SetTexCoordT( a * original->v[0].GetTexCoordT()
|
||||
+ b * original->v[1].GetTexCoordT() + c * original->v[2].GetTexCoordT() );
|
||||
|
||||
idVec3 normal = tri->v[i].GetNormal();
|
||||
for( j = 0 ; j < 3 ; j++ )
|
||||
{
|
||||
normal[j] = a * original->v[0].GetNormal()[j]
|
||||
+ b * original->v[1].GetNormal()[j] + c * original->v[2].GetNormal()[j];
|
||||
}
|
||||
normal.Normalize();
|
||||
tri->v[i].SetNormal( normal );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
WindingToTriList
|
||||
|
||||
Generates a new list of triangles with proper texcoords from a winding
|
||||
created by clipping the originalTri
|
||||
|
||||
OriginalTri can be NULL if you don't care about texCoords
|
||||
================
|
||||
*/
|
||||
mapTri_t* WindingToTriList( const idWinding* w, const mapTri_t* originalTri )
|
||||
{
|
||||
mapTri_t* tri;
|
||||
mapTri_t* triList;
|
||||
int i, j;
|
||||
const idVec3* vec;
|
||||
|
||||
if( !w )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
triList = NULL;
|
||||
for( i = 2 ; i < w->GetNumPoints() ; i++ )
|
||||
{
|
||||
tri = AllocTri();
|
||||
if( !originalTri )
|
||||
{
|
||||
memset( tri, 0, sizeof( *tri ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
*tri = *originalTri;
|
||||
}
|
||||
tri->next = triList;
|
||||
triList = tri;
|
||||
|
||||
for( j = 0 ; j < 3 ; j++ )
|
||||
{
|
||||
if( j == 0 )
|
||||
{
|
||||
vec = &( ( *w )[0] ).ToVec3();
|
||||
}
|
||||
else if( j == 1 )
|
||||
{
|
||||
vec = &( ( *w )[i - 1] ).ToVec3();
|
||||
}
|
||||
else
|
||||
{
|
||||
vec = &( ( *w )[i] ).ToVec3();
|
||||
}
|
||||
tri->v[j].xyz = *vec;
|
||||
}
|
||||
if( originalTri )
|
||||
{
|
||||
TriVertsFromOriginal( tri, originalTri );
|
||||
}
|
||||
}
|
||||
|
||||
return triList;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
ClipTriList
|
||||
==================
|
||||
*/
|
||||
void ClipTriList( const mapTri_t* list, const idPlane& plane, float epsilon,
|
||||
mapTri_t** front, mapTri_t** back )
|
||||
{
|
||||
const mapTri_t* tri;
|
||||
mapTri_t* newList;
|
||||
idWinding* w, *frontW, *backW;
|
||||
|
||||
*front = NULL;
|
||||
*back = NULL;
|
||||
|
||||
for( tri = list ; tri ; tri = tri->next )
|
||||
{
|
||||
w = WindingForTri( tri );
|
||||
w->Split( plane, epsilon, &frontW, &backW );
|
||||
|
||||
newList = WindingToTriList( frontW, tri );
|
||||
*front = MergeTriLists( *front, newList );
|
||||
|
||||
newList = WindingToTriList( backW, tri );
|
||||
*back = MergeTriLists( *back, newList );
|
||||
|
||||
delete w;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PlaneForTri
|
||||
==================
|
||||
*/
|
||||
void PlaneForTri( const mapTri_t* tri, idPlane& plane )
|
||||
{
|
||||
plane.FromPoints( tri->v[0].xyz, tri->v[1].xyz, tri->v[2].xyz );
|
||||
}
|
753
neo/tools/compilers/dmap/ubrush.cpp
Normal file
753
neo/tools/compilers/dmap/ubrush.cpp
Normal file
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "dmap.h"
|
||||
|
||||
int c_active_brushes;
|
||||
|
||||
int c_nodes;
|
||||
|
||||
// if a brush just barely pokes onto the other side,
|
||||
// let it slide by without chopping
|
||||
#define PLANESIDE_EPSILON 0.001
|
||||
//0.1
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CountBrushList
|
||||
================
|
||||
*/
|
||||
int CountBrushList( uBrush_t* brushes )
|
||||
{
|
||||
int c;
|
||||
|
||||
c = 0;
|
||||
for( ; brushes ; brushes = brushes->next )
|
||||
c++;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int BrushSizeForSides( int numsides )
|
||||
{
|
||||
int c;
|
||||
|
||||
// allocate a structure with a variable number of sides at the end
|
||||
// c = (int)&(((uBrush_t *)0)->sides[numsides]); // bounds checker complains about this
|
||||
c = sizeof( uBrush_t ) + sizeof( side_t ) * ( numsides - 6 );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
AllocBrush
|
||||
================
|
||||
*/
|
||||
uBrush_t* AllocBrush( int numsides )
|
||||
{
|
||||
uBrush_t* bb;
|
||||
int c;
|
||||
|
||||
c = BrushSizeForSides( numsides );
|
||||
|
||||
bb = ( uBrush_t* )Mem_Alloc( c, TAG_TOOLS );
|
||||
memset( bb, 0, c );
|
||||
c_active_brushes++;
|
||||
return bb;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FreeBrush
|
||||
================
|
||||
*/
|
||||
void FreeBrush( uBrush_t* brushes )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0 ; i < brushes->numsides ; i++ )
|
||||
{
|
||||
if( brushes->sides[i].winding )
|
||||
{
|
||||
delete brushes->sides[i].winding;
|
||||
}
|
||||
if( brushes->sides[i].visibleHull )
|
||||
{
|
||||
delete brushes->sides[i].visibleHull;
|
||||
}
|
||||
}
|
||||
Mem_Free( brushes );
|
||||
c_active_brushes--;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FreeBrushList
|
||||
================
|
||||
*/
|
||||
void FreeBrushList( uBrush_t* brushes )
|
||||
{
|
||||
uBrush_t* next;
|
||||
|
||||
for( ; brushes ; brushes = next )
|
||||
{
|
||||
next = brushes->next;
|
||||
|
||||
FreeBrush( brushes );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CopyBrush
|
||||
|
||||
Duplicates the brush, the sides, and the windings
|
||||
==================
|
||||
*/
|
||||
uBrush_t* CopyBrush( uBrush_t* brush )
|
||||
{
|
||||
uBrush_t* newbrush;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
size = BrushSizeForSides( brush->numsides );
|
||||
|
||||
newbrush = AllocBrush( brush->numsides );
|
||||
memcpy( newbrush, brush, size );
|
||||
|
||||
for( i = 0 ; i < brush->numsides ; i++ )
|
||||
{
|
||||
if( brush->sides[i].winding )
|
||||
newbrush->sides[i].winding = brush->sides[i].winding->Copy();
|
||||
}
|
||||
|
||||
return newbrush;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
DrawBrushList
|
||||
================
|
||||
*/
|
||||
void DrawBrushList( uBrush_t* brush )
|
||||
{
|
||||
int i;
|
||||
side_t* s;
|
||||
|
||||
GLS_BeginScene();
|
||||
for( ; brush ; brush = brush->next )
|
||||
{
|
||||
for( i = 0 ; i < brush->numsides ; i++ )
|
||||
{
|
||||
s = &brush->sides[i];
|
||||
if( !s->winding )
|
||||
continue;
|
||||
GLS_Winding( s->winding, 0 );
|
||||
}
|
||||
}
|
||||
GLS_EndScene();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
PrintBrush
|
||||
=============
|
||||
*/
|
||||
void PrintBrush( uBrush_t* brush )
|
||||
{
|
||||
int i;
|
||||
|
||||
common->Printf( "brush: %p\n", brush );
|
||||
for( i = 0; i < brush->numsides ; i++ )
|
||||
{
|
||||
brush->sides[i].winding->Print();
|
||||
common->Printf( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BoundBrush
|
||||
|
||||
Sets the mins/maxs based on the windings
|
||||
returns false if the brush doesn't enclose a valid volume
|
||||
==================
|
||||
*/
|
||||
bool BoundBrush( uBrush_t* brush )
|
||||
{
|
||||
int i, j;
|
||||
idWinding* w;
|
||||
|
||||
brush->bounds.Clear();
|
||||
for( i = 0; i < brush->numsides; i++ )
|
||||
{
|
||||
w = brush->sides[i].winding;
|
||||
if( !w )
|
||||
continue;
|
||||
for( j = 0; j < w->GetNumPoints(); j++ )
|
||||
brush->bounds.AddPoint( ( *w )[j].ToVec3() );
|
||||
}
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
if( brush->bounds[0][i] < MIN_WORLD_COORD || brush->bounds[1][i] > MAX_WORLD_COORD
|
||||
|| brush->bounds[0][i] >= brush->bounds[1][i] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CreateBrushWindings
|
||||
|
||||
makes basewindigs for sides and mins / maxs for the brush
|
||||
returns false if the brush doesn't enclose a valid volume
|
||||
==================
|
||||
*/
|
||||
bool CreateBrushWindings( uBrush_t* brush )
|
||||
{
|
||||
int i, j;
|
||||
idWinding* w;
|
||||
idPlane* plane;
|
||||
side_t* side;
|
||||
|
||||
for( i = 0; i < brush->numsides; i++ )
|
||||
{
|
||||
side = &brush->sides[i];
|
||||
plane = &dmapGlobals.mapPlanes[side->planenum];
|
||||
w = new idWinding( *plane );
|
||||
for( j = 0; j < brush->numsides && w; j++ )
|
||||
{
|
||||
if( i == j )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( brush->sides[j].planenum == ( brush->sides[i].planenum ^ 1 ) )
|
||||
{
|
||||
continue; // back side clipaway
|
||||
}
|
||||
plane = &dmapGlobals.mapPlanes[brush->sides[j].planenum ^ 1];
|
||||
w = w->Clip( *plane, 0 );//CLIP_EPSILON);
|
||||
}
|
||||
if( side->winding )
|
||||
{
|
||||
delete side->winding;
|
||||
}
|
||||
side->winding = w;
|
||||
}
|
||||
|
||||
return BoundBrush( brush );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushFromBounds
|
||||
|
||||
Creates a new axial brush
|
||||
==================
|
||||
*/
|
||||
uBrush_t* BrushFromBounds( const idBounds& bounds )
|
||||
{
|
||||
uBrush_t* b;
|
||||
int i;
|
||||
idPlane plane;
|
||||
|
||||
b = AllocBrush( 6 );
|
||||
b->numsides = 6;
|
||||
for( i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
plane[0] = plane[1] = plane[2] = 0;
|
||||
plane[i] = 1;
|
||||
plane[3] = -bounds[1][i];
|
||||
b->sides[i].planenum = FindFloatPlane( plane );
|
||||
|
||||
plane[i] = -1;
|
||||
plane[3] = bounds[0][i];
|
||||
b->sides[3 + i].planenum = FindFloatPlane( plane );
|
||||
}
|
||||
|
||||
CreateBrushWindings( b );
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushVolume
|
||||
|
||||
==================
|
||||
*/
|
||||
float BrushVolume( uBrush_t* brush )
|
||||
{
|
||||
int i;
|
||||
idWinding* w;
|
||||
idVec3 corner;
|
||||
float d, area, volume;
|
||||
idPlane* plane;
|
||||
|
||||
if( !brush )
|
||||
return 0;
|
||||
|
||||
// grab the first valid point as the corner
|
||||
|
||||
w = NULL;
|
||||
for( i = 0; i < brush->numsides; i++ )
|
||||
{
|
||||
w = brush->sides[i].winding;
|
||||
if( w )
|
||||
break;
|
||||
}
|
||||
if( !w )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
corner = ( *w )[0].ToVec3();
|
||||
|
||||
// make tetrahedrons to all other faces
|
||||
|
||||
volume = 0;
|
||||
for( ; i < brush->numsides; i++ )
|
||||
{
|
||||
w = brush->sides[i].winding;
|
||||
if( !w )
|
||||
continue;
|
||||
plane = &dmapGlobals.mapPlanes[brush->sides[i].planenum];
|
||||
d = -plane->Distance( corner );
|
||||
area = w->GetArea();
|
||||
volume += d * area;
|
||||
}
|
||||
|
||||
volume /= 3;
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
WriteBspBrushMap
|
||||
|
||||
FIXME: use new brush format
|
||||
==================
|
||||
*/
|
||||
void WriteBspBrushMap( const char* name, uBrush_t* list )
|
||||
{
|
||||
idFile* f;
|
||||
side_t* s;
|
||||
int i;
|
||||
idWinding* w;
|
||||
|
||||
common->Printf( "writing %s\n", name );
|
||||
f = fileSystem->OpenFileWrite( name );
|
||||
|
||||
if( !f )
|
||||
{
|
||||
common->Error( "Can't write %s\b", name );
|
||||
}
|
||||
|
||||
f->Printf( "{\n\"classname\" \"worldspawn\"\n" );
|
||||
|
||||
for( ; list ; list = list->next )
|
||||
{
|
||||
f->Printf( "{\n" );
|
||||
for( i = 0, s = list->sides ; i < list->numsides ; i++, s++ )
|
||||
{
|
||||
w = new idWinding( dmapGlobals.mapPlanes[s->planenum] );
|
||||
|
||||
f->Printf( "( %i %i %i ) ", ( int )( *w )[0][0], ( int )( *w )[0][1], ( int )( *w )[0][2] );
|
||||
f->Printf( "( %i %i %i ) ", ( int )( *w )[1][0], ( int )( *w )[1][1], ( int )( *w )[1][2] );
|
||||
f->Printf( "( %i %i %i ) ", ( int )( *w )[2][0], ( int )( *w )[2][1], ( int )( *w )[2][2] );
|
||||
|
||||
f->Printf( "notexture 0 0 0 1 1\n" );
|
||||
delete w;
|
||||
}
|
||||
f->Printf( "}\n" );
|
||||
}
|
||||
f->Printf( "}\n" );
|
||||
|
||||
fileSystem->CloseFile( f );
|
||||
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
|
||||
/*
|
||||
====================
|
||||
FilterBrushIntoTree_r
|
||||
|
||||
====================
|
||||
*/
|
||||
int FilterBrushIntoTree_r( uBrush_t* b, node_t* node )
|
||||
{
|
||||
uBrush_t* front, *back;
|
||||
int c;
|
||||
|
||||
if( !b )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add it to the leaf list
|
||||
if( node->planenum == PLANENUM_LEAF )
|
||||
{
|
||||
b->next = node->brushlist;
|
||||
node->brushlist = b;
|
||||
|
||||
// classify the leaf by the structural brush
|
||||
if( b->opaque )
|
||||
{
|
||||
node->opaque = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// split it by the node plane
|
||||
SplitBrush( b, node->planenum, &front, &back );
|
||||
FreeBrush( b );
|
||||
|
||||
c = 0;
|
||||
c += FilterBrushIntoTree_r( front, node->children[0] );
|
||||
c += FilterBrushIntoTree_r( back, node->children[1] );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
FilterBrushesIntoTree
|
||||
|
||||
Mark the leafs as opaque and areaportals and put brush
|
||||
fragments in each leaf so portal surfaces can be matched
|
||||
to materials
|
||||
=====================
|
||||
*/
|
||||
void FilterBrushesIntoTree( uEntity_t* e )
|
||||
{
|
||||
primitive_t* prim;
|
||||
uBrush_t* b, *newb;
|
||||
int r;
|
||||
int c_unique, c_clusters;
|
||||
|
||||
common->Printf( "----- FilterBrushesIntoTree -----\n" );
|
||||
|
||||
c_unique = 0;
|
||||
c_clusters = 0;
|
||||
for( prim = e->primitives ; prim ; prim = prim->next )
|
||||
{
|
||||
b = prim->brush;
|
||||
if( !b )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
c_unique++;
|
||||
newb = CopyBrush( b );
|
||||
r = FilterBrushIntoTree_r( newb, e->tree->headnode );
|
||||
c_clusters += r;
|
||||
}
|
||||
|
||||
common->Printf( "%5i total brushes\n", c_unique );
|
||||
common->Printf( "%5i cluster references\n", c_clusters );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
AllocTree
|
||||
================
|
||||
*/
|
||||
tree_t* AllocTree( void )
|
||||
{
|
||||
tree_t* tree;
|
||||
|
||||
tree = ( tree_t* )Mem_Alloc( sizeof( *tree ), TAG_TOOLS );
|
||||
memset( tree, 0, sizeof( *tree ) );
|
||||
tree->bounds.Clear();
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
AllocNode
|
||||
================
|
||||
*/
|
||||
node_t* AllocNode( void )
|
||||
{
|
||||
node_t* node;
|
||||
|
||||
node = ( node_t* )Mem_Alloc( sizeof( *node ), TAG_TOOLS );
|
||||
memset( node, 0, sizeof( *node ) );
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushMostlyOnSide
|
||||
|
||||
==================
|
||||
*/
|
||||
int BrushMostlyOnSide( uBrush_t* brush, idPlane& plane )
|
||||
{
|
||||
int i, j;
|
||||
idWinding* w;
|
||||
float d, max;
|
||||
int side;
|
||||
|
||||
max = 0;
|
||||
side = PSIDE_FRONT;
|
||||
for( i = 0; i < brush->numsides; i++ )
|
||||
{
|
||||
w = brush->sides[i].winding;
|
||||
if( !w )
|
||||
continue;
|
||||
for( j = 0; j < w->GetNumPoints(); j++ )
|
||||
{
|
||||
d = plane.Distance( ( *w )[j].ToVec3() );
|
||||
if( d > max )
|
||||
{
|
||||
max = d;
|
||||
side = PSIDE_FRONT;
|
||||
}
|
||||
if( -d > max )
|
||||
{
|
||||
max = -d;
|
||||
side = PSIDE_BACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return side;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SplitBrush
|
||||
|
||||
Generates two new brushes, leaving the original
|
||||
unchanged
|
||||
================
|
||||
*/
|
||||
void SplitBrush( uBrush_t* brush, int planenum, uBrush_t** front, uBrush_t** back )
|
||||
{
|
||||
uBrush_t* b[2];
|
||||
int i, j;
|
||||
idWinding* w, *cw[2], *midwinding;
|
||||
side_t* s, *cs;
|
||||
float d, d_front, d_back;
|
||||
|
||||
*front = *back = NULL;
|
||||
idPlane& plane = dmapGlobals.mapPlanes[planenum];
|
||||
|
||||
// check all points
|
||||
d_front = d_back = 0;
|
||||
for( i = 0; i < brush->numsides; i++ )
|
||||
{
|
||||
w = brush->sides[i].winding;
|
||||
if( !w )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for( j = 0; j < w->GetNumPoints(); j++ )
|
||||
{
|
||||
d = plane.Distance( ( *w )[j].ToVec3() );
|
||||
if( d > 0 && d > d_front )
|
||||
d_front = d;
|
||||
if( d < 0 && d < d_back )
|
||||
d_back = d;
|
||||
}
|
||||
}
|
||||
if( d_front < 0.1 ) // PLANESIDE_EPSILON)
|
||||
{
|
||||
// only on back
|
||||
*back = CopyBrush( brush );
|
||||
return;
|
||||
}
|
||||
if( d_back > -0.1 ) // PLANESIDE_EPSILON)
|
||||
{
|
||||
// only on front
|
||||
*front = CopyBrush( brush );
|
||||
return;
|
||||
}
|
||||
|
||||
// create a new winding from the split plane
|
||||
|
||||
w = new idWinding( plane );
|
||||
for( i = 0; i < brush->numsides && w; i++ )
|
||||
{
|
||||
idPlane& plane2 = dmapGlobals.mapPlanes[brush->sides[i].planenum ^ 1];
|
||||
w = w->Clip( plane2, 0 ); // PLANESIDE_EPSILON);
|
||||
}
|
||||
|
||||
if( !w || w->IsTiny() )
|
||||
{
|
||||
// the brush isn't really split
|
||||
int side;
|
||||
|
||||
side = BrushMostlyOnSide( brush, plane );
|
||||
if( side == PSIDE_FRONT )
|
||||
*front = CopyBrush( brush );
|
||||
if( side == PSIDE_BACK )
|
||||
*back = CopyBrush( brush );
|
||||
return;
|
||||
}
|
||||
|
||||
if( w->IsHuge() )
|
||||
{
|
||||
common->Printf( "WARNING: huge winding\n" );
|
||||
}
|
||||
|
||||
midwinding = w;
|
||||
|
||||
// split it for real
|
||||
|
||||
for( i = 0; i < 2; i++ )
|
||||
{
|
||||
b[i] = AllocBrush( brush->numsides + 1 );
|
||||
memcpy( b[i], brush, sizeof( uBrush_t ) - sizeof( brush->sides ) );
|
||||
b[i]->numsides = 0;
|
||||
b[i]->next = NULL;
|
||||
b[i]->original = brush->original;
|
||||
}
|
||||
|
||||
// split all the current windings
|
||||
|
||||
for( i = 0; i < brush->numsides; i++ )
|
||||
{
|
||||
s = &brush->sides[i];
|
||||
w = s->winding;
|
||||
if( !w )
|
||||
continue;
|
||||
w->Split( plane, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1] );
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
if( !cw[j] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
if ( cw[j]->IsTiny() )
|
||||
{
|
||||
delete cw[j];
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
cs = &b[j]->sides[b[j]->numsides];
|
||||
b[j]->numsides++;
|
||||
*cs = *s;
|
||||
cs->winding = cw[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// see if we have valid polygons on both sides
|
||||
|
||||
for( i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
if( !BoundBrush( b[i] ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( b[i]->numsides < 3 )
|
||||
{
|
||||
FreeBrush( b[i] );
|
||||
b[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !( b[0] && b[1] ) )
|
||||
{
|
||||
if( !b[0] && !b[1] )
|
||||
common->Printf( "split removed brush\n" );
|
||||
else
|
||||
common->Printf( "split not on both sides\n" );
|
||||
if( b[0] )
|
||||
{
|
||||
FreeBrush( b[0] );
|
||||
*front = CopyBrush( brush );
|
||||
}
|
||||
if( b[1] )
|
||||
{
|
||||
FreeBrush( b[1] );
|
||||
*back = CopyBrush( brush );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// add the midwinding to both sides
|
||||
for( i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
cs = &b[i]->sides[b[i]->numsides];
|
||||
b[i]->numsides++;
|
||||
|
||||
cs->planenum = planenum ^ i ^ 1;
|
||||
cs->material = NULL;
|
||||
if( i == 0 )
|
||||
cs->winding = midwinding->Copy();
|
||||
else
|
||||
cs->winding = midwinding;
|
||||
}
|
||||
|
||||
{
|
||||
float v1;
|
||||
int i;
|
||||
|
||||
for( i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
v1 = BrushVolume( b[i] );
|
||||
if( v1 < 1.0 )
|
||||
{
|
||||
FreeBrush( b[i] );
|
||||
b[i] = NULL;
|
||||
// common->Printf ("tiny volume after clip\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*front = b[0];
|
||||
*back = b[1];
|
||||
}
|
1064
neo/tools/compilers/dmap/usurface.cpp
Normal file
1064
neo/tools/compilers/dmap/usurface.cpp
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue