mirror of
https://github.com/id-Software/DOOM-3.git
synced 2026-03-19 16:39:27 +01:00
hello world
This commit is contained in:
1031
neo/tools/compilers/aas/AASBuild.cpp
Normal file
1031
neo/tools/compilers/aas/AASBuild.cpp
Normal file
File diff suppressed because it is too large
Load Diff
499
neo/tools/compilers/aas/AASBuild_file.cpp
Normal file
499
neo/tools/compilers/aas/AASBuild_file.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/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[ INTSIGNBITNOTSET(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;
|
||||
}
|
||||
359
neo/tools/compilers/aas/AASBuild_gravity.cpp
Normal file
359
neo/tools/compilers/aas/AASBuild_gravity.cpp
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/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 );
|
||||
}
|
||||
575
neo/tools/compilers/aas/AASBuild_ledge.cpp
Normal file
575
neo/tools/compilers/aas/AASBuild_ledge.cpp
Normal file
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/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 );
|
||||
}
|
||||
149
neo/tools/compilers/aas/AASBuild_local.h
Normal file
149
neo/tools/compilers/aas/AASBuild_local.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "AASFile.h"
|
||||
#include "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__ */
|
||||
163
neo/tools/compilers/aas/AASBuild_merge.cpp
Normal file
163
neo/tools/compilers/aas/AASBuild_merge.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/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 );
|
||||
}
|
||||
557
neo/tools/compilers/aas/AASCluster.cpp
Normal file
557
neo/tools/compilers/aas/AASCluster.cpp
Normal file
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASFile.h"
|
||||
#include "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;
|
||||
}
|
||||
62
neo/tools/compilers/aas/AASCluster.h
Normal file
62
neo/tools/compilers/aas/AASCluster.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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__ */
|
||||
1314
neo/tools/compilers/aas/AASFile.cpp
Normal file
1314
neo/tools/compilers/aas/AASFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
351
neo/tools/compilers/aas/AASFile.h
Normal file
351
neo/tools/compilers/aas/AASFile.h
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 __AASFILE_H__
|
||||
#define __AASFILE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
AAS File
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define AAS_FILEID "DewmAAS"
|
||||
#define AAS_FILEVERSION "1.07"
|
||||
|
||||
// travel flags
|
||||
#define TFL_INVALID BIT(0) // not valid
|
||||
#define TFL_WALK BIT(1) // walking
|
||||
#define TFL_CROUCH BIT(2) // crouching
|
||||
#define TFL_WALKOFFLEDGE BIT(3) // walking of a ledge
|
||||
#define TFL_BARRIERJUMP BIT(4) // jumping onto a barrier
|
||||
#define TFL_JUMP BIT(5) // jumping
|
||||
#define TFL_LADDER BIT(6) // climbing a ladder
|
||||
#define TFL_SWIM BIT(7) // swimming
|
||||
#define TFL_WATERJUMP BIT(8) // jump out of the water
|
||||
#define TFL_TELEPORT BIT(9) // teleportation
|
||||
#define TFL_ELEVATOR BIT(10) // travel by elevator
|
||||
#define TFL_FLY BIT(11) // fly
|
||||
#define TFL_SPECIAL BIT(12) // special
|
||||
#define TFL_WATER BIT(21) // travel through water
|
||||
#define TFL_AIR BIT(22) // travel through air
|
||||
|
||||
// face flags
|
||||
#define FACE_SOLID BIT(0) // solid at the other side
|
||||
#define FACE_LADDER BIT(1) // ladder surface
|
||||
#define FACE_FLOOR BIT(2) // standing on floor when on this face
|
||||
#define FACE_LIQUID BIT(3) // face seperating two areas with liquid
|
||||
#define FACE_LIQUIDSURFACE BIT(4) // face seperating liquid and air
|
||||
|
||||
// area flags
|
||||
#define AREA_FLOOR BIT(0) // AI can stand on the floor in this area
|
||||
#define AREA_GAP BIT(1) // area has a gap
|
||||
#define AREA_LEDGE BIT(2) // if entered the AI bbox partly floats above a ledge
|
||||
#define AREA_LADDER BIT(3) // area contains one or more ladder faces
|
||||
#define AREA_LIQUID BIT(4) // area contains a liquid
|
||||
#define AREA_CROUCH BIT(5) // AI cannot walk but can only crouch in this area
|
||||
#define AREA_REACHABLE_WALK BIT(6) // area is reachable by walking or swimming
|
||||
#define AREA_REACHABLE_FLY BIT(7) // area is reachable by flying
|
||||
|
||||
// area contents flags
|
||||
#define AREACONTENTS_SOLID BIT(0) // solid, not a valid area
|
||||
#define AREACONTENTS_WATER BIT(1) // area contains water
|
||||
#define AREACONTENTS_CLUSTERPORTAL BIT(2) // area is a cluster portal
|
||||
#define AREACONTENTS_OBSTACLE BIT(3) // area contains (part of) a dynamic obstacle
|
||||
#define AREACONTENTS_TELEPORTER BIT(4) // area contains (part of) a teleporter trigger
|
||||
|
||||
// bits for different bboxes
|
||||
#define AREACONTENTS_BBOX_BIT 24
|
||||
|
||||
#define MAX_REACH_PER_AREA 256
|
||||
#define MAX_AAS_TREE_DEPTH 128
|
||||
|
||||
#define MAX_AAS_BOUNDING_BOXES 4
|
||||
|
||||
// reachability to another area
|
||||
class idReachability {
|
||||
public:
|
||||
int travelType; // type of travel required to get to the area
|
||||
short toAreaNum; // number of the reachable area
|
||||
short fromAreaNum; // number of area the reachability starts
|
||||
idVec3 start; // start point of inter area movement
|
||||
idVec3 end; // end point of inter area movement
|
||||
int edgeNum; // edge crossed by this reachability
|
||||
unsigned short travelTime; // travel time of the inter area movement
|
||||
byte number; // reachability number within the fromAreaNum (must be < 256)
|
||||
byte disableCount; // number of times this reachability has been disabled
|
||||
idReachability * next; // next reachability in list
|
||||
idReachability * rev_next; // next reachability in reversed list
|
||||
unsigned short * areaTravelTimes; // travel times within the fromAreaNum from reachabilities that lead towards this area
|
||||
public:
|
||||
void CopyBase( idReachability &reach );
|
||||
};
|
||||
|
||||
class idReachability_Walk : public idReachability {
|
||||
};
|
||||
|
||||
class idReachability_BarrierJump : public idReachability {
|
||||
};
|
||||
|
||||
class idReachability_WaterJump : public idReachability {
|
||||
};
|
||||
|
||||
class idReachability_WalkOffLedge : public idReachability {
|
||||
};
|
||||
|
||||
class idReachability_Swim : public idReachability {
|
||||
};
|
||||
|
||||
class idReachability_Fly : public idReachability {
|
||||
};
|
||||
|
||||
class idReachability_Special : public idReachability {
|
||||
public:
|
||||
idDict dict;
|
||||
};
|
||||
|
||||
// index
|
||||
typedef int aasIndex_t;
|
||||
|
||||
// vertex
|
||||
typedef idVec3 aasVertex_t;
|
||||
|
||||
// edge
|
||||
typedef struct aasEdge_s {
|
||||
int vertexNum[2]; // numbers of the vertexes of this edge
|
||||
} aasEdge_t;
|
||||
|
||||
// area boundary face
|
||||
typedef struct aasFace_s {
|
||||
unsigned short planeNum; // number of the plane this face is on
|
||||
unsigned short flags; // face flags
|
||||
int numEdges; // number of edges in the boundary of the face
|
||||
int firstEdge; // first edge in the edge index
|
||||
short areas[2]; // area at the front and back of this face
|
||||
} aasFace_t;
|
||||
|
||||
// area with a boundary of faces
|
||||
typedef struct aasArea_s {
|
||||
int numFaces; // number of faces used for the boundary of the area
|
||||
int firstFace; // first face in the face index used for the boundary of the area
|
||||
idBounds bounds; // bounds of the area
|
||||
idVec3 center; // center of the area an AI can move towards
|
||||
unsigned short flags; // several area flags
|
||||
unsigned short contents; // contents of the area
|
||||
short cluster; // cluster the area belongs to, if negative it's a portal
|
||||
short clusterAreaNum; // number of the area in the cluster
|
||||
int travelFlags; // travel flags for traveling through this area
|
||||
idReachability * reach; // reachabilities that start from this area
|
||||
idReachability * rev_reach; // reachabilities that lead to this area
|
||||
} aasArea_t;
|
||||
|
||||
// nodes of the bsp tree
|
||||
typedef struct aasNode_s {
|
||||
unsigned short planeNum; // number of the plane that splits the subspace at this node
|
||||
int children[2]; // child nodes, zero is solid, negative is -(area number)
|
||||
} aasNode_t;
|
||||
|
||||
// cluster portal
|
||||
typedef struct aasPortal_s {
|
||||
short areaNum; // number of the area that is the actual portal
|
||||
short clusters[2]; // number of cluster at the front and back of the portal
|
||||
short clusterAreaNum[2]; // number of this portal area in the front and back cluster
|
||||
unsigned short maxAreaTravelTime; // maximum travel time through the portal area
|
||||
} aasPortal_t;
|
||||
|
||||
// cluster
|
||||
typedef struct aasCluster_s {
|
||||
int numAreas; // number of areas in the cluster
|
||||
int numReachableAreas; // number of areas with reachabilities
|
||||
int numPortals; // number of cluster portals
|
||||
int firstPortal; // first cluster portal in the index
|
||||
} aasCluster_t;
|
||||
|
||||
// trace through the world
|
||||
typedef struct aasTrace_s {
|
||||
// parameters
|
||||
int flags; // areas with these flags block the trace
|
||||
int travelFlags; // areas with these travel flags block the trace
|
||||
int maxAreas; // size of the 'areas' array
|
||||
int getOutOfSolid; // trace out of solid if the trace starts in solid
|
||||
// output
|
||||
float fraction; // fraction of trace completed
|
||||
idVec3 endpos; // end position of trace
|
||||
int planeNum; // plane hit
|
||||
int lastAreaNum; // number of last area the trace went through
|
||||
int blockingAreaNum; // area that could not be entered
|
||||
int numAreas; // number of areas the trace went through
|
||||
int * areas; // array to store areas the trace went through
|
||||
idVec3 * points; // points where the trace entered each new area
|
||||
aasTrace_s( void ) { areas = NULL; points = NULL; getOutOfSolid = false; flags = travelFlags = maxAreas = 0; }
|
||||
} aasTrace_t;
|
||||
|
||||
// settings
|
||||
class idAASSettings {
|
||||
public:
|
||||
// collision settings
|
||||
int numBoundingBoxes;
|
||||
idBounds boundingBoxes[MAX_AAS_BOUNDING_BOXES];
|
||||
bool usePatches;
|
||||
bool writeBrushMap;
|
||||
bool playerFlood;
|
||||
bool noOptimize;
|
||||
bool allowSwimReachabilities;
|
||||
bool allowFlyReachabilities;
|
||||
idStr fileExtension;
|
||||
// physics settings
|
||||
idVec3 gravity;
|
||||
idVec3 gravityDir;
|
||||
idVec3 invGravityDir;
|
||||
float gravityValue;
|
||||
float maxStepHeight;
|
||||
float maxBarrierHeight;
|
||||
float maxWaterJumpHeight;
|
||||
float maxFallHeight;
|
||||
float minFloorCos;
|
||||
// fixed travel times
|
||||
int tt_barrierJump;
|
||||
int tt_startCrouching;
|
||||
int tt_waterJump;
|
||||
int tt_startWalkOffLedge;
|
||||
|
||||
public:
|
||||
idAASSettings( void );
|
||||
|
||||
bool FromFile( const idStr &fileName );
|
||||
bool FromParser( idLexer &src );
|
||||
bool FromDict( const char *name, const idDict *dict );
|
||||
bool WriteToFile( idFile *fp ) const;
|
||||
bool ValidForBounds( const idBounds &bounds ) const;
|
||||
bool ValidEntity( const char *classname ) const;
|
||||
|
||||
private:
|
||||
bool ParseBool( idLexer &src, bool &b );
|
||||
bool ParseInt( idLexer &src, int &i );
|
||||
bool ParseFloat( idLexer &src, float &f );
|
||||
bool ParseVector( idLexer &src, idVec3 &vec );
|
||||
bool ParseBBoxes( idLexer &src );
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
||||
- when a node child is a solid leaf the node child number is zero
|
||||
- two adjacent areas (sharing a plane at opposite sides) share a face
|
||||
this face is a portal between the areas
|
||||
- when an area uses a face from the faceindex with a positive index
|
||||
then the face plane normal points into the area
|
||||
- the face edges are stored counter clockwise using the edgeindex
|
||||
- two adjacent convex areas (sharing a face) only share One face
|
||||
this is a simple result of the areas being convex
|
||||
- the areas can't have a mixture of ground and gap faces
|
||||
other mixtures of faces in one area are allowed
|
||||
- areas with the AREACONTENTS_CLUSTERPORTAL in the settings have
|
||||
the cluster number set to the negative portal number
|
||||
- edge zero is a dummy
|
||||
- face zero is a dummy
|
||||
- area zero is a dummy
|
||||
- node zero is a dummy
|
||||
- portal zero is a dummy
|
||||
- cluster zero is a dummy
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class idAASFile {
|
||||
public:
|
||||
virtual ~idAASFile( void ) {}
|
||||
|
||||
const char * GetName( void ) const { return name.c_str(); }
|
||||
unsigned int GetCRC( void ) const { return crc; }
|
||||
|
||||
int GetNumPlanes( void ) const { return planeList.Num(); }
|
||||
const idPlane & GetPlane( int index ) const { return planeList[index]; }
|
||||
int GetNumVertices( void ) const { return vertices.Num(); }
|
||||
const aasVertex_t & GetVertex( int index ) const { return vertices[index]; }
|
||||
int GetNumEdges( void ) const { return edges.Num(); }
|
||||
const aasEdge_t & GetEdge( int index ) const { return edges[index]; }
|
||||
int GetNumEdgeIndexes( void ) const { return edgeIndex.Num(); }
|
||||
const aasIndex_t & GetEdgeIndex( int index ) const { return edgeIndex[index]; }
|
||||
int GetNumFaces( void ) const { return faces.Num(); }
|
||||
const aasFace_t & GetFace( int index ) const { return faces[index]; }
|
||||
int GetNumFaceIndexes( void ) const { return faceIndex.Num(); }
|
||||
const aasIndex_t & GetFaceIndex( int index ) const { return faceIndex[index]; }
|
||||
int GetNumAreas( void ) const { return areas.Num(); }
|
||||
const aasArea_t & GetArea( int index ) { return areas[index]; }
|
||||
int GetNumNodes( void ) const { return nodes.Num(); }
|
||||
const aasNode_t & GetNode( int index ) const { return nodes[index]; }
|
||||
int GetNumPortals( void ) const { return portals.Num(); }
|
||||
const aasPortal_t & GetPortal( int index ) { return portals[index]; }
|
||||
int GetNumPortalIndexes( void ) const { return portalIndex.Num(); }
|
||||
const aasIndex_t & GetPortalIndex( int index ) const { return portalIndex[index]; }
|
||||
int GetNumClusters( void ) const { return clusters.Num(); }
|
||||
const aasCluster_t & GetCluster( int index ) const { return clusters[index]; }
|
||||
|
||||
const idAASSettings & GetSettings( void ) const { return settings; }
|
||||
|
||||
void SetPortalMaxTravelTime( int index, int time ) { portals[index].maxAreaTravelTime = time; }
|
||||
void SetAreaTravelFlag( int index, int flag ) { areas[index].travelFlags |= flag; }
|
||||
void RemoveAreaTravelFlag( int index, int flag ) { areas[index].travelFlags &= ~flag; }
|
||||
|
||||
virtual idVec3 EdgeCenter( int edgeNum ) const = 0;
|
||||
virtual idVec3 FaceCenter( int faceNum ) const = 0;
|
||||
virtual idVec3 AreaCenter( int areaNum ) const = 0;
|
||||
|
||||
virtual idBounds EdgeBounds( int edgeNum ) const = 0;
|
||||
virtual idBounds FaceBounds( int faceNum ) const = 0;
|
||||
virtual idBounds AreaBounds( int areaNum ) const = 0;
|
||||
|
||||
virtual int PointAreaNum( const idVec3 &origin ) const = 0;
|
||||
virtual int PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const = 0;
|
||||
virtual int BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const = 0;
|
||||
virtual void PushPointIntoAreaNum( int areaNum, idVec3 &point ) const = 0;
|
||||
virtual bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const = 0;
|
||||
virtual void PrintInfo( void ) const = 0;
|
||||
|
||||
protected:
|
||||
idStr name;
|
||||
unsigned int crc;
|
||||
|
||||
idPlaneSet planeList;
|
||||
idList<aasVertex_t> vertices;
|
||||
idList<aasEdge_t> edges;
|
||||
idList<aasIndex_t> edgeIndex;
|
||||
idList<aasFace_t> faces;
|
||||
idList<aasIndex_t> faceIndex;
|
||||
idList<aasArea_t> areas;
|
||||
idList<aasNode_t> nodes;
|
||||
idList<aasPortal_t> portals;
|
||||
idList<aasIndex_t> portalIndex;
|
||||
idList<aasCluster_t> clusters;
|
||||
idAASSettings settings;
|
||||
};
|
||||
|
||||
#endif /* !__AASFILE_H__ */
|
||||
76
neo/tools/compilers/aas/AASFileManager.cpp
Normal file
76
neo/tools/compilers/aas/AASFileManager.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASFile.h"
|
||||
#include "AASFile_local.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
AAS File Manager
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idAASFileManagerLocal : public idAASFileManager {
|
||||
public:
|
||||
virtual ~idAASFileManagerLocal( void ) {}
|
||||
|
||||
virtual idAASFile * LoadAAS( const char *fileName, unsigned int mapFileCRC );
|
||||
virtual void FreeAAS( idAASFile *file );
|
||||
};
|
||||
|
||||
idAASFileManagerLocal AASFileManagerLocal;
|
||||
idAASFileManager * AASFileManager = &AASFileManagerLocal;
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileManagerLocal::LoadAAS
|
||||
================
|
||||
*/
|
||||
idAASFile *idAASFileManagerLocal::LoadAAS( const char *fileName, unsigned int mapFileCRC ) {
|
||||
idAASFileLocal *file = new idAASFileLocal();
|
||||
if ( !file->Load( fileName, mapFileCRC ) ) {
|
||||
delete file;
|
||||
return NULL;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileManagerLocal::FreeAAS
|
||||
================
|
||||
*/
|
||||
void idAASFileManagerLocal::FreeAAS( idAASFile *file ) {
|
||||
delete file;
|
||||
}
|
||||
50
neo/tools/compilers/aas/AASFileManager.h
Normal file
50
neo/tools/compilers/aas/AASFileManager.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 __AASFILEMANAGER_H__
|
||||
#define __AASFILEMANAGER_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
AAS File Manager
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idAASFileManager {
|
||||
public:
|
||||
virtual ~idAASFileManager( void ) {}
|
||||
|
||||
virtual idAASFile * LoadAAS( const char *fileName, unsigned int mapFileCRC ) = 0;
|
||||
virtual void FreeAAS( idAASFile *file ) = 0;
|
||||
};
|
||||
|
||||
extern idAASFileManager * AASFileManager;
|
||||
|
||||
#endif /* !__AASFILEMANAGER_H__ */
|
||||
99
neo/tools/compilers/aas/AASFile_local.h
Normal file
99
neo/tools/compilers/aas/AASFile_local.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 __AASFILELOCAL_H__
|
||||
#define __AASFILELOCAL_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
AAS File Local
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idAASFileLocal : public idAASFile {
|
||||
friend class idAASBuild;
|
||||
friend class idAASReach;
|
||||
friend class idAASCluster;
|
||||
public:
|
||||
idAASFileLocal( void );
|
||||
virtual ~idAASFileLocal( void );
|
||||
|
||||
public:
|
||||
virtual idVec3 EdgeCenter( int edgeNum ) const;
|
||||
virtual idVec3 FaceCenter( int faceNum ) const;
|
||||
virtual idVec3 AreaCenter( int areaNum ) const;
|
||||
|
||||
virtual idBounds EdgeBounds( int edgeNum ) const;
|
||||
virtual idBounds FaceBounds( int faceNum ) const;
|
||||
virtual idBounds AreaBounds( int areaNum ) const;
|
||||
|
||||
virtual int PointAreaNum( const idVec3 &origin ) const;
|
||||
virtual int PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const;
|
||||
virtual int BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const;
|
||||
virtual void PushPointIntoAreaNum( int areaNum, idVec3 &point ) const;
|
||||
virtual bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const;
|
||||
virtual void PrintInfo( void ) const;
|
||||
|
||||
public:
|
||||
bool Load( const idStr &fileName, unsigned int mapFileCRC );
|
||||
bool Write( const idStr &fileName, unsigned int mapFileCRC );
|
||||
|
||||
int MemorySize( void ) const;
|
||||
void ReportRoutingEfficiency( void ) const;
|
||||
void Optimize( void );
|
||||
void LinkReversedReachability( void );
|
||||
void FinishAreas( void );
|
||||
|
||||
void Clear( void );
|
||||
void DeleteReachabilities( void );
|
||||
void DeleteClusters( void );
|
||||
|
||||
private:
|
||||
bool ParseIndex( idLexer &src, idList<aasIndex_t> &indexes );
|
||||
bool ParsePlanes( idLexer &src );
|
||||
bool ParseVertices( idLexer &src );
|
||||
bool ParseEdges( idLexer &src );
|
||||
bool ParseFaces( idLexer &src );
|
||||
bool ParseReachabilities( idLexer &src, int areaNum );
|
||||
bool ParseAreas( idLexer &src );
|
||||
bool ParseNodes( idLexer &src );
|
||||
bool ParsePortals( idLexer &src );
|
||||
bool ParseClusters( idLexer &src );
|
||||
|
||||
private:
|
||||
int BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const;
|
||||
void MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const;
|
||||
int MaxTreeDepth( void ) const;
|
||||
int AreaContentsTravelFlags( int areaNum ) const;
|
||||
idVec3 AreaReachableGoal( int areaNum ) const;
|
||||
int NumReachabilities( void ) const;
|
||||
};
|
||||
|
||||
#endif /* !__AASFILELOCAL_H__ */
|
||||
154
neo/tools/compilers/aas/AASFile_optimize.cpp
Normal file
154
neo/tools/compilers/aas/AASFile_optimize.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASFile.h"
|
||||
#include "AASFile_local.h"
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// optimize file
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::Optimize
|
||||
================
|
||||
*/
|
||||
void idAASFileLocal::Optimize( void ) {
|
||||
int i, j, k, faceNum, edgeNum, areaFirstFace, faceFirstEdge;
|
||||
aasArea_t *area;
|
||||
aasFace_t *face;
|
||||
aasEdge_t *edge;
|
||||
idReachability *reach;
|
||||
idList<int> vertexRemap;
|
||||
idList<int> edgeRemap;
|
||||
idList<int> faceRemap;
|
||||
idList<aasVertex_t> newVertices;
|
||||
idList<aasEdge_t> newEdges;
|
||||
idList<aasIndex_t> newEdgeIndex;
|
||||
idList<aasFace_t> newFaces;
|
||||
idList<aasIndex_t> newFaceIndex;
|
||||
|
||||
vertexRemap.AssureSize( vertices.Num(), -1 );
|
||||
edgeRemap.AssureSize( edges.Num(), 0 );
|
||||
faceRemap.AssureSize( faces.Num(), 0 );
|
||||
|
||||
newVertices.Resize( vertices.Num() );
|
||||
newEdges.Resize( edges.Num() );
|
||||
newEdges.SetNum( 1, false );
|
||||
newEdgeIndex.Resize( edgeIndex.Num() );
|
||||
newFaces.Resize( faces.Num() );
|
||||
newFaces.SetNum( 1, false );
|
||||
newFaceIndex.Resize( faceIndex.Num() );
|
||||
|
||||
for ( i = 0; i < areas.Num(); i++ ) {
|
||||
area = &areas[i];
|
||||
|
||||
areaFirstFace = newFaceIndex.Num();
|
||||
for ( j = 0; j < area->numFaces; j++ ) {
|
||||
faceNum = faceIndex[area->firstFace + j];
|
||||
face = &faces[ abs(faceNum) ];
|
||||
|
||||
// store face
|
||||
if ( !faceRemap[ abs(faceNum) ] ) {
|
||||
faceRemap[ abs(faceNum) ] = newFaces.Num();
|
||||
newFaces.Append( *face );
|
||||
|
||||
// don't store edges for faces we don't care about
|
||||
if ( !( face->flags & ( FACE_FLOOR|FACE_LADDER ) ) ) {
|
||||
|
||||
newFaces[ newFaces.Num()-1 ].firstEdge = 0;
|
||||
newFaces[ newFaces.Num()-1 ].numEdges = 0;
|
||||
|
||||
} else {
|
||||
|
||||
// store edges
|
||||
faceFirstEdge = newEdgeIndex.Num();
|
||||
for ( k = 0; k < face->numEdges; k++ ) {
|
||||
edgeNum = edgeIndex[ face->firstEdge + k ];
|
||||
edge = &edges[ abs(edgeNum) ];
|
||||
|
||||
if ( !edgeRemap[ abs(edgeNum) ] ) {
|
||||
if ( edgeNum < 0 ) {
|
||||
edgeRemap[ abs(edgeNum) ] = -newEdges.Num();
|
||||
}
|
||||
else {
|
||||
edgeRemap[ abs(edgeNum) ] = newEdges.Num();
|
||||
}
|
||||
|
||||
// remap vertices if not yet remapped
|
||||
if ( vertexRemap[ edge->vertexNum[0] ] == -1 ) {
|
||||
vertexRemap[ edge->vertexNum[0] ] = newVertices.Num();
|
||||
newVertices.Append( vertices[ edge->vertexNum[0] ] );
|
||||
}
|
||||
if ( vertexRemap[ edge->vertexNum[1] ] == -1 ) {
|
||||
vertexRemap[ edge->vertexNum[1] ] = newVertices.Num();
|
||||
newVertices.Append( vertices[ edge->vertexNum[1] ] );
|
||||
}
|
||||
|
||||
newEdges.Append( *edge );
|
||||
newEdges[ newEdges.Num()-1 ].vertexNum[0] = vertexRemap[ edge->vertexNum[0] ];
|
||||
newEdges[ newEdges.Num()-1 ].vertexNum[1] = vertexRemap[ edge->vertexNum[1] ];
|
||||
}
|
||||
|
||||
newEdgeIndex.Append( edgeRemap[ abs(edgeNum) ] );
|
||||
}
|
||||
|
||||
newFaces[ newFaces.Num()-1 ].firstEdge = faceFirstEdge;
|
||||
newFaces[ newFaces.Num()-1 ].numEdges = newEdgeIndex.Num() - faceFirstEdge;
|
||||
}
|
||||
}
|
||||
|
||||
if ( faceNum < 0 ) {
|
||||
newFaceIndex.Append( -faceRemap[ abs(faceNum) ] );
|
||||
} else {
|
||||
newFaceIndex.Append( faceRemap[ abs(faceNum) ] );
|
||||
}
|
||||
}
|
||||
|
||||
area->firstFace = areaFirstFace;
|
||||
area->numFaces = newFaceIndex.Num() - areaFirstFace;
|
||||
|
||||
// remap the reachability edges
|
||||
for ( reach = area->reach; reach; reach = reach->next ) {
|
||||
reach->edgeNum = abs( edgeRemap[reach->edgeNum] );
|
||||
}
|
||||
}
|
||||
|
||||
// store new list
|
||||
vertices = newVertices;
|
||||
edges = newEdges;
|
||||
edgeIndex = newEdgeIndex;
|
||||
faces = newFaces;
|
||||
faceIndex = newFaceIndex;
|
||||
}
|
||||
608
neo/tools/compilers/aas/AASFile_sample.cpp
Normal file
608
neo/tools/compilers/aas/AASFile_sample.cpp
Normal file
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASFile.h"
|
||||
#include "AASFile_local.h"
|
||||
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// Environment Sampling
|
||||
//
|
||||
//===============================================================
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::EdgeCenter
|
||||
================
|
||||
*/
|
||||
idVec3 idAASFileLocal::EdgeCenter( int edgeNum ) const {
|
||||
const aasEdge_t *edge;
|
||||
edge = &edges[edgeNum];
|
||||
return ( vertices[edge->vertexNum[0]] + vertices[edge->vertexNum[1]] ) * 0.5f;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::FaceCenter
|
||||
================
|
||||
*/
|
||||
idVec3 idAASFileLocal::FaceCenter( int faceNum ) const {
|
||||
int i, edgeNum;
|
||||
const aasFace_t *face;
|
||||
const aasEdge_t *edge;
|
||||
idVec3 center;
|
||||
|
||||
center = vec3_origin;
|
||||
|
||||
face = &faces[faceNum];
|
||||
if ( face->numEdges > 0 ) {
|
||||
for ( i = 0; i < face->numEdges; i++ ) {
|
||||
edgeNum = edgeIndex[ face->firstEdge + i ];
|
||||
edge = &edges[ abs( edgeNum ) ];
|
||||
center += vertices[ edge->vertexNum[ INTSIGNBITSET(edgeNum) ] ];
|
||||
}
|
||||
center /= face->numEdges;
|
||||
}
|
||||
return center;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::AreaCenter
|
||||
================
|
||||
*/
|
||||
idVec3 idAASFileLocal::AreaCenter( int areaNum ) const {
|
||||
int i, faceNum;
|
||||
const aasArea_t *area;
|
||||
idVec3 center;
|
||||
|
||||
center = vec3_origin;
|
||||
|
||||
area = &areas[areaNum];
|
||||
if ( area->numFaces > 0 ) {
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = faceIndex[area->firstFace + i];
|
||||
center += FaceCenter( abs(faceNum) );
|
||||
}
|
||||
center /= area->numFaces;
|
||||
}
|
||||
return center;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::AreaReachableGoal
|
||||
============
|
||||
*/
|
||||
idVec3 idAASFileLocal::AreaReachableGoal( int areaNum ) const {
|
||||
int i, faceNum, numFaces;
|
||||
const aasArea_t *area;
|
||||
idVec3 center;
|
||||
idVec3 start, end;
|
||||
aasTrace_t trace;
|
||||
|
||||
area = &areas[areaNum];
|
||||
|
||||
if ( !(area->flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) || (area->flags & AREA_LIQUID) ) {
|
||||
return AreaCenter( areaNum );
|
||||
}
|
||||
|
||||
center = vec3_origin;
|
||||
|
||||
numFaces = 0;
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = faceIndex[area->firstFace + i];
|
||||
if ( !(faces[abs(faceNum)].flags & FACE_FLOOR) ) {
|
||||
continue;
|
||||
}
|
||||
center += FaceCenter( abs(faceNum) );
|
||||
numFaces++;
|
||||
}
|
||||
if ( numFaces > 0 ) {
|
||||
center /= numFaces;
|
||||
}
|
||||
center[2] += 1.0f;
|
||||
end = center;
|
||||
end[2] -= 1024;
|
||||
Trace( trace, center, end );
|
||||
|
||||
return trace.endpos;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::EdgeBounds
|
||||
================
|
||||
*/
|
||||
idBounds idAASFileLocal::EdgeBounds( int edgeNum ) const {
|
||||
const aasEdge_t *edge;
|
||||
idBounds bounds;
|
||||
|
||||
edge = &edges[ abs( edgeNum ) ];
|
||||
bounds[0] = bounds[1] = vertices[ edge->vertexNum[0] ];
|
||||
bounds += vertices[ edge->vertexNum[1] ];
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::FaceBounds
|
||||
================
|
||||
*/
|
||||
idBounds idAASFileLocal::FaceBounds( int faceNum ) const {
|
||||
int i, edgeNum;
|
||||
const aasFace_t *face;
|
||||
const aasEdge_t *edge;
|
||||
idBounds bounds;
|
||||
|
||||
face = &faces[faceNum];
|
||||
bounds.Clear();
|
||||
|
||||
for ( i = 0; i < face->numEdges; i++ ) {
|
||||
edgeNum = edgeIndex[ face->firstEdge + i ];
|
||||
edge = &edges[ abs( edgeNum ) ];
|
||||
bounds.AddPoint( vertices[ edge->vertexNum[ INTSIGNBITSET(edgeNum) ] ] );
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASFileLocal::AreaBounds
|
||||
================
|
||||
*/
|
||||
idBounds idAASFileLocal::AreaBounds( int areaNum ) const {
|
||||
int i, faceNum;
|
||||
const aasArea_t *area;
|
||||
idBounds bounds;
|
||||
|
||||
area = &areas[areaNum];
|
||||
bounds.Clear();
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = faceIndex[area->firstFace + i];
|
||||
bounds += FaceBounds( abs(faceNum) );
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::PointAreaNum
|
||||
============
|
||||
*/
|
||||
int idAASFileLocal::PointAreaNum( const idVec3 &origin ) const {
|
||||
int nodeNum;
|
||||
const aasNode_t *node;
|
||||
|
||||
nodeNum = 1;
|
||||
do {
|
||||
node = &nodes[nodeNum];
|
||||
if ( planeList[node->planeNum].Side( origin ) == PLANESIDE_BACK ) {
|
||||
nodeNum = node->children[1];
|
||||
}
|
||||
else {
|
||||
nodeNum = node->children[0];
|
||||
}
|
||||
if ( nodeNum < 0 ) {
|
||||
return -nodeNum;
|
||||
}
|
||||
} while( nodeNum );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::PointReachableAreaNum
|
||||
============
|
||||
*/
|
||||
int idAASFileLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const {
|
||||
int areaList[32], areaNum, i;
|
||||
idVec3 start, end, pointList[32];
|
||||
aasTrace_t trace;
|
||||
idBounds bounds;
|
||||
float frac;
|
||||
|
||||
start = origin;
|
||||
|
||||
trace.areas = areaList;
|
||||
trace.points = pointList;
|
||||
trace.maxAreas = sizeof( areaList ) / sizeof( int );
|
||||
trace.getOutOfSolid = true;
|
||||
|
||||
areaNum = PointAreaNum( start );
|
||||
if ( areaNum ) {
|
||||
if ( ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
|
||||
return areaNum;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// trace up
|
||||
end = start;
|
||||
end[2] += 32.0f;
|
||||
Trace( trace, start, end );
|
||||
if ( trace.numAreas >= 1 ) {
|
||||
if ( ( areas[0].flags & areaFlags ) && ( ( areas[0].travelFlags & excludeTravelFlags ) == 0 ) ) {
|
||||
return areaList[0];
|
||||
}
|
||||
start = pointList[0];
|
||||
start[2] += 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// trace down
|
||||
end = start;
|
||||
end[2] -= 32.0f;
|
||||
Trace( trace, start, end );
|
||||
if ( trace.lastAreaNum ) {
|
||||
if ( ( areas[trace.lastAreaNum].flags & areaFlags ) && ( ( areas[trace.lastAreaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
|
||||
return trace.lastAreaNum;
|
||||
}
|
||||
start = trace.endpos;
|
||||
}
|
||||
|
||||
// expand bounds until an area is found
|
||||
for ( i = 1; i <= 12; i++ ) {
|
||||
frac = i * ( 1.0f / 12.0f );
|
||||
bounds[0] = origin + searchBounds[0] * frac;
|
||||
bounds[1] = origin + searchBounds[1] * frac;
|
||||
areaNum = BoundsReachableAreaNum( bounds, areaFlags, excludeTravelFlags );
|
||||
if ( areaNum && ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
|
||||
return areaNum;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::BoundsReachableAreaNum_r
|
||||
============
|
||||
*/
|
||||
int idAASFileLocal::BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
|
||||
int res;
|
||||
const aasNode_t *node;
|
||||
|
||||
while( nodeNum ) {
|
||||
if ( nodeNum < 0 ) {
|
||||
if ( ( areas[-nodeNum].flags & areaFlags ) && ( ( areas[-nodeNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
|
||||
return -nodeNum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
node = &nodes[nodeNum];
|
||||
res = bounds.PlaneSide( planeList[node->planeNum] );
|
||||
if ( res == PLANESIDE_BACK ) {
|
||||
nodeNum = node->children[1];
|
||||
}
|
||||
else if ( res == PLANESIDE_FRONT ) {
|
||||
nodeNum = node->children[0];
|
||||
}
|
||||
else {
|
||||
nodeNum = BoundsReachableAreaNum_r( node->children[1], bounds, areaFlags, excludeTravelFlags );
|
||||
if ( nodeNum ) {
|
||||
return nodeNum;
|
||||
}
|
||||
nodeNum = node->children[0];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::BoundsReachableAreaNum
|
||||
============
|
||||
*/
|
||||
int idAASFileLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
|
||||
|
||||
return BoundsReachableAreaNum_r( 1, bounds, areaFlags, excludeTravelFlags );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::PushPointIntoAreaNum
|
||||
============
|
||||
*/
|
||||
void idAASFileLocal::PushPointIntoAreaNum( int areaNum, idVec3 &point ) const {
|
||||
int i, faceNum;
|
||||
const aasArea_t *area;
|
||||
const aasFace_t *face;
|
||||
|
||||
area = &areas[areaNum];
|
||||
|
||||
// push the point to the right side of all area face planes
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = faceIndex[area->firstFace + i];
|
||||
face = &faces[abs( faceNum )];
|
||||
|
||||
const idPlane &plane = planeList[face->planeNum ^ INTSIGNBITSET( faceNum )];
|
||||
float dist = plane.Distance( point );
|
||||
|
||||
// project the point onto the face plane if it is on the wrong side
|
||||
if ( dist < 0.0f ) {
|
||||
point -= dist * plane.Normal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::Trace
|
||||
============
|
||||
*/
|
||||
#define TRACEPLANE_EPSILON 0.125f
|
||||
|
||||
typedef struct aasTraceStack_s
|
||||
{
|
||||
idVec3 start;
|
||||
idVec3 end;
|
||||
int planeNum;
|
||||
int nodeNum;
|
||||
} aasTraceStack_t;
|
||||
|
||||
bool idAASFileLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const {
|
||||
int side, nodeNum, tmpPlaneNum;
|
||||
double front, back, frac;
|
||||
idVec3 cur_start, cur_end, cur_mid, v1, v2;
|
||||
aasTraceStack_t tracestack[MAX_AAS_TREE_DEPTH];
|
||||
aasTraceStack_t *tstack_p;
|
||||
const aasNode_t *node;
|
||||
const idPlane *plane;
|
||||
|
||||
trace.numAreas = 0;
|
||||
trace.lastAreaNum = 0;
|
||||
trace.blockingAreaNum = 0;
|
||||
|
||||
tstack_p = tracestack;
|
||||
tstack_p->start = start;
|
||||
tstack_p->end = end;
|
||||
tstack_p->planeNum = 0;
|
||||
tstack_p->nodeNum = 1; //start with the root of the tree
|
||||
tstack_p++;
|
||||
|
||||
while( 1 ) {
|
||||
|
||||
tstack_p--;
|
||||
// if the trace stack is empty
|
||||
if ( tstack_p < tracestack ) {
|
||||
if ( !trace.lastAreaNum ) {
|
||||
// completely in solid
|
||||
trace.fraction = 0.0f;
|
||||
trace.endpos = start;
|
||||
}
|
||||
else {
|
||||
// nothing was hit
|
||||
trace.fraction = 1.0f;
|
||||
trace.endpos = end;
|
||||
}
|
||||
trace.planeNum = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// number of the current node to test the line against
|
||||
nodeNum = tstack_p->nodeNum;
|
||||
|
||||
// if it is an area
|
||||
if ( nodeNum < 0) {
|
||||
// if can't enter the area
|
||||
if ( ( areas[-nodeNum].flags & trace.flags ) || ( areas[-nodeNum].travelFlags & trace.travelFlags ) ) {
|
||||
if ( !trace.lastAreaNum ) {
|
||||
trace.fraction = 0.0f;
|
||||
v1 = vec3_origin;
|
||||
} else {
|
||||
v1 = end - start;
|
||||
v2 = tstack_p->start - start;
|
||||
trace.fraction = v2.Length() / v1.Length();
|
||||
}
|
||||
trace.endpos = tstack_p->start;
|
||||
trace.blockingAreaNum = -nodeNum;
|
||||
trace.planeNum = tstack_p->planeNum;
|
||||
// always take the plane with normal facing towards the trace start
|
||||
plane = &planeList[trace.planeNum];
|
||||
if ( v1 * plane->Normal() > 0.0f ) {
|
||||
trace.planeNum ^= 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
trace.lastAreaNum = -nodeNum;
|
||||
if ( trace.numAreas < trace.maxAreas ) {
|
||||
if ( trace.areas ) {
|
||||
trace.areas[trace.numAreas] = -nodeNum;
|
||||
}
|
||||
if ( trace.points ) {
|
||||
trace.points[trace.numAreas] = tstack_p->start;
|
||||
}
|
||||
trace.numAreas++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// if it is a solid leaf
|
||||
if ( !nodeNum ) {
|
||||
if ( !trace.lastAreaNum ) {
|
||||
trace.fraction = 0.0f;
|
||||
v1 = vec3_origin;
|
||||
} else {
|
||||
v1 = end - start;
|
||||
v2 = tstack_p->start - start;
|
||||
trace.fraction = v2.Length() / v1.Length();
|
||||
}
|
||||
trace.endpos = tstack_p->start;
|
||||
trace.blockingAreaNum = 0; // hit solid leaf
|
||||
trace.planeNum = tstack_p->planeNum;
|
||||
// always take the plane with normal facing towards the trace start
|
||||
plane = &planeList[trace.planeNum];
|
||||
if ( v1 * plane->Normal() > 0.0f ) {
|
||||
trace.planeNum ^= 1;
|
||||
}
|
||||
if ( !trace.lastAreaNum && trace.getOutOfSolid ) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// the node to test against
|
||||
node = &nodes[nodeNum];
|
||||
// start point of current line to test against node
|
||||
cur_start = tstack_p->start;
|
||||
// end point of the current line to test against node
|
||||
cur_end = tstack_p->end;
|
||||
// the current node plane
|
||||
plane = &planeList[node->planeNum];
|
||||
|
||||
front = plane->Distance( cur_start );
|
||||
back = plane->Distance( cur_end );
|
||||
|
||||
// if the whole to be traced line is totally at the front of this node
|
||||
// only go down the tree with the front child
|
||||
if ( front >= -ON_EPSILON && back >= -ON_EPSILON ) {
|
||||
// keep the current start and end point on the stack and go down the tree with the front child
|
||||
tstack_p->nodeNum = node->children[0];
|
||||
tstack_p++;
|
||||
if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
|
||||
common->Error("idAASFileLocal::Trace: stack overflow\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if the whole to be traced line is totally at the back of this node
|
||||
// only go down the tree with the back child
|
||||
else if ( front < ON_EPSILON && back < ON_EPSILON ) {
|
||||
// keep the current start and end point on the stack and go down the tree with the back child
|
||||
tstack_p->nodeNum = node->children[1];
|
||||
tstack_p++;
|
||||
if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
|
||||
common->Error("idAASFileLocal::Trace: stack overflow\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// go down the tree both at the front and back of the node
|
||||
else {
|
||||
tmpPlaneNum = tstack_p->planeNum;
|
||||
// calculate the hit point with the node plane
|
||||
// put the cross point TRACEPLANE_EPSILON on the near side
|
||||
if (front < 0) {
|
||||
frac = (front + TRACEPLANE_EPSILON) / ( front - back );
|
||||
}
|
||||
else {
|
||||
frac = (front - TRACEPLANE_EPSILON) / ( front - back );
|
||||
}
|
||||
|
||||
if (frac < 0) {
|
||||
frac = 0.001f; //0
|
||||
}
|
||||
else if (frac > 1) {
|
||||
frac = 0.999f; //1
|
||||
}
|
||||
|
||||
cur_mid = cur_start + ( cur_end - cur_start ) * frac;
|
||||
|
||||
// side the front part of the line is on
|
||||
side = front < 0;
|
||||
|
||||
// first put the end part of the line on the stack (back side)
|
||||
tstack_p->start = cur_mid;
|
||||
tstack_p->planeNum = node->planeNum;
|
||||
tstack_p->nodeNum = node->children[!side];
|
||||
tstack_p++;
|
||||
if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
|
||||
common->Error("idAASFileLocal::Trace: stack overflow\n" );
|
||||
return false;
|
||||
}
|
||||
// now put the part near the start of the line on the stack so we will
|
||||
// continue with that part first.
|
||||
tstack_p->start = cur_start;
|
||||
tstack_p->end = cur_mid;
|
||||
tstack_p->planeNum = tmpPlaneNum;
|
||||
tstack_p->nodeNum = node->children[side];
|
||||
tstack_p++;
|
||||
if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
|
||||
common->Error("idAASFileLocal::Trace: stack overflow\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::AreaContentsTravelFlags
|
||||
============
|
||||
*/
|
||||
int idAASFileLocal::AreaContentsTravelFlags( int areaNum ) const {
|
||||
if ( areas[areaNum].contents & AREACONTENTS_WATER ) {
|
||||
return TFL_WATER;
|
||||
}
|
||||
return TFL_AIR;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::MaxTreeDepth_r
|
||||
============
|
||||
*/
|
||||
void idAASFileLocal::MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const {
|
||||
const aasNode_t *node;
|
||||
|
||||
if ( nodeNum <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
depth++;
|
||||
if ( depth > maxDepth ) {
|
||||
maxDepth = depth;
|
||||
}
|
||||
|
||||
node = &nodes[nodeNum];
|
||||
MaxTreeDepth_r( node->children[0], depth, maxDepth );
|
||||
MaxTreeDepth_r( node->children[1], depth, maxDepth );
|
||||
|
||||
depth--;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASFileLocal::MaxTreeDepth
|
||||
============
|
||||
*/
|
||||
int idAASFileLocal::MaxTreeDepth( void ) const {
|
||||
int depth, maxDepth;
|
||||
|
||||
depth = maxDepth = 0;
|
||||
MaxTreeDepth_r( 1, depth, maxDepth );
|
||||
return maxDepth;
|
||||
}
|
||||
945
neo/tools/compilers/aas/AASReach.cpp
Normal file
945
neo/tools/compilers/aas/AASReach.cpp
Normal file
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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 "../../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AASFile.h"
|
||||
#include "AASFile_local.h"
|
||||
#include "AASReach.h"
|
||||
|
||||
#define INSIDEUNITS 2.0f
|
||||
#define INSIDEUNITS_WALKEND 0.5f
|
||||
#define INSIDEUNITS_WALKSTART 0.1f
|
||||
#define INSIDEUNITS_SWIMEND 0.5f
|
||||
#define INSIDEUNITS_FLYEND 0.5f
|
||||
#define INSIDEUNITS_WATERJUMP 15.0f
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::ReachabilityExists
|
||||
================
|
||||
*/
|
||||
bool idAASReach::ReachabilityExists( int fromAreaNum, int toAreaNum ) {
|
||||
aasArea_t *area;
|
||||
idReachability *reach;
|
||||
|
||||
area = &file->areas[fromAreaNum];
|
||||
for ( reach = area->reach; reach; reach = reach->next ) {
|
||||
if ( reach->toAreaNum == toAreaNum ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::CanSwimInArea
|
||||
================
|
||||
*/
|
||||
ID_INLINE bool idAASReach::CanSwimInArea( int areaNum ) {
|
||||
return ( file->areas[areaNum].contents & AREACONTENTS_WATER ) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::AreaHasFloor
|
||||
================
|
||||
*/
|
||||
ID_INLINE bool idAASReach::AreaHasFloor( int areaNum ) {
|
||||
return ( file->areas[areaNum].flags & AREA_FLOOR ) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::AreaIsClusterPortal
|
||||
================
|
||||
*/
|
||||
ID_INLINE bool idAASReach::AreaIsClusterPortal( int areaNum ) {
|
||||
return ( file->areas[areaNum].contents & AREACONTENTS_CLUSTERPORTAL ) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::AddReachabilityToArea
|
||||
================
|
||||
*/
|
||||
void idAASReach::AddReachabilityToArea( idReachability *reach, int areaNum ) {
|
||||
aasArea_t *area;
|
||||
|
||||
area = &file->areas[areaNum];
|
||||
reach->next = area->reach;
|
||||
area->reach = reach;
|
||||
numReachabilities++;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::Reachability_Fly
|
||||
================
|
||||
*/
|
||||
void idAASReach::Reachability_Fly( int areaNum ) {
|
||||
int i, faceNum, otherAreaNum;
|
||||
aasArea_t *area;
|
||||
aasFace_t *face;
|
||||
idReachability_Fly *reach;
|
||||
|
||||
area = &file->areas[areaNum];
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = file->faceIndex[area->firstFace + i];
|
||||
face = &file->faces[abs(faceNum)];
|
||||
|
||||
otherAreaNum = face->areas[INTSIGNBITNOTSET(faceNum)];
|
||||
|
||||
if ( otherAreaNum == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ReachabilityExists( areaNum, otherAreaNum ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create reachability going through this face
|
||||
reach = new idReachability_Fly();
|
||||
reach->travelType = TFL_FLY;
|
||||
reach->toAreaNum = otherAreaNum;
|
||||
reach->fromAreaNum = areaNum;
|
||||
reach->edgeNum = 0;
|
||||
reach->travelTime = 1;
|
||||
reach->start = file->FaceCenter( abs(faceNum) );
|
||||
if ( faceNum < 0 ) {
|
||||
reach->end = reach->start + file->planeList[face->planeNum].Normal() * INSIDEUNITS_FLYEND;
|
||||
} else {
|
||||
reach->end = reach->start - file->planeList[face->planeNum].Normal() * INSIDEUNITS_FLYEND;
|
||||
}
|
||||
AddReachabilityToArea( reach, areaNum );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::Reachability_Swim
|
||||
================
|
||||
*/
|
||||
void idAASReach::Reachability_Swim( int areaNum ) {
|
||||
int i, faceNum, otherAreaNum;
|
||||
aasArea_t *area;
|
||||
aasFace_t *face;
|
||||
idReachability_Swim *reach;
|
||||
|
||||
if ( !CanSwimInArea( areaNum ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
area = &file->areas[areaNum];
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = file->faceIndex[area->firstFace + i];
|
||||
face = &file->faces[abs(faceNum)];
|
||||
|
||||
otherAreaNum = face->areas[INTSIGNBITNOTSET(faceNum)];
|
||||
|
||||
if ( otherAreaNum == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !CanSwimInArea( otherAreaNum ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ReachabilityExists( areaNum, otherAreaNum ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create reachability going through this face
|
||||
reach = new idReachability_Swim();
|
||||
reach->travelType = TFL_SWIM;
|
||||
reach->toAreaNum = otherAreaNum;
|
||||
reach->fromAreaNum = areaNum;
|
||||
reach->edgeNum = 0;
|
||||
reach->travelTime = 1;
|
||||
reach->start = file->FaceCenter( abs(faceNum) );
|
||||
if ( faceNum < 0 ) {
|
||||
reach->end = reach->start + file->planeList[face->planeNum].Normal() * INSIDEUNITS_SWIMEND;
|
||||
} else {
|
||||
reach->end = reach->start - file->planeList[face->planeNum].Normal() * INSIDEUNITS_SWIMEND;
|
||||
}
|
||||
AddReachabilityToArea( reach, areaNum );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::Reachability_EqualFloorHeight
|
||||
================
|
||||
*/
|
||||
void idAASReach::Reachability_EqualFloorHeight( int areaNum ) {
|
||||
int i, k, l, m, n, faceNum, face1Num, face2Num, otherAreaNum, edge1Num, edge2Num;
|
||||
aasArea_t *area, *otherArea;
|
||||
aasFace_t *face, *face1, *face2;
|
||||
idReachability_Walk *reach;
|
||||
|
||||
if ( !AreaHasFloor( areaNum ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
area = &file->areas[areaNum];
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = file->faceIndex[area->firstFace + i];
|
||||
face = &file->faces[abs(faceNum)];
|
||||
|
||||
otherAreaNum = face->areas[INTSIGNBITNOTSET(faceNum)];
|
||||
if ( !AreaHasFloor( otherAreaNum ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
otherArea = &file->areas[otherAreaNum];
|
||||
|
||||
for ( k = 0; k < area->numFaces; k++ ) {
|
||||
face1Num = file->faceIndex[area->firstFace + k];
|
||||
face1 = &file->faces[abs(face1Num)];
|
||||
|
||||
if ( !( face1->flags & FACE_FLOOR ) ) {
|
||||
continue;
|
||||
}
|
||||
for ( l = 0; l < otherArea->numFaces; l++ ) {
|
||||
face2Num = file->faceIndex[otherArea->firstFace + l];
|
||||
face2 = &file->faces[abs(face2Num)];
|
||||
|
||||
if ( !( face2->flags & FACE_FLOOR ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( m = 0; m < face1->numEdges; m++ ) {
|
||||
edge1Num = abs(file->edgeIndex[face1->firstEdge + m]);
|
||||
for ( n = 0; n < face2->numEdges; n++ ) {
|
||||
edge2Num = abs(file->edgeIndex[face2->firstEdge + n]);
|
||||
if ( edge1Num == edge2Num ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( n < face2->numEdges ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( m < face1->numEdges ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( l < otherArea->numFaces ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k < area->numFaces ) {
|
||||
// create reachability
|
||||
reach = new idReachability_Walk();
|
||||
reach->travelType = TFL_WALK;
|
||||
reach->toAreaNum = otherAreaNum;
|
||||
reach->fromAreaNum = areaNum;
|
||||
reach->edgeNum = abs( edge1Num );
|
||||
reach->travelTime = 1;
|
||||
reach->start = file->EdgeCenter( edge1Num );
|
||||
if ( faceNum < 0 ) {
|
||||
reach->end = reach->start + file->planeList[face->planeNum].Normal() * INSIDEUNITS_WALKEND;
|
||||
}
|
||||
else {
|
||||
reach->end = reach->start - file->planeList[face->planeNum].Normal() * INSIDEUNITS_WALKEND;
|
||||
}
|
||||
AddReachabilityToArea( reach, areaNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::Reachability_Step_Barrier_WaterJump_WalkOffLedge
|
||||
================
|
||||
*/
|
||||
bool idAASReach::Reachability_Step_Barrier_WaterJump_WalkOffLedge( int area1num, int area2num ) {
|
||||
int i, j, k, l, edge1Num, edge2Num, areas[10];
|
||||
int floor_bestArea1FloorEdgeNum, floor_bestArea2FloorEdgeNum, floor_foundReach;
|
||||
int water_bestArea1FloorEdgeNum, water_bestArea2FloorEdgeNum, water_foundReach;
|
||||
int side1, faceSide1, floorFace1Num;
|
||||
float dist, dist1, dist2, diff, invGravityDot, orthogonalDot;
|
||||
float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y;
|
||||
float length, floor_bestLength, water_bestLength, floor_bestDist, water_bestDist;
|
||||
idVec3 v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2;
|
||||
idVec3 normal, orthogonal, edgeVec, start, end;
|
||||
idVec3 floor_bestStart, floor_bestEnd, floor_bestNormal;
|
||||
idVec3 water_bestStart, water_bestEnd, water_bestNormal;
|
||||
idVec3 testPoint;
|
||||
idPlane *plane;
|
||||
aasArea_t *area1, *area2;
|
||||
aasFace_t *floorFace1, *floorFace2, *floor_bestFace1, *water_bestFace1;
|
||||
aasEdge_t *edge1, *edge2;
|
||||
idReachability_Walk *walkReach;
|
||||
idReachability_BarrierJump *barrierJumpReach;
|
||||
idReachability_WaterJump *waterJumpReach;
|
||||
idReachability_WalkOffLedge *walkOffLedgeReach;
|
||||
aasTrace_t trace;
|
||||
|
||||
// must be able to walk or swim in the first area
|
||||
if ( !AreaHasFloor( area1num ) && !CanSwimInArea( area1num ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !AreaHasFloor( area2num ) && !CanSwimInArea( area2num ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
area1 = &file->areas[area1num];
|
||||
area2 = &file->areas[area2num];
|
||||
|
||||
// if the areas are not near anough in the x-y direction
|
||||
for ( i = 0; i < 2; i++ ) {
|
||||
if ( area1->bounds[0][i] > area2->bounds[1][i] + 2.0f ) {
|
||||
return false;
|
||||
}
|
||||
if ( area1->bounds[1][i] < area2->bounds[0][i] - 2.0f ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
floor_foundReach = false;
|
||||
floor_bestDist = 99999;
|
||||
floor_bestLength = 0;
|
||||
floor_bestArea2FloorEdgeNum = 0;
|
||||
|
||||
water_foundReach = false;
|
||||
water_bestDist = 99999;
|
||||
water_bestLength = 0;
|
||||
water_bestArea2FloorEdgeNum = 0;
|
||||
|
||||
for ( i = 0; i < area1->numFaces; i++ ) {
|
||||
floorFace1Num = file->faceIndex[area1->firstFace + i];
|
||||
faceSide1 = floorFace1Num < 0;
|
||||
floorFace1 = &file->faces[abs(floorFace1Num)];
|
||||
|
||||
// if this isn't a floor face
|
||||
if ( !(floorFace1->flags & FACE_FLOOR) ) {
|
||||
|
||||
// if we can swim in the first area
|
||||
if ( CanSwimInArea( area1num ) ) {
|
||||
|
||||
// face plane must be more or less horizontal
|
||||
plane = &file->planeList[ floorFace1->planeNum ^ (!faceSide1) ];
|
||||
if ( plane->Normal() * file->settings.invGravityDir < file->settings.minFloorCos ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if we can't swim in the area it must be a ground face
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for ( k = 0; k < floorFace1->numEdges; k++ ) {
|
||||
edge1Num = file->edgeIndex[floorFace1->firstEdge + k];
|
||||
side1 = (edge1Num < 0);
|
||||
// NOTE: for water faces we must take the side area 1 is on into
|
||||
// account because the face is shared and doesn't have to be oriented correctly
|
||||
if ( !(floorFace1->flags & FACE_FLOOR) ) {
|
||||
side1 = (side1 == faceSide1);
|
||||
}
|
||||
edge1Num = abs(edge1Num);
|
||||
edge1 = &file->edges[edge1Num];
|
||||
// vertices of the edge
|
||||
v1 = file->vertices[edge1->vertexNum[!side1]];
|
||||
v2 = file->vertices[edge1->vertexNum[side1]];
|
||||
// get a vertical plane through the edge
|
||||
// NOTE: normal is pointing into area 2 because the face edges are stored counter clockwise
|
||||
edgeVec = v2 - v1;
|
||||
normal = edgeVec.Cross( file->settings.invGravityDir );
|
||||
normal.Normalize();
|
||||
dist = normal * v1;
|
||||
|
||||
// check the faces from the second area
|
||||
for ( j = 0; j < area2->numFaces; j++ ) {
|
||||
floorFace2 = &file->faces[abs(file->faceIndex[area2->firstFace + j])];
|
||||
// must be a ground face
|
||||
if ( !(floorFace2->flags & FACE_FLOOR) ) {
|
||||
continue;
|
||||
}
|
||||
// check the edges of this ground face
|
||||
for ( l = 0; l < floorFace2->numEdges; l++ ) {
|
||||
edge2Num = abs(file->edgeIndex[floorFace2->firstEdge + l]);
|
||||
edge2 = &file->edges[edge2Num];
|
||||
// vertices of the edge
|
||||
v3 = file->vertices[edge2->vertexNum[0]];
|
||||
v4 = file->vertices[edge2->vertexNum[1]];
|
||||
// check the distance between the two points and the vertical plane through the edge of area1
|
||||
diff = normal * v3 - dist;
|
||||
if ( diff < -0.2f || diff > 0.2f ) {
|
||||
continue;
|
||||
}
|
||||
diff = normal * v4 - dist;
|
||||
if ( diff < -0.2f || diff > 0.2f ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// project the two ground edges into the step side plane
|
||||
// and calculate the shortest distance between the two
|
||||
// edges if they overlap in the direction orthogonal to
|
||||
// the gravity direction
|
||||
orthogonal = file->settings.invGravityDir.Cross( normal );
|
||||
invGravityDot = file->settings.invGravityDir * file->settings.invGravityDir;
|
||||
orthogonalDot = orthogonal * orthogonal;
|
||||
// projection into the step plane
|
||||
// NOTE: since gravity is vertical this is just the z coordinate
|
||||
y1 = v1[2];//(v1 * file->settings.invGravity) / invGravityDot;
|
||||
y2 = v2[2];//(v2 * file->settings.invGravity) / invGravityDot;
|
||||
y3 = v3[2];//(v3 * file->settings.invGravity) / invGravityDot;
|
||||
y4 = v4[2];//(v4 * file->settings.invGravity) / invGravityDot;
|
||||
|
||||
x1 = (v1 * orthogonal) / orthogonalDot;
|
||||
x2 = (v2 * orthogonal) / orthogonalDot;
|
||||
x3 = (v3 * orthogonal) / orthogonalDot;
|
||||
x4 = (v4 * orthogonal) / orthogonalDot;
|
||||
|
||||
if ( x1 > x2 ) {
|
||||
tmp = x1; x1 = x2; x2 = tmp;
|
||||
tmp = y1; y1 = y2; y2 = tmp;
|
||||
tmpv = v1; v1 = v2; v2 = tmpv;
|
||||
}
|
||||
if ( x3 > x4 ) {
|
||||
tmp = x3; x3 = x4; x4 = tmp;
|
||||
tmp = y3; y3 = y4; y4 = tmp;
|
||||
tmpv = v3; v3 = v4; v4 = tmpv;
|
||||
}
|
||||
// if the two projected edge lines have no overlap
|
||||
if ( x2 <= x3 || x4 <= x1 ) {
|
||||
continue;
|
||||
}
|
||||
// if the two lines fully overlap
|
||||
if ( (x1 - 0.5f < x3 && x4 < x2 + 0.5f) && (x3 - 0.5f < x1 && x2 < x4 + 0.5f) ) {
|
||||
dist1 = y3 - y1;
|
||||
dist2 = y4 - y2;
|
||||
p1area1 = v1;
|
||||
p2area1 = v2;
|
||||
p1area2 = v3;
|
||||
p2area2 = v4;
|
||||
}
|
||||
else {
|
||||
// if the points are equal
|
||||
if ( x1 > x3 - 0.1f && x1 < x3 + 0.1f ) {
|
||||
dist1 = y3 - y1;
|
||||
p1area1 = v1;
|
||||
p1area2 = v3;
|
||||
}
|
||||
else if ( x1 < x3 ) {
|
||||
y = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1);
|
||||
dist1 = y3 - y;
|
||||
p1area1 = v3;
|
||||
p1area1[2] = y;
|
||||
p1area2 = v3;
|
||||
}
|
||||
else {
|
||||
y = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3);
|
||||
dist1 = y - y1;
|
||||
p1area1 = v1;
|
||||
p1area2 = v1;
|
||||
p1area2[2] = y;
|
||||
}
|
||||
// if the points are equal
|
||||
if ( x2 > x4 - 0.1f && x2 < x4 + 0.1f ) {
|
||||
dist2 = y4 - y2;
|
||||
p2area1 = v2;
|
||||
p2area2 = v4;
|
||||
}
|
||||
else if ( x2 < x4 ) {
|
||||
y = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3);
|
||||
dist2 = y - y2;
|
||||
p2area1 = v2;
|
||||
p2area2 = v2;
|
||||
p2area2[2] = y;
|
||||
}
|
||||
else {
|
||||
y = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1);
|
||||
dist2 = y4 - y;
|
||||
p2area1 = v4;
|
||||
p2area1[2] = y;
|
||||
p2area2 = v4;
|
||||
}
|
||||
}
|
||||
|
||||
// if both distances are pretty much equal then we take the middle of the points
|
||||
if ( dist1 > dist2 - 1.0f && dist1 < dist2 + 1.0f ) {
|
||||
dist = dist1;
|
||||
start = ( p1area1 + p2area1 ) * 0.5f;
|
||||
end = ( p1area2 + p2area2 ) * 0.5f;
|
||||
}
|
||||
else if (dist1 < dist2) {
|
||||
dist = dist1;
|
||||
start = p1area1;
|
||||
end = p1area2;
|
||||
}
|
||||
else {
|
||||
dist = dist2;
|
||||
start = p2area1;
|
||||
end = p2area2;
|
||||
}
|
||||
|
||||
// get the length of the overlapping part of the edges of the two areas
|
||||
length = (p2area2 - p1area2).Length();
|
||||
|
||||
if ( floorFace1->flags & FACE_FLOOR ) {
|
||||
// if the vertical distance is smaller
|
||||
if ( dist < floor_bestDist ||
|
||||
// or the vertical distance is pretty much the same
|
||||
// but the overlapping part of the edges is longer
|
||||
(dist < floor_bestDist + 1.0f && length > floor_bestLength) ) {
|
||||
floor_bestDist = dist;
|
||||
floor_bestLength = length;
|
||||
floor_foundReach = true;
|
||||
floor_bestArea1FloorEdgeNum = edge1Num;
|
||||
floor_bestArea2FloorEdgeNum = edge2Num;
|
||||
floor_bestFace1 = floorFace1;
|
||||
floor_bestStart = start;
|
||||
floor_bestNormal = normal;
|
||||
floor_bestEnd = end;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if the vertical distance is smaller
|
||||
if ( dist < water_bestDist ||
|
||||
//or the vertical distance is pretty much the same
|
||||
//but the overlapping part of the edges is longer
|
||||
(dist < water_bestDist + 1.0f && length > water_bestLength) ) {
|
||||
water_bestDist = dist;
|
||||
water_bestLength = length;
|
||||
water_foundReach = true;
|
||||
water_bestArea1FloorEdgeNum = edge1Num;
|
||||
water_bestArea2FloorEdgeNum = edge2Num;
|
||||
water_bestFace1 = floorFace1;
|
||||
water_bestStart = start; // best start point in area1
|
||||
water_bestNormal = normal; // normal is pointing into area2
|
||||
water_bestEnd = end; // best point towards area2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// NOTE: swim reachabilities should already be filtered out
|
||||
//
|
||||
// Steps
|
||||
//
|
||||
// ---------
|
||||
// | step height -> TFL_WALK
|
||||
// --------|
|
||||
//
|
||||
// ---------
|
||||
// ~~~~~~~~| step height and low water -> TFL_WALK
|
||||
// --------|
|
||||
//
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
// ---------
|
||||
// | step height and low water up to the step -> TFL_WALK
|
||||
// --------|
|
||||
//
|
||||
// check for a step reachability
|
||||
if ( floor_foundReach ) {
|
||||
// if area2 is higher but lower than the maximum step height
|
||||
// NOTE: floor_bestDist >= 0 also catches equal floor reachabilities
|
||||
if ( floor_bestDist >= 0 && floor_bestDist < file->settings.maxStepHeight ) {
|
||||
// create walk reachability from area1 to area2
|
||||
walkReach = new idReachability_Walk();
|
||||
walkReach->travelType = TFL_WALK;
|
||||
walkReach->toAreaNum = area2num;
|
||||
walkReach->fromAreaNum = area1num;
|
||||
walkReach->start = floor_bestStart + INSIDEUNITS_WALKSTART * floor_bestNormal;
|
||||
walkReach->end = floor_bestEnd + INSIDEUNITS_WALKEND * floor_bestNormal;
|
||||
walkReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
|
||||
walkReach->travelTime = 0;
|
||||
if ( area2->flags & AREA_CROUCH ) {
|
||||
walkReach->travelTime += file->settings.tt_startCrouching;
|
||||
}
|
||||
AddReachabilityToArea( walkReach, area1num );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Water Jumps
|
||||
//
|
||||
// ---------
|
||||
// |
|
||||
// ~~~~~~~~|
|
||||
// |
|
||||
// | higher than step height and water up to waterjump height -> TFL_WATERJUMP
|
||||
// --------|
|
||||
//
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
// ---------
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// | higher than step height and low water up to the step -> TFL_WATERJUMP
|
||||
// --------|
|
||||
//
|
||||
// check for a waterjump reachability
|
||||
if ( water_foundReach ) {
|
||||
// get a test point a little bit towards area1
|
||||
testPoint = water_bestEnd - INSIDEUNITS * water_bestNormal;
|
||||
// go down the maximum waterjump height
|
||||
testPoint[2] -= file->settings.maxWaterJumpHeight;
|
||||
// if there IS water the sv_maxwaterjump height below the bestend point
|
||||
if ( area1->flags & AREA_LIQUID ) {
|
||||
// don't create rediculous water jump reachabilities from areas very far below the water surface
|
||||
if ( water_bestDist < file->settings.maxWaterJumpHeight + 24 ) {
|
||||
// water jumping from or towards a crouch only areas is not possible
|
||||
if ( !(area1->flags & AREA_CROUCH) && !(area2->flags & AREA_CROUCH) ) {
|
||||
// create water jump reachability from area1 to area2
|
||||
waterJumpReach = new idReachability_WaterJump();
|
||||
waterJumpReach->travelType = TFL_WATERJUMP;
|
||||
waterJumpReach->toAreaNum = area2num;
|
||||
waterJumpReach->fromAreaNum = area1num;
|
||||
waterJumpReach->start = water_bestStart;
|
||||
waterJumpReach->end = water_bestEnd + INSIDEUNITS_WATERJUMP * water_bestNormal;
|
||||
waterJumpReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
|
||||
waterJumpReach->travelTime = file->settings.tt_waterJump;
|
||||
AddReachabilityToArea( waterJumpReach, area1num );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Barrier Jumps
|
||||
//
|
||||
// ---------
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// | higher than max step height lower than max barrier height -> TFL_BARRIERJUMP
|
||||
// --------|
|
||||
//
|
||||
// ---------
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// ~~~~~~~~| higher than max step height lower than max barrier height
|
||||
// --------| and a thin layer of water in the area to jump from -> TFL_BARRIERJUMP
|
||||
//
|
||||
// check for a barrier jump reachability
|
||||
if ( floor_foundReach ) {
|
||||
//if area2 is higher but lower than the maximum barrier jump height
|
||||
if ( floor_bestDist > 0 && floor_bestDist < file->settings.maxBarrierHeight ) {
|
||||
//if no water in area1 or a very thin layer of water on the ground
|
||||
if ( !water_foundReach || (floor_bestDist - water_bestDist < 16) ) {
|
||||
// cannot perform a barrier jump towards or from a crouch area
|
||||
if ( !(area1->flags & AREA_CROUCH) && !(area2->flags & AREA_CROUCH) ) {
|
||||
// create barrier jump reachability from area1 to area2
|
||||
barrierJumpReach = new idReachability_BarrierJump();
|
||||
barrierJumpReach->travelType = TFL_BARRIERJUMP;
|
||||
barrierJumpReach->toAreaNum = area2num;
|
||||
barrierJumpReach->fromAreaNum = area1num;
|
||||
barrierJumpReach->start = floor_bestStart + INSIDEUNITS_WALKSTART * floor_bestNormal;
|
||||
barrierJumpReach->end = floor_bestEnd + INSIDEUNITS_WALKEND * floor_bestNormal;
|
||||
barrierJumpReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
|
||||
barrierJumpReach->travelTime = file->settings.tt_barrierJump;
|
||||
AddReachabilityToArea( barrierJumpReach, area1num );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Walk and Walk Off Ledge
|
||||
//
|
||||
// --------|
|
||||
// | can walk or step back -> TFL_WALK
|
||||
// ---------
|
||||
//
|
||||
// --------|
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// | cannot walk/step back -> TFL_WALKOFFLEDGE
|
||||
// ---------
|
||||
//
|
||||
// --------|
|
||||
// |
|
||||
// |~~~~~~~~
|
||||
// |
|
||||
// | cannot step back but can waterjump back -> TFL_WALKOFFLEDGE
|
||||
// --------- FIXME: create TFL_WALK reach??
|
||||
//
|
||||
// check for a walk or walk off ledge reachability
|
||||
if ( floor_foundReach ) {
|
||||
if ( floor_bestDist < 0 ) {
|
||||
if ( floor_bestDist > -file->settings.maxStepHeight ) {
|
||||
// create walk reachability from area1 to area2
|
||||
walkReach = new idReachability_Walk();
|
||||
walkReach->travelType = TFL_WALK;
|
||||
walkReach->toAreaNum = area2num;
|
||||
walkReach->fromAreaNum = area1num;
|
||||
walkReach->start = floor_bestStart + INSIDEUNITS_WALKSTART * floor_bestNormal;
|
||||
walkReach->end = floor_bestEnd + INSIDEUNITS_WALKEND * floor_bestNormal;
|
||||
walkReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
|
||||
walkReach->travelTime = 1;
|
||||
AddReachabilityToArea( walkReach, area1num );
|
||||
return true;
|
||||
}
|
||||
// if no maximum fall height set or less than the max
|
||||
if ( !file->settings.maxFallHeight || idMath::Fabs(floor_bestDist) < file->settings.maxFallHeight ) {
|
||||
// trace a bounding box vertically to check for solids
|
||||
floor_bestEnd += INSIDEUNITS * floor_bestNormal;
|
||||
start = floor_bestEnd;
|
||||
start[2] = floor_bestStart[2];
|
||||
end = floor_bestEnd;
|
||||
end[2] += 4;
|
||||
trace.areas = areas;
|
||||
trace.maxAreas = sizeof(areas) / sizeof(int);
|
||||
file->Trace( trace, start, end );
|
||||
// if the trace didn't start in solid and nothing was hit
|
||||
if ( trace.lastAreaNum && trace.fraction >= 1.0f ) {
|
||||
// the trace end point must be in the goal area
|
||||
if ( trace.lastAreaNum == area2num ) {
|
||||
// don't create reachability if going through a cluster portal
|
||||
for (i = 0; i < trace.numAreas; i++) {
|
||||
if ( AreaIsClusterPortal( trace.areas[i] ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i >= trace.numAreas ) {
|
||||
// create a walk off ledge reachability from area1 to area2
|
||||
walkOffLedgeReach = new idReachability_WalkOffLedge();
|
||||
walkOffLedgeReach->travelType = TFL_WALKOFFLEDGE;
|
||||
walkOffLedgeReach->toAreaNum = area2num;
|
||||
walkOffLedgeReach->fromAreaNum = area1num;
|
||||
walkOffLedgeReach->start = floor_bestStart;
|
||||
walkOffLedgeReach->end = floor_bestEnd;
|
||||
walkOffLedgeReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
|
||||
walkOffLedgeReach->travelTime = file->settings.tt_startWalkOffLedge + idMath::Fabs(floor_bestDist) * 50 / file->settings.gravityValue;
|
||||
AddReachabilityToArea( walkOffLedgeReach, area1num );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::Reachability_WalkOffLedge
|
||||
================
|
||||
*/
|
||||
void idAASReach::Reachability_WalkOffLedge( int areaNum ) {
|
||||
int i, j, faceNum, edgeNum, side, reachAreaNum, p, areas[10];
|
||||
aasArea_t *area;
|
||||
aasFace_t *face;
|
||||
aasEdge_t *edge;
|
||||
idPlane *plane;
|
||||
idVec3 v1, v2, mid, dir, testEnd;
|
||||
idReachability_WalkOffLedge *reach;
|
||||
aasTrace_t trace;
|
||||
|
||||
if ( !AreaHasFloor( areaNum ) || CanSwimInArea( areaNum ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
area = &file->areas[areaNum];
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = file->faceIndex[area->firstFace + i];
|
||||
face = &file->faces[abs(faceNum)];
|
||||
|
||||
// face must be a floor face
|
||||
if ( !(face->flags & FACE_FLOOR) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( j = 0; j < face->numEdges; j++ ) {
|
||||
|
||||
edgeNum = file->edgeIndex[face->firstEdge + j];
|
||||
edge = &file->edges[abs(edgeNum)];
|
||||
|
||||
//if ( !(edge->flags & EDGE_LEDGE) ) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
side = edgeNum < 0;
|
||||
|
||||
v1 = file->vertices[edge->vertexNum[side]];
|
||||
v2 = file->vertices[edge->vertexNum[!side]];
|
||||
|
||||
plane = &file->planeList[face->planeNum ^ INTSIGNBITSET(faceNum) ];
|
||||
|
||||
// get the direction into the other area
|
||||
dir = plane->Normal().Cross( v2 - v1 );
|
||||
dir.Normalize();
|
||||
|
||||
mid = ( v1 + v2 ) * 0.5f;
|
||||
testEnd = mid + INSIDEUNITS_WALKEND * dir;
|
||||
testEnd[2] -= file->settings.maxFallHeight + 1.0f;
|
||||
trace.areas = areas;
|
||||
trace.maxAreas = sizeof(areas) / sizeof(int);
|
||||
file->Trace( trace, mid, testEnd );
|
||||
|
||||
reachAreaNum = trace.lastAreaNum;
|
||||
if ( !reachAreaNum || reachAreaNum == areaNum ) {
|
||||
continue;
|
||||
}
|
||||
if ( idMath::Fabs( mid[2] - trace.endpos[2] ) > file->settings.maxFallHeight ) {
|
||||
continue;
|
||||
}
|
||||
if ( !AreaHasFloor( reachAreaNum ) && !CanSwimInArea( reachAreaNum ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( ReachabilityExists( areaNum, reachAreaNum) ) {
|
||||
continue;
|
||||
}
|
||||
// if not going through a cluster portal
|
||||
for ( p = 0; p < trace.numAreas; p++ ) {
|
||||
if ( AreaIsClusterPortal( trace.areas[p] ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( p < trace.numAreas ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reach = new idReachability_WalkOffLedge();
|
||||
reach->travelType = TFL_WALKOFFLEDGE;
|
||||
reach->toAreaNum = reachAreaNum;
|
||||
reach->fromAreaNum = areaNum;
|
||||
reach->start = mid;
|
||||
reach->end = trace.endpos;
|
||||
reach->edgeNum = abs( edgeNum );
|
||||
reach->travelTime = file->settings.tt_startWalkOffLedge + idMath::Fabs(mid[2] - trace.endpos[2]) * 50 / file->settings.gravityValue;
|
||||
AddReachabilityToArea( reach, areaNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::FlagReachableAreas
|
||||
================
|
||||
*/
|
||||
void idAASReach::FlagReachableAreas( idAASFileLocal *file ) {
|
||||
int i, numReachableAreas;
|
||||
|
||||
numReachableAreas = 0;
|
||||
for ( i = 1; i < file->areas.Num(); i++ ) {
|
||||
|
||||
if ( ( file->areas[i].flags & ( AREA_FLOOR | AREA_LADDER ) ) ||
|
||||
( file->areas[i].contents & AREACONTENTS_WATER ) ) {
|
||||
file->areas[i].flags |= AREA_REACHABLE_WALK;
|
||||
}
|
||||
if ( file->GetSettings().allowFlyReachabilities ) {
|
||||
file->areas[i].flags |= AREA_REACHABLE_FLY;
|
||||
}
|
||||
numReachableAreas++;
|
||||
}
|
||||
|
||||
common->Printf( "%6d reachable areas\n", numReachableAreas );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAASReach::Build
|
||||
================
|
||||
*/
|
||||
bool idAASReach::Build( const idMapFile *mapFile, idAASFileLocal *file ) {
|
||||
int i, j, lastPercent, percent;
|
||||
|
||||
this->mapFile = mapFile;
|
||||
this->file = file;
|
||||
numReachabilities = 0;
|
||||
|
||||
common->Printf( "[Reachability]\n" );
|
||||
|
||||
// delete all existing reachabilities
|
||||
file->DeleteReachabilities();
|
||||
|
||||
FlagReachableAreas( file );
|
||||
|
||||
for ( i = 1; i < file->areas.Num(); i++ ) {
|
||||
if ( !( file->areas[i].flags & AREA_REACHABLE_WALK ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( file->GetSettings().allowSwimReachabilities ) {
|
||||
Reachability_Swim( i );
|
||||
}
|
||||
Reachability_EqualFloorHeight( i );
|
||||
}
|
||||
|
||||
lastPercent = -1;
|
||||
for ( i = 1; i < file->areas.Num(); i++ ) {
|
||||
|
||||
if ( !( file->areas[i].flags & AREA_REACHABLE_WALK ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( j = 0; j < file->areas.Num(); j++ ) {
|
||||
if ( i == j ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !( file->areas[j].flags & AREA_REACHABLE_WALK ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ReachabilityExists( i, j ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( Reachability_Step_Barrier_WaterJump_WalkOffLedge( i, j ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Reachability_WalkOffLedge( i );
|
||||
|
||||
percent = 100 * i / file->areas.Num();
|
||||
if ( percent > lastPercent ) {
|
||||
common->Printf( "\r%6d%%", percent );
|
||||
lastPercent = percent;
|
||||
}
|
||||
}
|
||||
|
||||
if ( file->GetSettings().allowFlyReachabilities ) {
|
||||
for ( i = 1; i < file->areas.Num(); i++ ) {
|
||||
Reachability_Fly( i );
|
||||
}
|
||||
}
|
||||
|
||||
file->LinkReversedReachability();
|
||||
|
||||
common->Printf( "\r%6d reachabilities\n", numReachabilities );
|
||||
|
||||
return true;
|
||||
}
|
||||
67
neo/tools/compilers/aas/AASReach.h
Normal file
67
neo/tools/compilers/aas/AASReach.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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__ */
|
||||
1582
neo/tools/compilers/aas/Brush.cpp
Normal file
1582
neo/tools/compilers/aas/Brush.cpp
Normal file
File diff suppressed because it is too large
Load Diff
231
neo/tools/compilers/aas/Brush.h
Normal file
231
neo/tools/compilers/aas/Brush.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
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_attribute((format(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__ */
|
||||
2151
neo/tools/compilers/aas/BrushBSP.cpp
Normal file
2151
neo/tools/compilers/aas/BrushBSP.cpp
Normal file
File diff suppressed because it is too large
Load Diff
233
neo/tools/compilers/aas/BrushBSP.h
Normal file
233
neo/tools/compilers/aas/BrushBSP.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __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__ */
|
||||
Reference in New Issue
Block a user