2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Trace model vs . polygonal model collision detection .
It is more important to minimize the number of collision polygons
than it is to minimize the number of edges used for collision
detection ( total edges - internal edges ) .
Stitching the world tends to minimize the number of edges used
for collision detection ( more internal edges ) . However stitching
also results in more collision polygons which usually makes a
stitched world slower .
In an average map over 30 % of all edges is internal .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "CollisionModel_local.h"
# define CMODEL_BINARYFILE_EXT "bcmodel"
idCollisionModelManagerLocal collisionModelManagerLocal ;
2012-11-28 15:47:07 +00:00
idCollisionModelManager * collisionModelManager = & collisionModelManagerLocal ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
cm_windingList_t * cm_windingList ;
cm_windingList_t * cm_outList ;
cm_windingList_t * cm_tmpList ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
idHashIndex * cm_vertexHash ;
idHashIndex * cm_edgeHash ;
2012-11-26 18:58:24 +00:00
idBounds cm_modelBounds ;
int cm_vertexShift ;
idCVar preLoad_Collision ( " preLoad_Collision " , " 1 " , CVAR_SYSTEM | CVAR_BOOL , " preload collision beginlevelload " ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Proc BSP tree for data pruning
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ParseProcNodes
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ParseProcNodes ( idLexer * src )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src - > ExpectTokenString ( " { " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
numProcNodes = src - > ParseInt ( ) ;
2012-11-28 15:47:07 +00:00
if ( numProcNodes < 0 )
{
2012-11-26 18:58:24 +00:00
src - > Error ( " ParseProcNodes: bad numProcNodes " ) ;
}
2012-11-28 15:47:07 +00:00
procNodes = ( cm_procNode_t * ) Mem_ClearedAlloc ( numProcNodes * sizeof ( cm_procNode_t ) , TAG_COLLISION ) ;
for ( i = 0 ; i < numProcNodes ; i + + )
{
cm_procNode_t * node ;
2012-11-26 18:58:24 +00:00
node = & procNodes [ i ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src - > Parse1DMatrix ( 4 , node - > plane . ToFloatPtr ( ) ) ;
node - > children [ 0 ] = src - > ParseInt ( ) ;
node - > children [ 1 ] = src - > ParseInt ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src - > ExpectTokenString ( " } " ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : LoadProcBSP
FIXME : if the nodes would be at the start of the . proc file it would speed things up considerably
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : LoadProcBSP ( const char * name )
{
2012-11-26 18:58:24 +00:00
idStr filename ;
idToken token ;
2012-11-28 15:47:07 +00:00
idLexer * src ;
2012-11-26 18:58:24 +00:00
// load it
filename = name ;
filename . SetFileExtension ( PROC_FILE_EXT ) ;
2012-11-28 15:47:07 +00:00
src = new ( TAG_COLLISION ) idLexer ( filename , LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE ) ;
if ( ! src - > IsLoaded ( ) )
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::LoadProcBSP: couldn't load %s " , filename . c_str ( ) ) ;
delete src ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! src - > ReadToken ( & token ) | | token . Icmp ( PROC_FILE_ID ) )
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::LoadProcBSP: bad id '%s' instead of '%s' " , token . c_str ( ) , PROC_FILE_ID ) ;
delete src ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// parse the file
2012-11-28 15:47:07 +00:00
while ( 1 )
{
if ( ! src - > ReadToken ( & token ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( token = = " model " )
{
2012-11-26 18:58:24 +00:00
src - > SkipBracedSection ( ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( token = = " shadowModel " )
{
2012-11-26 18:58:24 +00:00
src - > SkipBracedSection ( ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( token = = " interAreaPortals " )
{
2012-11-26 18:58:24 +00:00
src - > SkipBracedSection ( ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( token = = " nodes " )
{
2012-11-26 18:58:24 +00:00
ParseProcNodes ( src ) ;
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src - > Error ( " idCollisionModelManagerLocal::LoadProcBSP: bad token \" %s \" " , token . c_str ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
delete src ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Free map
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : Clear
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : Clear ( )
{
2012-11-26 18:58:24 +00:00
mapName . Clear ( ) ;
mapFileTime = 0 ;
loaded = 0 ;
checkCount = 0 ;
maxModels = 0 ;
numModels = 0 ;
models = NULL ;
memset ( trmPolygons , 0 , sizeof ( trmPolygons ) ) ;
trmBrushes [ 0 ] = NULL ;
trmMaterial = NULL ;
numProcNodes = 0 ;
procNodes = NULL ;
getContacts = false ;
contacts = NULL ;
maxContacts = 0 ;
numContacts = 0 ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : RemovePolygonReferences_r
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : RemovePolygonReferences_r ( cm_node_t * node , cm_polygon_t * p )
{
cm_polygonRef_t * pref ;
while ( node )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
if ( pref - > p = = p )
{
2012-11-26 18:58:24 +00:00
pref - > p = NULL ;
// cannot return here because we can have links down the tree due to polygon merging
//return;
}
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( p - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( p - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
RemovePolygonReferences_r ( node - > children [ 1 ] , p ) ;
node = node - > children [ 0 ] ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : RemoveBrushReferences_r
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : RemoveBrushReferences_r ( cm_node_t * node , cm_brush_t * b )
{
cm_brushRef_t * bref ;
while ( node )
{
for ( bref = node - > brushes ; bref ; bref = bref - > next )
{
if ( bref - > b = = b )
{
2012-11-26 18:58:24 +00:00
bref - > b = NULL ;
return ;
}
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( b - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( b - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
RemoveBrushReferences_r ( node - > children [ 1 ] , b ) ;
node = node - > children [ 0 ] ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeNode
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeNode ( cm_node_t * node )
{
2012-11-26 18:58:24 +00:00
// don't free the node here
// the nodes are allocated in blocks which are freed when the model is freed
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreePolygonReference
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreePolygonReference ( cm_polygonRef_t * pref )
{
2012-11-26 18:58:24 +00:00
// don't free the polygon reference here
// the polygon references are allocated in blocks which are freed when the model is freed
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeBrushReference
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeBrushReference ( cm_brushRef_t * bref )
{
2012-11-26 18:58:24 +00:00
// don't free the brush reference here
// the brush references are allocated in blocks which are freed when the model is freed
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreePolygon
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreePolygon ( cm_model_t * model , cm_polygon_t * poly )
{
2012-11-26 18:58:24 +00:00
model - > numPolygons - - ;
model - > polygonMemory - = sizeof ( cm_polygon_t ) + ( poly - > numEdges - 1 ) * sizeof ( poly - > edges [ 0 ] ) ;
2012-11-28 15:47:07 +00:00
if ( model - > polygonBlock = = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( poly ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeBrush
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeBrush ( cm_model_t * model , cm_brush_t * brush )
{
2012-11-26 18:58:24 +00:00
model - > numBrushes - - ;
model - > brushMemory - = sizeof ( cm_brush_t ) + ( brush - > numPlanes - 1 ) * sizeof ( brush - > planes [ 0 ] ) ;
2012-11-28 15:47:07 +00:00
if ( model - > brushBlock = = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( brush ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeTree_r
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeTree_r ( cm_model_t * model , cm_node_t * headNode , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
cm_brushRef_t * bref ;
cm_brush_t * b ;
2012-11-26 18:58:24 +00:00
// free all polygons at this node
2012-11-28 15:47:07 +00:00
for ( pref = node - > polygons ; pref ; pref = node - > polygons )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
2012-11-28 15:47:07 +00:00
if ( p )
{
2012-11-26 18:58:24 +00:00
// remove all other references to this polygon
RemovePolygonReferences_r ( headNode , p ) ;
FreePolygon ( model , p ) ;
}
node - > polygons = pref - > next ;
FreePolygonReference ( pref ) ;
}
// free all brushes at this node
2012-11-28 15:47:07 +00:00
for ( bref = node - > brushes ; bref ; bref = node - > brushes )
{
2012-11-26 18:58:24 +00:00
b = bref - > b ;
2012-11-28 15:47:07 +00:00
if ( b )
{
2012-11-26 18:58:24 +00:00
// remove all other references to this brush
RemoveBrushReferences_r ( headNode , b ) ;
FreeBrush ( model , b ) ;
}
node - > brushes = bref - > next ;
FreeBrushReference ( bref ) ;
}
// recurse down the tree
2012-11-28 15:47:07 +00:00
if ( node - > planeType ! = - 1 )
{
2012-11-26 18:58:24 +00:00
FreeTree_r ( model , headNode , node - > children [ 0 ] ) ;
node - > children [ 0 ] = NULL ;
FreeTree_r ( model , headNode , node - > children [ 1 ] ) ;
node - > children [ 1 ] = NULL ;
}
FreeNode ( node ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeModel ( cm_model_t * model )
{
cm_polygonRefBlock_t * polygonRefBlock , * nextPolygonRefBlock ;
cm_brushRefBlock_t * brushRefBlock , * nextBrushRefBlock ;
cm_nodeBlock_t * nodeBlock , * nextNodeBlock ;
2012-11-26 18:58:24 +00:00
// free the tree structure
2012-11-28 15:47:07 +00:00
if ( model - > node )
{
2012-11-26 18:58:24 +00:00
FreeTree_r ( model , model - > node , model - > node ) ;
}
// free blocks with polygon references
2012-11-28 15:47:07 +00:00
for ( polygonRefBlock = model - > polygonRefBlocks ; polygonRefBlock ; polygonRefBlock = nextPolygonRefBlock )
{
2012-11-26 18:58:24 +00:00
nextPolygonRefBlock = polygonRefBlock - > next ;
Mem_Free ( polygonRefBlock ) ;
}
// free blocks with brush references
2012-11-28 15:47:07 +00:00
for ( brushRefBlock = model - > brushRefBlocks ; brushRefBlock ; brushRefBlock = nextBrushRefBlock )
{
2012-11-26 18:58:24 +00:00
nextBrushRefBlock = brushRefBlock - > next ;
Mem_Free ( brushRefBlock ) ;
}
// free blocks with nodes
2012-11-28 15:47:07 +00:00
for ( nodeBlock = model - > nodeBlocks ; nodeBlock ; nodeBlock = nextNodeBlock )
{
2012-11-26 18:58:24 +00:00
nextNodeBlock = nodeBlock - > next ;
Mem_Free ( nodeBlock ) ;
}
// free block allocated polygons
Mem_Free ( model - > polygonBlock ) ;
// free block allocated brushes
Mem_Free ( model - > brushBlock ) ;
// free edges
Mem_Free ( model - > edges ) ;
// free vertices
Mem_Free ( model - > vertices ) ;
// free the model
delete model ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeMap
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeMap ( )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
if ( ! loaded )
{
2012-11-26 18:58:24 +00:00
Clear ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < maxModels ; i + + )
{
if ( ! models [ i ] )
{
2012-11-26 18:58:24 +00:00
continue ;
}
FreeModel ( models [ i ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
FreeTrmModelStructure ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Mem_Free ( models ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ShutdownHash ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FreeTrmModelStructure
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FreeTrmModelStructure ( )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( models ) ;
2012-11-28 15:47:07 +00:00
if ( ! models [ MAX_SUBMODELS ] )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < MAX_TRACEMODEL_POLYS ; i + + )
{
2012-11-26 18:58:24 +00:00
FreePolygon ( models [ MAX_SUBMODELS ] , trmPolygons [ i ] - > p ) ;
}
FreeBrush ( models [ MAX_SUBMODELS ] , trmBrushes [ 0 ] - > b ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
models [ MAX_SUBMODELS ] - > node - > polygons = NULL ;
models [ MAX_SUBMODELS ] - > node - > brushes = NULL ;
FreeModel ( models [ MAX_SUBMODELS ] ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Edge normals
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : CalculateEdgeNormals
= = = = = = = = = = = = = = = =
*/
# define SHARP_EDGE_DOT -0.7f
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : CalculateEdgeNormals ( cm_model_t * model , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
cm_edge_t * edge ;
2012-11-26 18:58:24 +00:00
float dot , s ;
int i , edgeNum ;
idVec3 dir ;
2012-11-28 15:47:07 +00:00
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
// if we checked this polygon already
2012-11-28 15:47:07 +00:00
if ( p - > checkcount = = checkCount )
{
2012-11-26 18:58:24 +00:00
continue ;
}
p - > checkcount = checkCount ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
edgeNum = p - > edges [ i ] ;
edge = model - > edges + abs ( edgeNum ) ;
2012-11-28 15:47:07 +00:00
if ( edge - > normal [ 0 ] = = 0.0f & & edge - > normal [ 1 ] = = 0.0f & & edge - > normal [ 2 ] = = 0.0f )
{
2012-11-26 18:58:24 +00:00
// if the edge is only used by this polygon
2012-11-28 15:47:07 +00:00
if ( edge - > numUsers = = 1 )
{
2012-11-26 18:58:24 +00:00
dir = model - > vertices [ edge - > vertexNum [ edgeNum < 0 ] ] . p - model - > vertices [ edge - > vertexNum [ edgeNum > 0 ] ] . p ;
edge - > normal = p - > plane . Normal ( ) . Cross ( dir ) ;
edge - > normal . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// the edge is used by more than one polygon
edge - > normal = p - > plane . Normal ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
dot = edge - > normal * p - > plane . Normal ( ) ;
// if the two planes make a very sharp edge
2012-11-28 15:47:07 +00:00
if ( dot < SHARP_EDGE_DOT )
{
2012-11-26 18:58:24 +00:00
// max length normal pointing outside both polygons
dir = model - > vertices [ edge - > vertexNum [ edgeNum > 0 ] ] . p - model - > vertices [ edge - > vertexNum [ edgeNum < 0 ] ] . p ;
edge - > normal = edge - > normal . Cross ( dir ) + p - > plane . Normal ( ) . Cross ( - dir ) ;
edge - > normal * = ( 0.5f / ( 0.5f + 0.5f * SHARP_EDGE_DOT ) ) / edge - > normal . Length ( ) ;
model - > numSharpEdges + + ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
s = 0.5f / ( 0.5f + 0.5f * dot ) ;
edge - > normal = s * ( edge - > normal + p - > plane . Normal ( ) ) ;
}
}
}
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
CalculateEdgeNormals ( model , node - > children [ 1 ] ) ;
node = node - > children [ 0 ] ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Trace model to general collision model
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AllocModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_model_t * idCollisionModelManagerLocal : : AllocModel ( )
{
cm_model_t * model ;
model = new ( TAG_COLLISION ) cm_model_t ;
2012-11-26 18:58:24 +00:00
model - > contents = 0 ;
model - > isConvex = false ;
model - > maxVertices = 0 ;
model - > numVertices = 0 ;
model - > vertices = NULL ;
model - > maxEdges = 0 ;
model - > numEdges = 0 ;
2012-11-28 15:47:07 +00:00
model - > edges = NULL ;
2012-11-26 18:58:24 +00:00
model - > node = NULL ;
model - > nodeBlocks = NULL ;
model - > polygonRefBlocks = NULL ;
model - > brushRefBlocks = NULL ;
model - > polygonBlock = NULL ;
model - > brushBlock = NULL ;
model - > numPolygons = model - > polygonMemory =
2012-11-28 15:47:07 +00:00
model - > numBrushes = model - > brushMemory =
model - > numNodes = model - > numBrushRefs =
model - > numPolygonRefs = model - > numInternalEdges =
model - > numSharpEdges = model - > numRemovedPolys =
model - > numMergedPolys = model - > usedMemory = 0 ;
2012-11-26 18:58:24 +00:00
return model ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AllocNode
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_node_t * idCollisionModelManagerLocal : : AllocNode ( cm_model_t * model , int blockSize )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
cm_node_t * node ;
cm_nodeBlock_t * nodeBlock ;
if ( ! model - > nodeBlocks | | ! model - > nodeBlocks - > nextNode )
{
nodeBlock = ( cm_nodeBlock_t * ) Mem_ClearedAlloc ( sizeof ( cm_nodeBlock_t ) + blockSize * sizeof ( cm_node_t ) , TAG_COLLISION ) ;
nodeBlock - > nextNode = ( cm_node_t * ) ( ( ( byte * ) nodeBlock ) + sizeof ( cm_nodeBlock_t ) ) ;
2012-11-26 18:58:24 +00:00
nodeBlock - > next = model - > nodeBlocks ;
model - > nodeBlocks = nodeBlock ;
node = nodeBlock - > nextNode ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < blockSize - 1 ; i + + )
{
2012-11-26 18:58:24 +00:00
node - > parent = node + 1 ;
node = node - > parent ;
}
node - > parent = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
node = model - > nodeBlocks - > nextNode ;
model - > nodeBlocks - > nextNode = node - > parent ;
node - > parent = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return node ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AllocPolygonReference
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_polygonRef_t * idCollisionModelManagerLocal : : AllocPolygonReference ( cm_model_t * model , int blockSize )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
cm_polygonRef_t * pref ;
cm_polygonRefBlock_t * prefBlock ;
if ( ! model - > polygonRefBlocks | | ! model - > polygonRefBlocks - > nextRef )
{
prefBlock = ( cm_polygonRefBlock_t * ) Mem_ClearedAlloc ( sizeof ( cm_polygonRefBlock_t ) + blockSize * sizeof ( cm_polygonRef_t ) , TAG_COLLISION ) ;
prefBlock - > nextRef = ( cm_polygonRef_t * ) ( ( ( byte * ) prefBlock ) + sizeof ( cm_polygonRefBlock_t ) ) ;
2012-11-26 18:58:24 +00:00
prefBlock - > next = model - > polygonRefBlocks ;
model - > polygonRefBlocks = prefBlock ;
pref = prefBlock - > nextRef ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < blockSize - 1 ; i + + )
{
2012-11-26 18:58:24 +00:00
pref - > next = pref + 1 ;
pref = pref - > next ;
}
pref - > next = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
pref = model - > polygonRefBlocks - > nextRef ;
model - > polygonRefBlocks - > nextRef = pref - > next ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return pref ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AllocBrushReference
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_brushRef_t * idCollisionModelManagerLocal : : AllocBrushReference ( cm_model_t * model , int blockSize )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
cm_brushRef_t * bref ;
cm_brushRefBlock_t * brefBlock ;
if ( ! model - > brushRefBlocks | | ! model - > brushRefBlocks - > nextRef )
{
brefBlock = ( cm_brushRefBlock_t * ) Mem_ClearedAlloc ( sizeof ( cm_brushRefBlock_t ) + blockSize * sizeof ( cm_brushRef_t ) , TAG_COLLISION ) ;
brefBlock - > nextRef = ( cm_brushRef_t * ) ( ( ( byte * ) brefBlock ) + sizeof ( cm_brushRefBlock_t ) ) ;
2012-11-26 18:58:24 +00:00
brefBlock - > next = model - > brushRefBlocks ;
model - > brushRefBlocks = brefBlock ;
bref = brefBlock - > nextRef ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < blockSize - 1 ; i + + )
{
2012-11-26 18:58:24 +00:00
bref - > next = bref + 1 ;
bref = bref - > next ;
}
bref - > next = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bref = model - > brushRefBlocks - > nextRef ;
model - > brushRefBlocks - > nextRef = bref - > next ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return bref ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AllocPolygon
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_polygon_t * idCollisionModelManagerLocal : : AllocPolygon ( cm_model_t * model , int numEdges )
{
cm_polygon_t * poly ;
2012-11-26 18:58:24 +00:00
int size ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
size = sizeof ( cm_polygon_t ) + ( numEdges - 1 ) * sizeof ( poly - > edges [ 0 ] ) ;
model - > numPolygons + + ;
model - > polygonMemory + = size ;
2012-11-28 15:47:07 +00:00
if ( model - > polygonBlock & & model - > polygonBlock - > bytesRemaining > = size )
{
poly = ( cm_polygon_t * ) model - > polygonBlock - > next ;
2012-11-26 18:58:24 +00:00
model - > polygonBlock - > next + = size ;
model - > polygonBlock - > bytesRemaining - = size ;
2012-11-28 15:47:07 +00:00
}
else
{
poly = ( cm_polygon_t * ) Mem_ClearedAlloc ( size , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
}
return poly ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AllocBrush
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_brush_t * idCollisionModelManagerLocal : : AllocBrush ( cm_model_t * model , int numPlanes )
{
cm_brush_t * brush ;
2012-11-26 18:58:24 +00:00
int size ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
size = sizeof ( cm_brush_t ) + ( numPlanes - 1 ) * sizeof ( brush - > planes [ 0 ] ) ;
model - > numBrushes + + ;
model - > brushMemory + = size ;
2012-11-28 15:47:07 +00:00
if ( model - > brushBlock & & model - > brushBlock - > bytesRemaining > = size )
{
brush = ( cm_brush_t * ) model - > brushBlock - > next ;
2012-11-26 18:58:24 +00:00
model - > brushBlock - > next + = size ;
model - > brushBlock - > bytesRemaining - = size ;
2012-11-28 15:47:07 +00:00
}
else
{
brush = ( cm_brush_t * ) Mem_ClearedAlloc ( size , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
}
return brush ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AddPolygonToNode
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : AddPolygonToNode ( cm_model_t * model , cm_node_t * node , cm_polygon_t * p )
{
cm_polygonRef_t * pref ;
2012-11-26 18:58:24 +00:00
pref = AllocPolygonReference ( model , model - > numPolygonRefs < REFERENCE_BLOCK_SIZE_SMALL ? REFERENCE_BLOCK_SIZE_SMALL : REFERENCE_BLOCK_SIZE_LARGE ) ;
pref - > p = p ;
pref - > next = node - > polygons ;
node - > polygons = pref ;
model - > numPolygonRefs + + ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AddBrushToNode
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : AddBrushToNode ( cm_model_t * model , cm_node_t * node , cm_brush_t * b )
{
cm_brushRef_t * bref ;
2012-11-26 18:58:24 +00:00
bref = AllocBrushReference ( model , model - > numBrushRefs < REFERENCE_BLOCK_SIZE_SMALL ? REFERENCE_BLOCK_SIZE_SMALL : REFERENCE_BLOCK_SIZE_LARGE ) ;
bref - > b = b ;
bref - > next = node - > brushes ;
node - > brushes = bref ;
model - > numBrushRefs + + ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : SetupTrmModelStructure
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : SetupTrmModelStructure ( )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
cm_node_t * node ;
cm_model_t * model ;
2012-11-26 18:58:24 +00:00
// setup model
model = AllocModel ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( models ) ;
models [ MAX_SUBMODELS ] = model ;
// create node to hold the collision data
2012-11-28 15:47:07 +00:00
node = ( cm_node_t * ) AllocNode ( model , 1 ) ;
2012-11-26 18:58:24 +00:00
node - > planeType = - 1 ;
model - > node = node ;
// allocate vertex and edge arrays
model - > numVertices = 0 ;
model - > maxVertices = MAX_TRACEMODEL_VERTS ;
2012-11-28 15:47:07 +00:00
model - > vertices = ( cm_vertex_t * ) Mem_ClearedAlloc ( model - > maxVertices * sizeof ( cm_vertex_t ) , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
model - > numEdges = 0 ;
2012-11-28 15:47:07 +00:00
model - > maxEdges = MAX_TRACEMODEL_EDGES + 1 ;
model - > edges = ( cm_edge_t * ) Mem_ClearedAlloc ( model - > maxEdges * sizeof ( cm_edge_t ) , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
// create a material for the trace model polygons
trmMaterial = declManager - > FindMaterial ( " _tracemodel " , false ) ;
2012-11-28 15:47:07 +00:00
if ( ! trmMaterial )
{
2012-11-26 18:58:24 +00:00
common - > FatalError ( " _tracemodel material not found " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// allocate polygons
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < MAX_TRACEMODEL_POLYS ; i + + )
{
2012-11-26 18:58:24 +00:00
trmPolygons [ i ] = AllocPolygonReference ( model , MAX_TRACEMODEL_POLYS ) ;
trmPolygons [ i ] - > p = AllocPolygon ( model , MAX_TRACEMODEL_POLYEDGES ) ;
trmPolygons [ i ] - > p - > bounds . Clear ( ) ;
trmPolygons [ i ] - > p - > plane . Zero ( ) ;
trmPolygons [ i ] - > p - > checkcount = 0 ;
trmPolygons [ i ] - > p - > contents = - 1 ; // all contents
trmPolygons [ i ] - > p - > material = trmMaterial ;
trmPolygons [ i ] - > p - > numEdges = 0 ;
}
// allocate brush for position test
trmBrushes [ 0 ] = AllocBrushReference ( model , 1 ) ;
trmBrushes [ 0 ] - > b = AllocBrush ( model , MAX_TRACEMODEL_POLYS ) ;
trmBrushes [ 0 ] - > b - > primitiveNum = 0 ;
trmBrushes [ 0 ] - > b - > bounds . Clear ( ) ;
trmBrushes [ 0 ] - > b - > checkcount = 0 ;
trmBrushes [ 0 ] - > b - > contents = - 1 ; // all contents
trmBrushes [ 0 ] - > b - > material = trmMaterial ;
trmBrushes [ 0 ] - > b - > numPlanes = 0 ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : SetupTrmModel
Trace models ( item boxes , etc ) are converted to collision models on the fly , using the last model slot
as a reusable temporary buffer
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cmHandle_t idCollisionModelManagerLocal : : SetupTrmModel ( const idTraceModel & trm , const idMaterial * material )
{
2012-11-26 18:58:24 +00:00
int i , j ;
2012-11-28 15:47:07 +00:00
cm_vertex_t * vertex ;
cm_edge_t * edge ;
cm_polygon_t * poly ;
cm_model_t * model ;
const traceModelVert_t * trmVert ;
const traceModelEdge_t * trmEdge ;
const traceModelPoly_t * trmPoly ;
2012-11-26 18:58:24 +00:00
assert ( models ) ;
2012-11-28 15:47:07 +00:00
if ( material = = NULL )
{
2012-11-26 18:58:24 +00:00
material = trmMaterial ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model = models [ MAX_SUBMODELS ] ;
model - > node - > brushes = NULL ;
model - > node - > polygons = NULL ;
// if not a valid trace model
2012-11-28 15:47:07 +00:00
if ( trm . type = = TRM_INVALID | | ! trm . numPolys )
{
2012-11-26 18:58:24 +00:00
return TRACE_MODEL_HANDLE ;
}
// vertices
model - > numVertices = trm . numVerts ;
vertex = model - > vertices ;
trmVert = trm . verts ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < trm . numVerts ; i + + , vertex + + , trmVert + + )
{
2012-11-26 18:58:24 +00:00
vertex - > p = * trmVert ;
vertex - > sideSet = 0 ;
}
// edges
model - > numEdges = trm . numEdges ;
edge = model - > edges + 1 ;
trmEdge = trm . edges + 1 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < trm . numEdges ; i + + , edge + + , trmEdge + + )
{
2012-11-26 18:58:24 +00:00
edge - > vertexNum [ 0 ] = trmEdge - > v [ 0 ] ;
edge - > vertexNum [ 1 ] = trmEdge - > v [ 1 ] ;
edge - > normal = trmEdge - > normal ;
edge - > internal = false ;
edge - > sideSet = 0 ;
}
// polygons
model - > numPolygons = trm . numPolys ;
trmPoly = trm . polys ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < trm . numPolys ; i + + , trmPoly + + )
{
2012-11-26 18:58:24 +00:00
poly = trmPolygons [ i ] - > p ;
poly - > numEdges = trmPoly - > numEdges ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < trmPoly - > numEdges ; j + + )
{
2012-11-26 18:58:24 +00:00
poly - > edges [ j ] = trmPoly - > edges [ j ] ;
}
poly - > plane . SetNormal ( trmPoly - > normal ) ;
poly - > plane . SetDist ( trmPoly - > dist ) ;
poly - > bounds = trmPoly - > bounds ;
poly - > material = material ;
// link polygon at node
trmPolygons [ i ] - > next = model - > node - > polygons ;
model - > node - > polygons = trmPolygons [ i ] ;
}
// if the trace model is convex
2012-11-28 15:47:07 +00:00
if ( trm . isConvex )
{
2012-11-26 18:58:24 +00:00
// setup brush for position test
trmBrushes [ 0 ] - > b - > numPlanes = trm . numPolys ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < trm . numPolys ; i + + )
{
2012-11-26 18:58:24 +00:00
trmBrushes [ 0 ] - > b - > planes [ i ] = trmPolygons [ i ] - > p - > plane ;
}
trmBrushes [ 0 ] - > b - > bounds = trm . bounds ;
// link brush at node
trmBrushes [ 0 ] - > next = model - > node - > brushes ;
trmBrushes [ 0 ] - > b - > material = material ;
model - > node - > brushes = trmBrushes [ 0 ] ;
}
// model bounds
model - > bounds = trm . bounds ;
// convex
model - > isConvex = trm . isConvex ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return TRACE_MODEL_HANDLE ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Optimisation , removal of polygons contained within brushes or solid
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = =
idCollisionModelManagerLocal : : R_ChoppedAwayByProcBSP
= = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idCollisionModelManagerLocal : : R_ChoppedAwayByProcBSP ( int nodeNum , idFixedWinding * w , const idVec3 & normal , const idVec3 & origin , const float radius )
{
2012-11-26 18:58:24 +00:00
int res ;
idFixedWinding back ;
2012-11-28 15:47:07 +00:00
cm_procNode_t * node ;
2012-11-26 18:58:24 +00:00
float dist ;
2012-11-28 15:47:07 +00:00
do
{
2012-11-26 18:58:24 +00:00
node = procNodes + nodeNum ;
dist = node - > plane . Normal ( ) * origin + node - > plane [ 3 ] ;
2012-11-28 15:47:07 +00:00
if ( dist > radius )
{
2012-11-26 18:58:24 +00:00
res = SIDE_FRONT ;
}
2012-11-28 15:47:07 +00:00
else if ( dist < - radius )
{
2012-11-26 18:58:24 +00:00
res = SIDE_BACK ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
res = w - > Split ( & back , node - > plane , CHOP_EPSILON ) ;
}
2012-11-28 15:47:07 +00:00
if ( res = = SIDE_FRONT )
{
2012-11-26 18:58:24 +00:00
nodeNum = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( res = = SIDE_BACK )
{
2012-11-26 18:58:24 +00:00
nodeNum = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( res = = SIDE_ON )
{
2012-11-26 18:58:24 +00:00
// continue with the side the winding faces
2012-11-28 15:47:07 +00:00
if ( node - > plane . Normal ( ) * normal > 0.0f )
{
2012-11-26 18:58:24 +00:00
nodeNum = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
nodeNum = node - > children [ 1 ] ;
}
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
// if either node is not solid
2012-11-28 15:47:07 +00:00
if ( node - > children [ 0 ] < 0 | | node - > children [ 1 ] < 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
// only recurse if the node is not solid
2012-11-28 15:47:07 +00:00
if ( node - > children [ 1 ] > 0 )
{
if ( ! R_ChoppedAwayByProcBSP ( node - > children [ 1 ] , & back , normal , origin , radius ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
}
nodeNum = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
}
while ( nodeNum > 0 ) ;
if ( nodeNum < 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
return true ;
}
/*
= = = = = = = = = = = =
idCollisionModelManagerLocal : : ChoppedAwayByProcBSP
= = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idCollisionModelManagerLocal : : ChoppedAwayByProcBSP ( const idFixedWinding & w , const idPlane & plane , int contents )
{
2012-11-26 18:58:24 +00:00
idFixedWinding neww ;
idBounds bounds ;
float radius ;
idVec3 origin ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the .proc file has no BSP tree
2012-11-28 15:47:07 +00:00
if ( procNodes = = NULL )
{
2012-11-26 18:58:24 +00:00
return false ;
}
// don't chop if the polygon is not solid
2012-11-28 15:47:07 +00:00
if ( ! ( contents & CONTENTS_SOLID ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
// make a local copy of the winding
neww = w ;
neww . GetBounds ( bounds ) ;
2012-11-28 15:47:07 +00:00
origin = ( bounds [ 1 ] - bounds [ 0 ] ) * 0.5f ;
2012-11-26 18:58:24 +00:00
radius = origin . Length ( ) + CHOP_EPSILON ;
origin = bounds [ 0 ] + origin ;
//
return R_ChoppedAwayByProcBSP ( 0 , & neww , plane . Normal ( ) , origin , radius ) ;
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : ChopWindingWithBrush
returns the least number of winding fragments outside the brush
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ChopWindingListWithBrush ( cm_windingList_t * list , cm_brush_t * b )
{
2012-11-26 18:58:24 +00:00
int i , k , res , startPlane , planeNum , bestNumWindings ;
idFixedWinding back , front ;
idPlane plane ;
bool chopped ;
int sidedness [ MAX_POINTS_ON_WINDING ] ;
float dist ;
2012-11-28 15:47:07 +00:00
if ( b - > numPlanes > MAX_POINTS_ON_WINDING )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get sidedness for the list of windings
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < b - > numPlanes ; i + + )
{
2012-11-26 18:58:24 +00:00
plane = - b - > planes [ i ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
dist = plane . Distance ( list - > origin ) ;
2012-11-28 15:47:07 +00:00
if ( dist > list - > radius )
{
2012-11-26 18:58:24 +00:00
sidedness [ i ] = SIDE_FRONT ;
}
2012-11-28 15:47:07 +00:00
else if ( dist < - list - > radius )
{
2012-11-26 18:58:24 +00:00
sidedness [ i ] = SIDE_BACK ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
sidedness [ i ] = list - > bounds . PlaneSide ( plane ) ;
2012-11-28 15:47:07 +00:00
if ( sidedness [ i ] = = PLANESIDE_FRONT )
{
2012-11-26 18:58:24 +00:00
sidedness [ i ] = SIDE_FRONT ;
}
2012-11-28 15:47:07 +00:00
else if ( sidedness [ i ] = = PLANESIDE_BACK )
{
2012-11-26 18:58:24 +00:00
sidedness [ i ] = SIDE_BACK ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
sidedness [ i ] = SIDE_CROSS ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_outList - > numWindings = 0 ;
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < list - > numWindings ; k + + )
{
2012-11-26 18:58:24 +00:00
//
startPlane = 0 ;
bestNumWindings = 1 + b - > numPlanes ;
chopped = false ;
2012-11-28 15:47:07 +00:00
do
{
2012-11-26 18:58:24 +00:00
front = list - > w [ k ] ;
cm_tmpList - > numWindings = 0 ;
2012-11-28 15:47:07 +00:00
for ( planeNum = startPlane , i = 0 ; i < b - > numPlanes ; i + + , planeNum + + )
{
if ( planeNum > = b - > numPlanes )
{
2012-11-26 18:58:24 +00:00
planeNum = 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
res = sidedness [ planeNum ] ;
2012-11-28 15:47:07 +00:00
if ( res = = SIDE_CROSS )
{
2012-11-26 18:58:24 +00:00
plane = - b - > planes [ planeNum ] ;
res = front . Split ( & back , plane , CHOP_EPSILON ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// NOTE: disabling this can create gaps at places where Z-fighting occurs
// Z-fighting should not occur but what if there is a decal brush side
// with exactly the same size as another brush side ?
// only leave windings on a brush if the winding plane and brush side plane face the same direction
2012-11-28 15:47:07 +00:00
if ( res = = SIDE_ON & & list - > primitiveNum > = 0 & & ( list - > normal * b - > planes [ planeNum ] . Normal ( ) ) > 0 )
{
2012-11-26 18:58:24 +00:00
// return because all windings in the list will be on this brush side plane
return ;
}
2012-11-28 15:47:07 +00:00
if ( res = = SIDE_BACK )
{
if ( cm_outList - > numWindings > = MAX_WINDING_LIST )
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::ChopWindingWithBrush: primitive %d more than %d windings " , list - > primitiveNum , MAX_WINDING_LIST ) ;
return ;
}
// winding and brush didn't intersect, store the original winding
cm_outList - > w [ cm_outList - > numWindings ] = list - > w [ k ] ;
cm_outList - > numWindings + + ;
chopped = false ;
break ;
}
2012-11-28 15:47:07 +00:00
if ( res = = SIDE_CROSS )
{
if ( cm_tmpList - > numWindings > = MAX_WINDING_LIST )
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::ChopWindingWithBrush: primitive %d more than %d windings " , list - > primitiveNum , MAX_WINDING_LIST ) ;
return ;
}
// store the front winding in the temporary list
cm_tmpList - > w [ cm_tmpList - > numWindings ] = back ;
cm_tmpList - > numWindings + + ;
chopped = true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if already found a start plane which generates less fragments
2012-11-28 15:47:07 +00:00
if ( cm_tmpList - > numWindings > = bestNumWindings )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// find the best start plane to get the least number of fragments outside the brush
2012-11-28 15:47:07 +00:00
if ( cm_tmpList - > numWindings < bestNumWindings )
{
2012-11-26 18:58:24 +00:00
bestNumWindings = cm_tmpList - > numWindings ;
// store windings from temporary list in the out list
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < cm_tmpList - > numWindings ; i + + )
{
if ( cm_outList - > numWindings + i > = MAX_WINDING_LIST )
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::ChopWindingWithBrush: primitive %d more than %d windings " , list - > primitiveNum , MAX_WINDING_LIST ) ;
return ;
}
2012-11-28 15:47:07 +00:00
cm_outList - > w [ cm_outList - > numWindings + i ] = cm_tmpList - > w [ i ] ;
2012-11-26 18:58:24 +00:00
}
// if only one winding left then we can't do any better
2012-11-28 15:47:07 +00:00
if ( bestNumWindings = = 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// try the next start plane
startPlane + + ;
2012-11-28 15:47:07 +00:00
}
while ( chopped & & startPlane < b - > numPlanes ) ;
2012-11-26 18:58:24 +00:00
//
2012-11-28 15:47:07 +00:00
if ( chopped )
{
2012-11-26 18:58:24 +00:00
cm_outList - > numWindings + = bestNumWindings ;
}
}
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < cm_outList - > numWindings ; k + + )
{
2012-11-26 18:58:24 +00:00
list - > w [ k ] = cm_outList - > w [ k ] ;
}
list - > numWindings = cm_outList - > numWindings ;
}
/*
= = = = = = = = = = = =
idCollisionModelManagerLocal : : R_ChopWindingListWithTreeBrushes
= = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : R_ChopWindingListWithTreeBrushes ( cm_windingList_t * list , cm_node_t * node )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
cm_brushRef_t * bref ;
cm_brush_t * b ;
while ( 1 )
{
for ( bref = node - > brushes ; bref ; bref = bref - > next )
{
2012-11-26 18:58:24 +00:00
b = bref - > b ;
// if we checked this brush already
2012-11-28 15:47:07 +00:00
if ( b - > checkcount = = checkCount )
{
2012-11-26 18:58:24 +00:00
continue ;
}
b - > checkcount = checkCount ;
// if the windings in the list originate from this brush
2012-11-28 15:47:07 +00:00
if ( b - > primitiveNum = = list - > primitiveNum )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// if brush has a different contents
2012-11-28 15:47:07 +00:00
if ( b - > contents ! = list - > contents )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// brush bounds and winding list bounds should overlap
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
if ( list - > bounds [ 0 ] [ i ] > b - > bounds [ 1 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( list - > bounds [ 1 ] [ i ] < b - > bounds [ 0 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( i < 3 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// chop windings in the list with brush
ChopWindingListWithBrush ( list , b ) ;
// if all windings are chopped away we're done
2012-11-28 15:47:07 +00:00
if ( ! list - > numWindings )
{
2012-11-26 18:58:24 +00:00
return ;
}
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( list - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( list - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
R_ChopWindingListWithTreeBrushes ( list , node - > children [ 1 ] ) ;
2012-11-28 15:47:07 +00:00
if ( ! list - > numWindings )
{
2012-11-26 18:58:24 +00:00
return ;
}
node = node - > children [ 0 ] ;
}
}
}
/*
= = = = = = = = = = = =
idCollisionModelManagerLocal : : WindingOutsideBrushes
Returns one winding which is not fully contained in brushes .
We always favor less polygons over a stitched world .
If the winding is partly contained and the contained pieces can be chopped off
without creating multiple winding fragments then the chopped winding is returned .
= = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idFixedWinding * idCollisionModelManagerLocal : : WindingOutsideBrushes ( idFixedWinding * w , const idPlane & plane , int contents , int primitiveNum , cm_node_t * headNode )
{
2012-11-26 18:58:24 +00:00
int i , windingLeft ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_windingList - > bounds . Clear ( ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < w - > GetNumPoints ( ) ; i + + )
{
cm_windingList - > bounds . AddPoint ( ( * w ) [ i ] . ToVec3 ( ) ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
cm_windingList - > origin = ( cm_windingList - > bounds [ 1 ] - cm_windingList - > bounds [ 0 ] ) * 0.5 ;
2012-11-26 18:58:24 +00:00
cm_windingList - > radius = cm_windingList - > origin . Length ( ) + CHOP_EPSILON ;
cm_windingList - > origin = cm_windingList - > bounds [ 0 ] + cm_windingList - > origin ;
cm_windingList - > bounds [ 0 ] - = idVec3 ( CHOP_EPSILON , CHOP_EPSILON , CHOP_EPSILON ) ;
cm_windingList - > bounds [ 1 ] + = idVec3 ( CHOP_EPSILON , CHOP_EPSILON , CHOP_EPSILON ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_windingList - > w [ 0 ] = * w ;
cm_windingList - > numWindings = 1 ;
cm_windingList - > normal = plane . Normal ( ) ;
cm_windingList - > contents = contents ;
cm_windingList - > primitiveNum = primitiveNum ;
//
checkCount + + ;
R_ChopWindingListWithTreeBrushes ( cm_windingList , headNode ) ;
//
2012-11-28 15:47:07 +00:00
if ( ! cm_windingList - > numWindings )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( cm_windingList - > numWindings = = 1 )
{
2012-11-26 18:58:24 +00:00
return & cm_windingList - > w [ 0 ] ;
}
// if not the world model
2012-11-28 15:47:07 +00:00
if ( numModels ! = 0 )
{
2012-11-26 18:58:24 +00:00
return w ;
}
// check if winding fragments would be chopped away by the proc BSP tree
windingLeft = - 1 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < cm_windingList - > numWindings ; i + + )
{
if ( ! ChoppedAwayByProcBSP ( cm_windingList - > w [ i ] , plane , contents ) )
{
if ( windingLeft > = 0 )
{
2012-11-26 18:58:24 +00:00
return w ;
}
windingLeft = i ;
}
}
2012-11-28 15:47:07 +00:00
if ( windingLeft > = 0 )
{
2012-11-26 18:58:24 +00:00
return & cm_windingList - > w [ windingLeft ] ;
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Merging polygons
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : ReplacePolygons
does not allow for a node to have multiple references to the same polygon
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ReplacePolygons ( cm_model_t * model , cm_node_t * node , cm_polygon_t * p1 , cm_polygon_t * p2 , cm_polygon_t * newp )
{
cm_polygonRef_t * pref , * lastpref , * nextpref ;
cm_polygon_t * p ;
2012-11-26 18:58:24 +00:00
bool linked ;
2012-11-28 15:47:07 +00:00
while ( 1 )
{
2012-11-26 18:58:24 +00:00
linked = false ;
lastpref = NULL ;
2012-11-28 15:47:07 +00:00
for ( pref = node - > polygons ; pref ; pref = nextpref )
{
2012-11-26 18:58:24 +00:00
nextpref = pref - > next ;
//
p = pref - > p ;
// if this polygon reference should change
2012-11-28 15:47:07 +00:00
if ( p = = p1 | | p = = p2 )
{
2012-11-26 18:58:24 +00:00
// if the new polygon is already linked at this node
2012-11-28 15:47:07 +00:00
if ( linked )
{
if ( lastpref )
{
2012-11-26 18:58:24 +00:00
lastpref - > next = nextpref ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
node - > polygons = nextpref ;
}
FreePolygonReference ( pref ) ;
model - > numPolygonRefs - - ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
pref - > p = newp ;
linked = true ;
lastpref = pref ;
}
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
lastpref = pref ;
}
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( p1 - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist & & p2 - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( p1 - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist & & p2 - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
ReplacePolygons ( model , node - > children [ 1 ] , p1 , p2 , newp ) ;
node = node - > children [ 0 ] ;
}
}
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : TryMergePolygons
= = = = = = = = = = = = =
*/
# define CONTINUOUS_EPSILON 0.005f
# define NORMAL_EPSILON 0.01f
2012-11-28 15:47:07 +00:00
cm_polygon_t * idCollisionModelManagerLocal : : TryMergePolygons ( cm_model_t * model , cm_polygon_t * p1 , cm_polygon_t * p2 )
{
2012-11-26 18:58:24 +00:00
int i , j , nexti , prevj ;
int p1BeforeShare , p1AfterShare , p2BeforeShare , p2AfterShare ;
int newEdges [ CM_MAX_POLYGON_EDGES ] , newNumEdges ;
int edgeNum , edgeNum1 , edgeNum2 , newEdgeNum1 , newEdgeNum2 ;
2012-11-28 15:47:07 +00:00
cm_edge_t * edge ;
cm_polygon_t * newp ;
2012-11-26 18:58:24 +00:00
idVec3 delta , normal ;
float dot ;
bool keep1 , keep2 ;
2012-11-28 15:47:07 +00:00
if ( p1 - > material ! = p2 - > material )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( idMath : : Fabs ( p1 - > plane . Dist ( ) - p2 - > plane . Dist ( ) ) > NORMAL_EPSILON )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
if ( idMath : : Fabs ( p1 - > plane . Normal ( ) [ i ] - p2 - > plane . Normal ( ) [ i ] ) > NORMAL_EPSILON )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( p1 - > bounds [ 0 ] [ i ] > p2 - > bounds [ 1 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( p1 - > bounds [ 1 ] [ i ] < p2 - > bounds [ 0 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
}
// this allows for merging polygons with multiple shared edges
// polygons with multiple shared edges probably never occur tho ;)
p1BeforeShare = p1AfterShare = p2BeforeShare = p2AfterShare = - 1 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p1 - > numEdges ; i + + )
{
nexti = ( i + 1 ) % p1 - > numEdges ;
for ( j = 0 ; j < p2 - > numEdges ; j + + )
{
prevj = ( j + p2 - > numEdges - 1 ) % p2 - > numEdges ;
2012-11-26 18:58:24 +00:00
//
2012-11-28 15:47:07 +00:00
if ( abs ( p1 - > edges [ i ] ) ! = abs ( p2 - > edges [ j ] ) )
{
2012-11-26 18:58:24 +00:00
// if the next edge of p1 and the previous edge of p2 are the same
2012-11-28 15:47:07 +00:00
if ( abs ( p1 - > edges [ nexti ] ) = = abs ( p2 - > edges [ prevj ] ) )
{
2012-11-26 18:58:24 +00:00
// if both polygons don't use the edge in the same direction
2012-11-28 15:47:07 +00:00
if ( p1 - > edges [ nexti ] ! = p2 - > edges [ prevj ] )
{
2012-11-26 18:58:24 +00:00
p1BeforeShare = i ;
p2AfterShare = j ;
}
break ;
}
}
// if both polygons don't use the edge in the same direction
2012-11-28 15:47:07 +00:00
else if ( p1 - > edges [ i ] ! = p2 - > edges [ j ] )
{
2012-11-26 18:58:24 +00:00
// if the next edge of p1 and the previous edge of p2 are not the same
2012-11-28 15:47:07 +00:00
if ( abs ( p1 - > edges [ nexti ] ) ! = abs ( p2 - > edges [ prevj ] ) )
{
2012-11-26 18:58:24 +00:00
p1AfterShare = nexti ;
p2BeforeShare = prevj ;
break ;
}
}
}
}
2012-11-28 15:47:07 +00:00
if ( p1BeforeShare < 0 | | p1AfterShare < 0 | | p2BeforeShare < 0 | | p2AfterShare < 0 )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check if the new polygon would still be convex
edgeNum = p1 - > edges [ p1BeforeShare ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
delta = model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p -
model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
2012-11-26 18:58:24 +00:00
normal = p1 - > plane . Normal ( ) . Cross ( delta ) ;
normal . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
edgeNum = p2 - > edges [ p2AfterShare ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
delta = model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p -
model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
2012-11-26 18:58:24 +00:00
dot = delta * normal ;
2012-11-28 15:47:07 +00:00
if ( dot < - CONTINUOUS_EPSILON )
2012-11-26 18:58:24 +00:00
return NULL ; // not a convex polygon
2012-11-28 15:47:07 +00:00
keep1 = ( bool ) ( dot > CONTINUOUS_EPSILON ) ;
2012-11-26 18:58:24 +00:00
edgeNum = p2 - > edges [ p2BeforeShare ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
delta = model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p -
model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
2012-11-26 18:58:24 +00:00
normal = p1 - > plane . Normal ( ) . Cross ( delta ) ;
normal . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
edgeNum = p1 - > edges [ p1AfterShare ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
delta = model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p -
model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
2012-11-26 18:58:24 +00:00
dot = delta * normal ;
2012-11-28 15:47:07 +00:00
if ( dot < - CONTINUOUS_EPSILON )
2012-11-26 18:58:24 +00:00
return NULL ; // not a convex polygon
2012-11-28 15:47:07 +00:00
keep2 = ( bool ) ( dot > CONTINUOUS_EPSILON ) ;
2012-11-26 18:58:24 +00:00
newEdgeNum1 = newEdgeNum2 = 0 ;
// get new edges if we need to replace colinear ones
2012-11-28 15:47:07 +00:00
if ( ! keep1 )
{
2012-11-26 18:58:24 +00:00
edgeNum1 = p1 - > edges [ p1BeforeShare ] ;
edgeNum2 = p2 - > edges [ p2AfterShare ] ;
2012-11-28 15:47:07 +00:00
GetEdge ( model , model - > vertices [ model - > edges [ abs ( edgeNum1 ) ] . vertexNum [ INT32_SIGNBITSET ( edgeNum1 ) ] ] . p ,
model - > vertices [ model - > edges [ abs ( edgeNum2 ) ] . vertexNum [ INT32_SIGNBITNOTSET ( edgeNum2 ) ] ] . p ,
& newEdgeNum1 , - 1 ) ;
if ( newEdgeNum1 = = 0 )
{
2012-11-26 18:58:24 +00:00
keep1 = true ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! keep2 )
{
2012-11-26 18:58:24 +00:00
edgeNum1 = p2 - > edges [ p2BeforeShare ] ;
edgeNum2 = p1 - > edges [ p1AfterShare ] ;
2012-11-28 15:47:07 +00:00
GetEdge ( model , model - > vertices [ model - > edges [ abs ( edgeNum1 ) ] . vertexNum [ INT32_SIGNBITSET ( edgeNum1 ) ] ] . p ,
model - > vertices [ model - > edges [ abs ( edgeNum2 ) ] . vertexNum [ INT32_SIGNBITNOTSET ( edgeNum2 ) ] ] . p ,
& newEdgeNum2 , - 1 ) ;
if ( newEdgeNum2 = = 0 )
{
2012-11-26 18:58:24 +00:00
keep2 = true ;
}
}
// set edges for new polygon
newNumEdges = 0 ;
2012-11-28 15:47:07 +00:00
if ( ! keep2 )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = newEdgeNum2 ;
}
2012-11-28 15:47:07 +00:00
if ( p1AfterShare < p1BeforeShare )
{
for ( i = p1AfterShare + ( ! keep2 ) ; i < = p1BeforeShare - ( ! keep1 ) ; i + + )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = p1 - > edges [ i ] ;
}
}
2012-11-28 15:47:07 +00:00
else
{
for ( i = p1AfterShare + ( ! keep2 ) ; i < p1 - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = p1 - > edges [ i ] ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < = p1BeforeShare - ( ! keep1 ) ; i + + )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = p1 - > edges [ i ] ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! keep1 )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = newEdgeNum1 ;
}
2012-11-28 15:47:07 +00:00
if ( p2AfterShare < p2BeforeShare )
{
for ( i = p2AfterShare + ( ! keep1 ) ; i < = p2BeforeShare - ( ! keep2 ) ; i + + )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = p2 - > edges [ i ] ;
}
}
2012-11-28 15:47:07 +00:00
else
{
for ( i = p2AfterShare + ( ! keep1 ) ; i < p2 - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = p2 - > edges [ i ] ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < = p2BeforeShare - ( ! keep2 ) ; i + + )
{
2012-11-26 18:58:24 +00:00
newEdges [ newNumEdges + + ] = p2 - > edges [ i ] ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
newp = AllocPolygon ( model , newNumEdges ) ;
2012-11-28 15:47:07 +00:00
memcpy ( newp , p1 , sizeof ( cm_polygon_t ) ) ;
memcpy ( newp - > edges , newEdges , newNumEdges * sizeof ( int ) ) ;
2012-11-26 18:58:24 +00:00
newp - > numEdges = newNumEdges ;
newp - > checkcount = 0 ;
// increase usage count for the edges of this polygon
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < newp - > numEdges ; i + + )
{
if ( ! keep1 & & newp - > edges [ i ] = = newEdgeNum1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! keep2 & & newp - > edges [ i ] = = newEdgeNum2 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
model - > edges [ abs ( newp - > edges [ i ] ) ] . numUsers + + ;
2012-11-26 18:58:24 +00:00
}
// create new bounds from the merged polygons
newp - > bounds = p1 - > bounds + p2 - > bounds ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return newp ;
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : MergePolygonWithTreePolygons
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : MergePolygonWithTreePolygons ( cm_model_t * model , cm_node_t * node , cm_polygon_t * polygon )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
cm_polygonRef_t * pref ;
cm_polygon_t * p , * newp ;
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
//
2012-11-28 15:47:07 +00:00
if ( p = = polygon )
{
2012-11-26 18:58:24 +00:00
continue ;
}
//
newp = TryMergePolygons ( model , polygon , p ) ;
// if polygons were merged
2012-11-28 15:47:07 +00:00
if ( newp )
{
2012-11-26 18:58:24 +00:00
model - > numMergedPolys + + ;
// replace links to the merged polygons with links to the new polygon
ReplacePolygons ( model , model - > node , polygon , p , newp ) ;
// decrease usage count for edges of both merged polygons
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < polygon - > numEdges ; i + + )
{
model - > edges [ abs ( polygon - > edges [ i ] ) ] . numUsers - - ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p - > numEdges ; i + + )
{
model - > edges [ abs ( p - > edges [ i ] ) ] . numUsers - - ;
2012-11-26 18:58:24 +00:00
}
// free merged polygons
FreePolygon ( model , polygon ) ;
FreePolygon ( model , p ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( polygon - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( polygon - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
if ( MergePolygonWithTreePolygons ( model , node - > children [ 1 ] , polygon ) )
{
2012-11-26 18:58:24 +00:00
return true ;
}
node = node - > children [ 0 ] ;
}
}
return false ;
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : MergeTreePolygons
try to merge any two polygons with the same surface flags and the same contents
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : MergeTreePolygons ( cm_model_t * model , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
2012-11-26 18:58:24 +00:00
bool merge ;
2012-11-28 15:47:07 +00:00
while ( 1 )
{
do
{
2012-11-26 18:58:24 +00:00
merge = false ;
2012-11-28 15:47:07 +00:00
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
// if we checked this polygon already
2012-11-28 15:47:07 +00:00
if ( p - > checkcount = = checkCount )
{
2012-11-26 18:58:24 +00:00
continue ;
}
p - > checkcount = checkCount ;
// try to merge this polygon with other polygons in the tree
2012-11-28 15:47:07 +00:00
if ( MergePolygonWithTreePolygons ( model , model - > node , p ) )
{
2012-11-26 18:58:24 +00:00
merge = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
}
while ( merge ) ;
2012-11-26 18:58:24 +00:00
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
MergeTreePolygons ( model , node - > children [ 1 ] ) ;
node = node - > children [ 0 ] ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Find internal edges
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
if ( two polygons have the same contents )
if ( the normals of the two polygon planes face towards each other )
if ( an edge is shared between the polygons )
if ( the edge is not shared in the same direction )
then this is an internal edge
else
if ( this edge is on the plane of the other polygon )
if ( this edge if fully inside the winding of the other polygon )
then this edge is an internal edge
*/
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : PointInsidePolygon
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : PointInsidePolygon ( cm_model_t * model , cm_polygon_t * p , idVec3 & v )
{
2012-11-26 18:58:24 +00:00
int i , edgeNum ;
2012-11-28 15:47:07 +00:00
idVec3 * v1 , * v2 , dir1 , dir2 , vec ;
cm_edge_t * edge ;
for ( i = 0 ; i < p - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
edgeNum = p - > edges [ i ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
2012-11-26 18:58:24 +00:00
//
2012-11-28 15:47:07 +00:00
v1 = & model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
v2 = & model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p ;
dir1 = ( * v2 ) - ( * v1 ) ;
vec = v - ( * v1 ) ;
2012-11-26 18:58:24 +00:00
dir2 = dir1 . Cross ( p - > plane . Normal ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( vec * dir2 > VERTEX_EPSILON )
{
2012-11-26 18:58:24 +00:00
return false ;
}
}
return true ;
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : FindInternalEdgesOnPolygon
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FindInternalEdgesOnPolygon ( cm_model_t * model , cm_polygon_t * p1 , cm_polygon_t * p2 )
{
2012-11-26 18:58:24 +00:00
int i , j , k , edgeNum ;
2012-11-28 15:47:07 +00:00
cm_edge_t * edge ;
idVec3 * v1 , * v2 , dir1 , dir2 ;
2012-11-26 18:58:24 +00:00
float d ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bounds of polygons should overlap or touch
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
if ( p1 - > bounds [ 0 ] [ i ] > p2 - > bounds [ 1 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( p1 - > bounds [ 1 ] [ i ] < p2 - > bounds [ 0 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
return ;
}
}
//
// FIXME: doubled geometry causes problems
//
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p1 - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
edgeNum = p1 - > edges [ i ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
2012-11-26 18:58:24 +00:00
// if already an internal edge
2012-11-28 15:47:07 +00:00
if ( edge - > internal )
{
2012-11-26 18:58:24 +00:00
continue ;
}
//
2012-11-28 15:47:07 +00:00
v1 = & model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
v2 = & model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p ;
2012-11-26 18:58:24 +00:00
// if either of the two vertices is outside the bounds of the other polygon
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < 3 ; k + + )
{
2012-11-26 18:58:24 +00:00
d = p2 - > bounds [ 1 ] [ k ] + VERTEX_EPSILON ;
2012-11-28 15:47:07 +00:00
if ( ( * v1 ) [ k ] > d | | ( * v2 ) [ k ] > d )
{
2012-11-26 18:58:24 +00:00
break ;
}
d = p2 - > bounds [ 0 ] [ k ] - VERTEX_EPSILON ;
2012-11-28 15:47:07 +00:00
if ( ( * v1 ) [ k ] < d | | ( * v2 ) [ k ] < d )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( k < 3 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
//
2012-11-28 15:47:07 +00:00
k = abs ( edgeNum ) ;
for ( j = 0 ; j < p2 - > numEdges ; j + + )
{
if ( k = = abs ( p2 - > edges [ j ] ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
// if the edge is shared between the two polygons
2012-11-28 15:47:07 +00:00
if ( j < p2 - > numEdges )
{
2012-11-26 18:58:24 +00:00
// if the edge is used by more than 2 polygons
2012-11-28 15:47:07 +00:00
if ( edge - > numUsers > 2 )
{
2012-11-26 18:58:24 +00:00
// could still be internal but we'd have to test all polygons using the edge
continue ;
}
// if the edge goes in the same direction for both polygons
2012-11-28 15:47:07 +00:00
if ( edgeNum = = p2 - > edges [ j ] )
{
2012-11-26 18:58:24 +00:00
// the polygons can lay ontop of each other or one can obscure the other
continue ;
}
}
// the edge was not shared
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
// both vertices should be on the plane of the other polygon
d = p2 - > plane . Distance ( * v1 ) ;
2012-11-28 15:47:07 +00:00
if ( idMath : : Fabs ( d ) > VERTEX_EPSILON )
{
2012-11-26 18:58:24 +00:00
continue ;
}
d = p2 - > plane . Distance ( * v2 ) ;
2012-11-28 15:47:07 +00:00
if ( idMath : : Fabs ( d ) > VERTEX_EPSILON )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
// the two polygon plane normals should face towards each other
2012-11-28 15:47:07 +00:00
dir1 = ( * v2 ) - ( * v1 ) ;
2012-11-26 18:58:24 +00:00
dir2 = p1 - > plane . Normal ( ) . Cross ( dir1 ) ;
2012-11-28 15:47:07 +00:00
if ( p2 - > plane . Normal ( ) * dir2 < 0 )
{
2012-11-26 18:58:24 +00:00
//continue;
break ;
}
// if the edge was not shared
2012-11-28 15:47:07 +00:00
if ( j > = p2 - > numEdges )
{
2012-11-26 18:58:24 +00:00
// both vertices of the edge should be inside the winding of the other polygon
2012-11-28 15:47:07 +00:00
if ( ! PointInsidePolygon ( model , p2 , * v1 ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! PointInsidePolygon ( model , p2 , * v2 ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
// we got another internal edge
edge - > internal = true ;
model - > numInternalEdges + + ;
}
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : FindInternalPolygonEdges
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FindInternalPolygonEdges ( cm_model_t * model , cm_node_t * node , cm_polygon_t * polygon )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
if ( polygon - > material - > GetCullType ( ) = = CT_TWO_SIDED | | polygon - > material - > ShouldCreateBackSides ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
//
// FIXME: use some sort of additional checkcount because currently
// polygons can be checked multiple times
//
// if the polygons don't have the same contents
2012-11-28 15:47:07 +00:00
if ( p - > contents ! = polygon - > contents )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( p = = polygon )
{
2012-11-26 18:58:24 +00:00
continue ;
}
FindInternalEdgesOnPolygon ( model , polygon , p ) ;
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( polygon - > bounds [ 0 ] [ node - > planeType ] > node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( polygon - > bounds [ 1 ] [ node - > planeType ] < node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
FindInternalPolygonEdges ( model , node - > children [ 1 ] , polygon ) ;
node = node - > children [ 0 ] ;
}
}
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : FindContainedEdges
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FindContainedEdges ( cm_model_t * model , cm_polygon_t * p )
{
2012-11-26 18:58:24 +00:00
int i , edgeNum ;
2012-11-28 15:47:07 +00:00
cm_edge_t * edge ;
2012-11-26 18:58:24 +00:00
idFixedWinding w ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
edgeNum = p - > edges [ i ] ;
2012-11-28 15:47:07 +00:00
edge = model - > edges + abs ( edgeNum ) ;
if ( edge - > internal )
{
2012-11-26 18:58:24 +00:00
continue ;
}
w . Clear ( ) ;
2012-11-28 15:47:07 +00:00
w + = model - > vertices [ edge - > vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
w + = model - > vertices [ edge - > vertexNum [ INT32_SIGNBITNOTSET ( edgeNum ) ] ] . p ;
if ( ChoppedAwayByProcBSP ( w , p - > plane , p - > contents ) )
{
2012-11-26 18:58:24 +00:00
edge - > internal = true ;
}
}
}
/*
= = = = = = = = = = = = =
idCollisionModelManagerLocal : : FindInternalEdges
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FindInternalEdges ( cm_model_t * model , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
// if we checked this polygon already
2012-11-28 15:47:07 +00:00
if ( p - > checkcount = = checkCount )
{
2012-11-26 18:58:24 +00:00
continue ;
}
p - > checkcount = checkCount ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
FindInternalPolygonEdges ( model , model - > node , p ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//FindContainedEdges( model, p );
}
// if leaf node
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
FindInternalEdges ( model , node - > children [ 1 ] ) ;
node = node - > children [ 0 ] ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Spatial subdivision
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
CM_FindSplitter
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static int CM_FindSplitter ( const cm_node_t * node , const idBounds & bounds , int * planeType , float * planeDist )
{
2012-11-26 18:58:24 +00:00
int i , j , type , axis [ 3 ] , polyCount ;
float dist , t , bestt , size [ 3 ] ;
2012-11-28 15:47:07 +00:00
cm_brushRef_t * bref ;
cm_polygonRef_t * pref ;
const cm_node_t * n ;
2012-11-26 18:58:24 +00:00
bool forceSplit = false ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
2012-11-26 18:58:24 +00:00
size [ i ] = bounds [ 1 ] [ i ] - bounds [ 0 ] [ i ] ;
axis [ i ] = i ;
}
// sort on largest axis
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 2 ; i + + )
{
if ( size [ i ] < size [ i + 1 ] )
{
2012-11-26 18:58:24 +00:00
t = size [ i ] ;
2012-11-28 15:47:07 +00:00
size [ i ] = size [ i + 1 ] ;
size [ i + 1 ] = t ;
2012-11-26 18:58:24 +00:00
j = axis [ i ] ;
2012-11-28 15:47:07 +00:00
axis [ i ] = axis [ i + 1 ] ;
axis [ i + 1 ] = j ;
2012-11-26 18:58:24 +00:00
i = - 1 ;
}
}
// if the node is too small for further splits
2012-11-28 15:47:07 +00:00
if ( size [ 0 ] < MIN_NODE_SIZE )
{
2012-11-26 18:58:24 +00:00
polyCount = 0 ;
2012-11-28 15:47:07 +00:00
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
polyCount + + ;
}
2012-11-28 15:47:07 +00:00
if ( polyCount > MAX_NODE_POLYGONS )
{
2012-11-26 18:58:24 +00:00
forceSplit = true ;
}
}
// find an axial aligned splitter
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
2012-11-26 18:58:24 +00:00
// start with the largest axis first
type = axis [ i ] ;
bestt = size [ i ] ;
// if the node is small anough in this axis direction
2012-11-28 15:47:07 +00:00
if ( ! forceSplit & & bestt < MIN_NODE_SIZE )
{
2012-11-26 18:58:24 +00:00
break ;
}
// find an axial splitter from the brush bounding boxes
// also try brushes from parent nodes
2012-11-28 15:47:07 +00:00
for ( n = node ; n ; n = n - > parent )
{
for ( bref = n - > brushes ; bref ; bref = bref - > next )
{
for ( j = 0 ; j < 2 ; j + + )
{
2012-11-26 18:58:24 +00:00
dist = bref - > b - > bounds [ j ] [ type ] ;
// if the splitter is already used or outside node bounds
2012-11-28 15:47:07 +00:00
if ( dist > = bounds [ 1 ] [ type ] | | dist < = bounds [ 0 ] [ type ] )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// find the most centered splitter
2012-11-28 15:47:07 +00:00
t = abs ( ( bounds [ 1 ] [ type ] - dist ) - ( dist - bounds [ 0 ] [ type ] ) ) ;
if ( t < bestt )
{
2012-11-26 18:58:24 +00:00
bestt = t ;
* planeType = type ;
* planeDist = dist ;
}
}
}
}
// find an axial splitter from the polygon bounding boxes
// also try brushes from parent nodes
2012-11-28 15:47:07 +00:00
for ( n = node ; n ; n = n - > parent )
{
for ( pref = n - > polygons ; pref ; pref = pref - > next )
{
for ( j = 0 ; j < 2 ; j + + )
{
2012-11-26 18:58:24 +00:00
dist = pref - > p - > bounds [ j ] [ type ] ;
// if the splitter is already used or outside node bounds
2012-11-28 15:47:07 +00:00
if ( dist > = bounds [ 1 ] [ type ] | | dist < = bounds [ 0 ] [ type ] )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// find the most centered splitter
2012-11-28 15:47:07 +00:00
t = abs ( ( bounds [ 1 ] [ type ] - dist ) - ( dist - bounds [ 0 ] [ type ] ) ) ;
if ( t < bestt )
{
2012-11-26 18:58:24 +00:00
bestt = t ;
* planeType = type ;
* planeDist = dist ;
}
}
}
}
// if we found a splitter on the largest axis
2012-11-28 15:47:07 +00:00
if ( bestt < size [ i ] )
{
2012-11-26 18:58:24 +00:00
// if forced split due to lots of polygons
2012-11-28 15:47:07 +00:00
if ( forceSplit )
{
2012-11-26 18:58:24 +00:00
return true ;
}
// don't create splitters real close to the bounds
2012-11-28 15:47:07 +00:00
if ( bounds [ 1 ] [ type ] - * planeDist > ( MIN_NODE_SIZE * 0.5f ) & &
* planeDist - bounds [ 0 ] [ type ] > ( MIN_NODE_SIZE * 0.5f ) )
{
2012-11-26 18:58:24 +00:00
return true ;
}
}
}
return false ;
}
/*
= = = = = = = = = = = = = = = =
CM_R_InsideAllChildren
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static int CM_R_InsideAllChildren ( cm_node_t * node , const idBounds & bounds )
{
assert ( node ! = NULL ) ;
if ( node - > planeType ! = - 1 )
{
if ( bounds [ 0 ] [ node - > planeType ] > = node - > planeDist )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( bounds [ 1 ] [ node - > planeType ] < = node - > planeDist )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! CM_R_InsideAllChildren ( node - > children [ 0 ] , bounds ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! CM_R_InsideAllChildren ( node - > children [ 1 ] , bounds ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
}
return true ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : R_FilterPolygonIntoTree
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : R_FilterPolygonIntoTree ( cm_model_t * model , cm_node_t * node , cm_polygonRef_t * pref , cm_polygon_t * p )
{
assert ( node ! = NULL ) ;
while ( node - > planeType ! = - 1 )
{
if ( CM_R_InsideAllChildren ( node , p - > bounds ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( p - > bounds [ 0 ] [ node - > planeType ] > = node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( p - > bounds [ 1 ] [ node - > planeType ] < = node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
R_FilterPolygonIntoTree ( model , node - > children [ 1 ] , NULL , p ) ;
node = node - > children [ 0 ] ;
}
}
2012-11-28 15:47:07 +00:00
if ( pref )
{
2012-11-26 18:58:24 +00:00
pref - > next = node - > polygons ;
node - > polygons = pref ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
AddPolygonToNode ( model , node , p ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : R_FilterBrushIntoTree
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : R_FilterBrushIntoTree ( cm_model_t * model , cm_node_t * node , cm_brushRef_t * pref , cm_brush_t * b )
{
assert ( node ! = NULL ) ;
while ( node - > planeType ! = - 1 )
{
if ( CM_R_InsideAllChildren ( node , b - > bounds ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( b - > bounds [ 0 ] [ node - > planeType ] > = node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 0 ] ;
}
2012-11-28 15:47:07 +00:00
else if ( b - > bounds [ 1 ] [ node - > planeType ] < = node - > planeDist )
{
2012-11-26 18:58:24 +00:00
node = node - > children [ 1 ] ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
R_FilterBrushIntoTree ( model , node - > children [ 1 ] , NULL , b ) ;
node = node - > children [ 0 ] ;
}
}
2012-11-28 15:47:07 +00:00
if ( pref )
{
2012-11-26 18:58:24 +00:00
pref - > next = node - > brushes ;
node - > brushes = pref ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
AddBrushToNode ( model , node , b ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : R_CreateAxialBSPTree
a brush or polygon is linked in the node closest to the root where
the brush or polygon is inside all children
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_node_t * idCollisionModelManagerLocal : : R_CreateAxialBSPTree ( cm_model_t * model , cm_node_t * node , const idBounds & bounds )
{
2012-11-26 18:58:24 +00:00
int planeType ;
float planeDist ;
2012-11-28 15:47:07 +00:00
cm_polygonRef_t * pref , * nextpref , * prevpref ;
cm_brushRef_t * bref , * nextbref , * prevbref ;
cm_node_t * frontNode , * backNode , * n ;
2012-11-26 18:58:24 +00:00
idBounds frontBounds , backBounds ;
2012-11-28 15:47:07 +00:00
if ( ! CM_FindSplitter ( node , bounds , & planeType , & planeDist ) )
{
2012-11-26 18:58:24 +00:00
node - > planeType = - 1 ;
return node ;
}
// create two child nodes
frontNode = AllocNode ( model , NODE_BLOCK_SIZE_LARGE ) ;
2012-11-28 15:47:07 +00:00
memset ( frontNode , 0 , sizeof ( cm_node_t ) ) ;
2012-11-26 18:58:24 +00:00
frontNode - > parent = node ;
frontNode - > planeType = - 1 ;
//
backNode = AllocNode ( model , NODE_BLOCK_SIZE_LARGE ) ;
2012-11-28 15:47:07 +00:00
memset ( backNode , 0 , sizeof ( cm_node_t ) ) ;
2012-11-26 18:58:24 +00:00
backNode - > parent = node ;
backNode - > planeType = - 1 ;
//
model - > numNodes + = 2 ;
// set front node bounds
frontBounds = bounds ;
frontBounds [ 0 ] [ planeType ] = planeDist ;
// set back node bounds
backBounds = bounds ;
backBounds [ 1 ] [ planeType ] = planeDist ;
//
node - > planeType = planeType ;
node - > planeDist = planeDist ;
node - > children [ 0 ] = frontNode ;
node - > children [ 1 ] = backNode ;
// filter polygons and brushes down the tree if necesary
2012-11-28 15:47:07 +00:00
for ( n = node ; n ; n = n - > parent )
{
2012-11-26 18:58:24 +00:00
prevpref = NULL ;
2012-11-28 15:47:07 +00:00
for ( pref = n - > polygons ; pref ; pref = nextpref )
{
2012-11-26 18:58:24 +00:00
nextpref = pref - > next ;
// if polygon is not inside all children
2012-11-28 15:47:07 +00:00
if ( ! CM_R_InsideAllChildren ( n , pref - > p - > bounds ) )
{
2012-11-26 18:58:24 +00:00
// filter polygon down the tree
R_FilterPolygonIntoTree ( model , n , pref , pref - > p ) ;
2012-11-28 15:47:07 +00:00
if ( prevpref )
{
2012-11-26 18:58:24 +00:00
prevpref - > next = nextpref ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
n - > polygons = nextpref ;
}
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
prevpref = pref ;
}
}
prevbref = NULL ;
2012-11-28 15:47:07 +00:00
for ( bref = n - > brushes ; bref ; bref = nextbref )
{
2012-11-26 18:58:24 +00:00
nextbref = bref - > next ;
// if brush is not inside all children
2012-11-28 15:47:07 +00:00
if ( ! CM_R_InsideAllChildren ( n , bref - > b - > bounds ) )
{
2012-11-26 18:58:24 +00:00
// filter brush down the tree
R_FilterBrushIntoTree ( model , n , bref , bref - > b ) ;
2012-11-28 15:47:07 +00:00
if ( prevbref )
{
2012-11-26 18:58:24 +00:00
prevbref - > next = nextbref ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
n - > brushes = nextbref ;
}
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
prevbref = bref ;
}
}
}
R_CreateAxialBSPTree ( model , frontNode , frontBounds ) ;
R_CreateAxialBSPTree ( model , backNode , backBounds ) ;
return node ;
}
/*
int cm_numSavedPolygonLinks ;
int cm_numSavedBrushLinks ;
int CM_R_CountChildren ( cm_node_t * node ) {
if ( node - > planeType = = - 1 ) {
return 0 ;
}
return 2 + CM_R_CountChildren ( node - > children [ 0 ] ) + CM_R_CountChildren ( node - > children [ 1 ] ) ;
}
void CM_R_TestOptimisation ( cm_node_t * node ) {
int polyCount , brushCount , numChildren ;
cm_polygonRef_t * pref ;
cm_brushRef_t * bref ;
if ( node - > planeType = = - 1 ) {
return ;
}
polyCount = 0 ;
for ( pref = node - > polygons ; pref ; pref = pref - > next ) {
polyCount + + ;
}
brushCount = 0 ;
for ( bref = node - > brushes ; bref ; bref = bref - > next ) {
brushCount + + ;
}
if ( polyCount | | brushCount ) {
numChildren = CM_R_CountChildren ( node ) ;
cm_numSavedPolygonLinks + = ( numChildren - 1 ) * polyCount ;
cm_numSavedBrushLinks + = ( numChildren - 1 ) * brushCount ;
}
CM_R_TestOptimisation ( node - > children [ 0 ] ) ;
CM_R_TestOptimisation ( node - > children [ 1 ] ) ;
}
*/
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : CreateAxialBSPTree
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_node_t * idCollisionModelManagerLocal : : CreateAxialBSPTree ( cm_model_t * model , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_brushRef_t * bref ;
2012-11-26 18:58:24 +00:00
idBounds bounds ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get head node bounds
bounds . Clear ( ) ;
2012-11-28 15:47:07 +00:00
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
bounds + = pref - > p - > bounds ;
}
2012-11-28 15:47:07 +00:00
for ( bref = node - > brushes ; bref ; bref = bref - > next )
{
2012-11-26 18:58:24 +00:00
bounds + = bref - > b - > bounds ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create axial BSP tree from head node
node = R_CreateAxialBSPTree ( model , node , bounds ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return node ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Raw polygon and brush data
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : SetupHash
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : SetupHash ( )
{
if ( ! cm_vertexHash )
{
cm_vertexHash = new ( TAG_COLLISION ) idHashIndex ( VERTEX_HASH_SIZE , 1024 ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( ! cm_edgeHash )
{
cm_edgeHash = new ( TAG_COLLISION ) idHashIndex ( EDGE_HASH_SIZE , 1024 ) ;
2012-11-26 18:58:24 +00:00
}
// init variables used during loading and optimization
2012-11-28 15:47:07 +00:00
if ( ! cm_windingList )
{
cm_windingList = new ( TAG_COLLISION ) cm_windingList_t ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( ! cm_outList )
{
cm_outList = new ( TAG_COLLISION ) cm_windingList_t ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( ! cm_tmpList )
{
cm_tmpList = new ( TAG_COLLISION ) cm_windingList_t ;
2012-11-26 18:58:24 +00:00
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ShutdownHash
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ShutdownHash ( )
{
2012-11-26 18:58:24 +00:00
delete cm_vertexHash ;
cm_vertexHash = NULL ;
delete cm_edgeHash ;
cm_edgeHash = NULL ;
delete cm_tmpList ;
cm_tmpList = NULL ;
delete cm_outList ;
cm_outList = NULL ;
delete cm_windingList ;
cm_windingList = NULL ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ClearHash
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ClearHash ( idBounds & bounds )
{
2012-11-26 18:58:24 +00:00
int i ;
float f , max ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_vertexHash - > Clear ( ) ;
cm_edgeHash - > Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_modelBounds = bounds ;
max = bounds [ 1 ] . x - bounds [ 0 ] . x ;
f = bounds [ 1 ] . y - bounds [ 0 ] . y ;
2012-11-28 15:47:07 +00:00
if ( f > max )
{
2012-11-26 18:58:24 +00:00
max = f ;
}
2012-11-28 15:47:07 +00:00
cm_vertexShift = ( float ) max / VERTEX_HASH_BOXSIZE ;
for ( i = 0 ; ( 1 < < i ) < cm_vertexShift ; i + + )
{
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( i = = 0 )
{
2012-11-26 18:58:24 +00:00
cm_vertexShift = 1 ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
cm_vertexShift = i ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : HashVec
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
ID_INLINE int idCollisionModelManagerLocal : : HashVec ( const idVec3 & vec )
{
2012-11-26 18:58:24 +00:00
/*
int x , y ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
x = ( ( ( int ) ( vec [ 0 ] - cm_modelBounds [ 0 ] . x + 0.5 ) ) > > cm_vertexShift ) & ( VERTEX_HASH_BOXSIZE - 1 ) ;
y = ( ( ( int ) ( vec [ 1 ] - cm_modelBounds [ 0 ] . y + 0.5 ) ) > > cm_vertexShift ) & ( VERTEX_HASH_BOXSIZE - 1 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( x > = 0 & & x < VERTEX_HASH_BOXSIZE & & y > = 0 & & y < VERTEX_HASH_BOXSIZE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return y * VERTEX_HASH_BOXSIZE + x ;
*/
int x , y , z ;
2012-11-28 15:47:07 +00:00
x = ( ( ( int ) ( vec [ 0 ] - cm_modelBounds [ 0 ] . x + 0.5 ) ) + 2 ) > > 2 ;
y = ( ( ( int ) ( vec [ 1 ] - cm_modelBounds [ 0 ] . y + 0.5 ) ) + 2 ) > > 2 ;
z = ( ( ( int ) ( vec [ 2 ] - cm_modelBounds [ 0 ] . z + 0.5 ) ) + 2 ) > > 2 ;
return ( x + y * VERTEX_HASH_BOXSIZE + z ) & ( VERTEX_HASH_SIZE - 1 ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetVertex
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idCollisionModelManagerLocal : : GetVertex ( cm_model_t * model , const idVec3 & v , int * vertexNum )
{
2012-11-26 18:58:24 +00:00
int i , hashKey , vn ;
idVec3 vert , * p ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
if ( idMath : : Fabs ( v [ i ] - idMath : : Rint ( v [ i ] ) ) < INTEGRAL_EPSILON )
vert [ i ] = idMath : : Rint ( v [ i ] ) ;
2012-11-26 18:58:24 +00:00
else
vert [ i ] = v [ i ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
hashKey = HashVec ( vert ) ;
2012-11-28 15:47:07 +00:00
for ( vn = cm_vertexHash - > First ( hashKey ) ; vn > = 0 ; vn = cm_vertexHash - > Next ( vn ) )
{
2012-11-26 18:58:24 +00:00
p = & model - > vertices [ vn ] . p ;
// first compare z-axis because hash is based on x-y plane
2012-11-28 15:47:07 +00:00
if ( idMath : : Fabs ( vert [ 2 ] - ( * p ) [ 2 ] ) < VERTEX_EPSILON & &
idMath : : Fabs ( vert [ 0 ] - ( * p ) [ 0 ] ) < VERTEX_EPSILON & &
idMath : : Fabs ( vert [ 1 ] - ( * p ) [ 1 ] ) < VERTEX_EPSILON )
2012-11-26 18:58:24 +00:00
{
* vertexNum = vn ;
return true ;
}
}
2012-11-28 15:47:07 +00:00
if ( model - > numVertices > = model - > maxVertices )
{
cm_vertex_t * oldVertices ;
2012-11-26 18:58:24 +00:00
// resize vertex array
2012-11-28 15:47:07 +00:00
model - > maxVertices = ( float ) model - > maxVertices * 1.5f + 1 ;
2012-11-26 18:58:24 +00:00
oldVertices = model - > vertices ;
2012-11-28 15:47:07 +00:00
model - > vertices = ( cm_vertex_t * ) Mem_ClearedAlloc ( model - > maxVertices * sizeof ( cm_vertex_t ) , TAG_COLLISION ) ;
memcpy ( model - > vertices , oldVertices , model - > numVertices * sizeof ( cm_vertex_t ) ) ;
2012-11-26 18:58:24 +00:00
Mem_Free ( oldVertices ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_vertexHash - > ResizeIndex ( model - > maxVertices ) ;
}
model - > vertices [ model - > numVertices ] . p = vert ;
model - > vertices [ model - > numVertices ] . checkcount = 0 ;
* vertexNum = model - > numVertices ;
// add vertice to hash
cm_vertexHash - > Add ( hashKey , model - > numVertices ) ;
//
model - > numVertices + + ;
return false ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetEdge
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idCollisionModelManagerLocal : : GetEdge ( cm_model_t * model , const idVec3 & v1 , const idVec3 & v2 , int * edgeNum , int v1num )
{
2012-11-26 18:58:24 +00:00
int v2num , hashKey , e ;
int found , * vertexNum ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// the first edge is a dummy
2012-11-28 15:47:07 +00:00
if ( model - > numEdges = = 0 )
{
2012-11-26 18:58:24 +00:00
model - > numEdges = 1 ;
}
2012-11-28 15:47:07 +00:00
if ( v1num ! = - 1 )
{
2012-11-26 18:58:24 +00:00
found = 1 ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
found = GetVertex ( model , v1 , & v1num ) ;
}
found & = GetVertex ( model , v2 , & v2num ) ;
// if both vertices are the same or snapped onto each other
2012-11-28 15:47:07 +00:00
if ( v1num = = v2num )
{
2012-11-26 18:58:24 +00:00
* edgeNum = 0 ;
return true ;
}
hashKey = cm_edgeHash - > GenerateKey ( v1num , v2num ) ;
// if both vertices where already stored
2012-11-28 15:47:07 +00:00
if ( found )
{
for ( e = cm_edgeHash - > First ( hashKey ) ; e > = 0 ; e = cm_edgeHash - > Next ( e ) )
2012-11-26 18:58:24 +00:00
{
// NOTE: only allow at most two users that use the edge in opposite direction
2012-11-28 15:47:07 +00:00
if ( model - > edges [ e ] . numUsers ! = 1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexNum = model - > edges [ e ] . vertexNum ;
2012-11-28 15:47:07 +00:00
if ( vertexNum [ 0 ] = = v2num )
{
if ( vertexNum [ 1 ] = = v1num )
{
2012-11-26 18:58:24 +00:00
// 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
2012-11-28 15:47:07 +00:00
if ( e > = 0 )
{
2012-11-26 18:58:24 +00:00
model - > edges [ e ] . numUsers + + ;
return true ;
}
}
2012-11-28 15:47:07 +00:00
if ( model - > numEdges > = model - > maxEdges )
{
cm_edge_t * oldEdges ;
2012-11-26 18:58:24 +00:00
// resize edge array
2012-11-28 15:47:07 +00:00
model - > maxEdges = ( float ) model - > maxEdges * 1.5f + 1 ;
2012-11-26 18:58:24 +00:00
oldEdges = model - > edges ;
2012-11-28 15:47:07 +00:00
model - > edges = ( cm_edge_t * ) Mem_ClearedAlloc ( model - > maxEdges * sizeof ( cm_edge_t ) , TAG_COLLISION ) ;
memcpy ( model - > edges , oldEdges , model - > numEdges * sizeof ( cm_edge_t ) ) ;
2012-11-26 18:58:24 +00:00
Mem_Free ( oldEdges ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_edgeHash - > ResizeIndex ( model - > maxEdges ) ;
}
// setup edge
model - > edges [ model - > numEdges ] . vertexNum [ 0 ] = v1num ;
model - > edges [ model - > numEdges ] . vertexNum [ 1 ] = v2num ;
model - > edges [ model - > numEdges ] . internal = false ;
model - > edges [ model - > numEdges ] . checkcount = 0 ;
model - > edges [ model - > numEdges ] . numUsers = 1 ; // used by one polygon atm
model - > edges [ model - > numEdges ] . normal . Zero ( ) ;
//
* edgeNum = model - > numEdges ;
// add edge to hash
cm_edgeHash - > Add ( hashKey , model - > numEdges ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model - > numEdges + + ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return false ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : CreatePolygon
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : CreatePolygon ( cm_model_t * model , idFixedWinding * w , const idPlane & plane , const idMaterial * material , int primitiveNum )
{
2012-11-26 18:58:24 +00:00
int i , j , edgeNum , v1num ;
int numPolyEdges , polyEdges [ MAX_POINTS_ON_WINDING ] ;
idBounds bounds ;
2012-11-28 15:47:07 +00:00
cm_polygon_t * p ;
2012-11-26 18:58:24 +00:00
// turn the winding into a sequence of edges
numPolyEdges = 0 ;
v1num = - 1 ; // first vertex unknown
2012-11-28 15:47:07 +00:00
for ( i = 0 , j = 1 ; i < w - > GetNumPoints ( ) ; i + + , j + + )
{
if ( j > = w - > GetNumPoints ( ) )
{
2012-11-26 18:58:24 +00:00
j = 0 ;
}
2012-11-28 15:47:07 +00:00
GetEdge ( model , ( * w ) [ i ] . ToVec3 ( ) , ( * w ) [ j ] . ToVec3 ( ) , & polyEdges [ numPolyEdges ] , v1num ) ;
if ( polyEdges [ numPolyEdges ] )
{
2012-11-26 18:58:24 +00:00
// last vertex of this edge is the first vertex of the next edge
2012-11-28 15:47:07 +00:00
v1num = model - > edges [ abs ( polyEdges [ numPolyEdges ] ) ] . vertexNum [ INT32_SIGNBITNOTSET ( polyEdges [ numPolyEdges ] ) ] ;
2012-11-26 18:58:24 +00:00
// this edge is valid so keep it
numPolyEdges + + ;
}
}
// should have at least 3 edges
2012-11-28 15:47:07 +00:00
if ( numPolyEdges < 3 )
{
2012-11-26 18:58:24 +00:00
return ;
}
// the polygon is invalid if some edge is found twice
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numPolyEdges ; i + + )
{
for ( j = i + 1 ; j < numPolyEdges ; j + + )
{
if ( abs ( polyEdges [ i ] ) = = abs ( polyEdges [ j ] ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
}
}
// don't overflow max edges
2012-11-28 15:47:07 +00:00
if ( numPolyEdges > CM_MAX_POLYGON_EDGES )
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::CreatePolygon: polygon has more than %d edges " , numPolyEdges ) ;
numPolyEdges = CM_MAX_POLYGON_EDGES ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
w - > GetBounds ( bounds ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
p = AllocPolygon ( model , numPolyEdges ) ;
p - > numEdges = numPolyEdges ;
p - > contents = material - > GetContentFlags ( ) ;
p - > material = material ;
p - > checkcount = 0 ;
p - > plane = plane ;
p - > bounds = bounds ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numPolyEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
edgeNum = polyEdges [ i ] ;
p - > edges [ i ] = edgeNum ;
}
R_FilterPolygonIntoTree ( model , model - > node , NULL , p ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : PolygonFromWinding
NOTE : for patches primitiveNum < 0 and abs ( primitiveNum ) is the real number
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : PolygonFromWinding ( cm_model_t * model , idFixedWinding * w , const idPlane & plane , const idMaterial * material , int primitiveNum )
{
2012-11-26 18:58:24 +00:00
int contents ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
contents = material - > GetContentFlags ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if this polygon is part of the world model
2012-11-28 15:47:07 +00:00
if ( numModels = = 0 )
{
2012-11-26 18:58:24 +00:00
// if the polygon is fully chopped away by the proc bsp tree
2012-11-28 15:47:07 +00:00
if ( ChoppedAwayByProcBSP ( * w , plane , contents ) )
{
2012-11-26 18:58:24 +00:00
model - > numRemovedPolys + + ;
return ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get one winding that is not or only partly contained in brushes
w = WindingOutsideBrushes ( w , plane , contents , primitiveNum , model - > node ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the polygon is fully contained within a brush
2012-11-28 15:47:07 +00:00
if ( ! w )
{
2012-11-26 18:58:24 +00:00
model - > numRemovedPolys + + ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( w - > IsHuge ( ) )
{
common - > Warning ( " idCollisionModelManagerLocal::PolygonFromWinding: model %s primitive %d is degenerate " , model - > name . c_str ( ) , abs ( primitiveNum ) ) ;
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
CreatePolygon ( model , w , plane , material , primitiveNum ) ;
2012-11-28 15:47:07 +00:00
if ( material - > GetCullType ( ) = = CT_TWO_SIDED | | material - > ShouldCreateBackSides ( ) )
{
2012-11-26 18:58:24 +00:00
w - > ReverseSelf ( ) ;
CreatePolygon ( model , w , - plane , material , primitiveNum ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : CreatePatchPolygons
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : CreatePatchPolygons ( cm_model_t * model , idSurface_Patch & mesh , const idMaterial * material , int primitiveNum )
{
2012-11-26 18:58:24 +00:00
int i , j ;
float dot ;
int v1 , v2 , v3 , v4 ;
idFixedWinding w ;
idPlane plane ;
idVec3 d1 , d2 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mesh . GetWidth ( ) - 1 ; i + + )
{
for ( j = 0 ; j < mesh . GetHeight ( ) - 1 ; j + + )
{
2012-11-26 18:58:24 +00:00
v1 = j * mesh . GetWidth ( ) + i ;
v2 = v1 + 1 ;
v3 = v1 + mesh . GetWidth ( ) + 1 ;
v4 = v1 + mesh . GetWidth ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
d1 = mesh [ v2 ] . xyz - mesh [ v1 ] . xyz ;
d2 = mesh [ v3 ] . xyz - mesh [ v1 ] . xyz ;
2012-11-28 15:47:07 +00:00
plane . SetNormal ( d1 . Cross ( d2 ) ) ;
if ( plane . Normalize ( ) ! = 0.0f )
{
2012-11-26 18:58:24 +00:00
plane . FitThroughPoint ( mesh [ v1 ] . xyz ) ;
dot = plane . Distance ( mesh [ v4 ] . xyz ) ;
// if we can turn it into a quad
2012-11-28 15:47:07 +00:00
if ( idMath : : Fabs ( dot ) < 0.1f )
{
2012-11-26 18:58:24 +00:00
w . Clear ( ) ;
w + = mesh [ v1 ] . xyz ;
w + = mesh [ v2 ] . xyz ;
w + = mesh [ v3 ] . xyz ;
w + = mesh [ v4 ] . xyz ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
PolygonFromWinding ( model , & w , plane , material , - primitiveNum ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
// create one of the triangles
w . Clear ( ) ;
w + = mesh [ v1 ] . xyz ;
w + = mesh [ v2 ] . xyz ;
w + = mesh [ v3 ] . xyz ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
PolygonFromWinding ( model , & w , plane , material , - primitiveNum ) ;
}
}
// create the other triangle
d1 = mesh [ v3 ] . xyz - mesh [ v1 ] . xyz ;
d2 = mesh [ v4 ] . xyz - mesh [ v1 ] . xyz ;
2012-11-28 15:47:07 +00:00
plane . SetNormal ( d1 . Cross ( d2 ) ) ;
if ( plane . Normalize ( ) ! = 0.0f )
{
2012-11-26 18:58:24 +00:00
plane . FitThroughPoint ( mesh [ v1 ] . xyz ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
w . Clear ( ) ;
w + = mesh [ v1 ] . xyz ;
w + = mesh [ v3 ] . xyz ;
w + = mesh [ v4 ] . xyz ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
PolygonFromWinding ( model , & w , plane , material , - primitiveNum ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = =
CM_EstimateVertsAndEdges
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void CM_EstimateVertsAndEdges ( const idMapEntity * mapEnt , int * numVerts , int * numEdges )
{
2012-11-26 18:58:24 +00:00
int j , width , height ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
* numVerts = * numEdges = 0 ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < mapEnt - > GetNumPrimitives ( ) ; j + + )
{
const idMapPrimitive * mapPrim ;
mapPrim = mapEnt - > GetPrimitive ( j ) ;
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_PATCH )
{
2012-11-26 18:58:24 +00:00
// assume maximum tesselation without adding verts
2012-11-28 15:47:07 +00:00
width = static_cast < const idMapPatch * > ( mapPrim ) - > GetWidth ( ) ;
height = static_cast < const idMapPatch * > ( mapPrim ) - > GetHeight ( ) ;
2012-11-26 18:58:24 +00:00
* numVerts + = width * height ;
2012-11-28 15:47:07 +00:00
* numEdges + = ( width - 1 ) * height + width * ( height - 1 ) + ( width - 1 ) * ( height - 1 ) ;
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_BRUSH )
{
2012-11-26 18:58:24 +00:00
// assume cylinder with a polygon with (numSides - 2) edges ontop and on the bottom
2012-11-28 15:47:07 +00:00
* numVerts + = ( static_cast < const idMapBrush * > ( mapPrim ) - > GetNumSides ( ) - 2 ) * 2 ;
* numEdges + = ( static_cast < const idMapBrush * > ( mapPrim ) - > GetNumSides ( ) - 2 ) * 3 ;
2012-11-26 18:58:24 +00:00
continue ;
}
}
}
/*
= = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ConverPatch
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ConvertPatch ( cm_model_t * model , const idMapPatch * patch , int primitiveNum )
{
const idMaterial * material ;
idSurface_Patch * cp ;
2012-11-26 18:58:24 +00:00
material = declManager - > FindMaterial ( patch - > GetMaterial ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! ( material - > GetContentFlags ( ) & CONTENTS_REMOVE_UTIL ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy the patch
2012-11-28 15:47:07 +00:00
cp = new ( TAG_COLLISION ) idSurface_Patch ( * patch ) ;
2012-11-26 18:58:24 +00:00
// if the patch has an explicit number of subdivisions use it to avoid cracks
2012-11-28 15:47:07 +00:00
if ( patch - > GetExplicitlySubdivided ( ) )
{
2012-11-26 18:58:24 +00:00
cp - > SubdivideExplicit ( patch - > GetHorzSubdivisions ( ) , patch - > GetVertSubdivisions ( ) , false , true ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
cp - > Subdivide ( DEFAULT_CURVE_MAX_ERROR_CD , DEFAULT_CURVE_MAX_ERROR_CD , DEFAULT_CURVE_MAX_LENGTH_CD , false ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create collision polygons for the patch
CreatePatchPolygons ( model , * cp , material , primitiveNum ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
delete cp ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ConvertBrushSides
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ConvertBrushSides ( cm_model_t * model , const idMapBrush * mapBrush , int primitiveNum )
{
2012-11-26 18:58:24 +00:00
int i , j ;
2012-11-28 15:47:07 +00:00
idMapBrushSide * mapSide ;
2012-11-26 18:58:24 +00:00
idFixedWinding w ;
2012-11-28 15:47:07 +00:00
idPlane * planes ;
const idMaterial * material ;
2012-11-26 18:58:24 +00:00
// fix degenerate planes
2012-11-28 15:47:07 +00:00
planes = ( idPlane * ) _alloca16 ( mapBrush - > GetNumSides ( ) * sizeof ( planes [ 0 ] ) ) ;
for ( i = 0 ; i < mapBrush - > GetNumSides ( ) ; i + + )
{
planes [ i ] = mapBrush - > GetSide ( i ) - > GetPlane ( ) ;
2012-11-26 18:58:24 +00:00
planes [ i ] . FixDegeneracies ( DEGENERATE_DIST_EPSILON ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create a collision polygon for each brush side
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mapBrush - > GetNumSides ( ) ; i + + )
{
mapSide = mapBrush - > GetSide ( i ) ;
2012-11-26 18:58:24 +00:00
material = declManager - > FindMaterial ( mapSide - > GetMaterial ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! ( material - > GetContentFlags ( ) & CONTENTS_REMOVE_UTIL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
w . BaseForPlane ( - planes [ i ] ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < mapBrush - > GetNumSides ( ) & & w . GetNumPoints ( ) ; j + + )
{
if ( i = = j )
{
2012-11-26 18:58:24 +00:00
continue ;
}
w . ClipInPlace ( - planes [ j ] , 0 ) ;
}
2012-11-28 15:47:07 +00:00
if ( w . GetNumPoints ( ) )
{
2012-11-26 18:58:24 +00:00
PolygonFromWinding ( model , & w , planes [ i ] , material , primitiveNum ) ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ConvertBrush
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ConvertBrush ( cm_model_t * model , const idMapBrush * mapBrush , int primitiveNum )
{
2012-11-26 18:58:24 +00:00
int i , j , contents ;
idBounds bounds ;
2012-11-28 15:47:07 +00:00
idMapBrushSide * mapSide ;
cm_brush_t * brush ;
idPlane * planes ;
2012-11-26 18:58:24 +00:00
idFixedWinding w ;
2012-11-28 15:47:07 +00:00
const idMaterial * material = NULL ;
2012-11-26 18:58:24 +00:00
contents = 0 ;
bounds . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// fix degenerate planes
2012-11-28 15:47:07 +00:00
planes = ( idPlane * ) _alloca16 ( mapBrush - > GetNumSides ( ) * sizeof ( planes [ 0 ] ) ) ;
for ( i = 0 ; i < mapBrush - > GetNumSides ( ) ; i + + )
{
planes [ i ] = mapBrush - > GetSide ( i ) - > GetPlane ( ) ;
2012-11-26 18:58:24 +00:00
planes [ i ] . FixDegeneracies ( DEGENERATE_DIST_EPSILON ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we are only getting the bounds for the brush so there's no need
// to create a winding for the last brush side
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mapBrush - > GetNumSides ( ) - 1 ; i + + )
{
mapSide = mapBrush - > GetSide ( i ) ;
2012-11-26 18:58:24 +00:00
material = declManager - > FindMaterial ( mapSide - > GetMaterial ( ) ) ;
contents | = ( material - > GetContentFlags ( ) & CONTENTS_REMOVE_UTIL ) ;
w . BaseForPlane ( - planes [ i ] ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < mapBrush - > GetNumSides ( ) & & w . GetNumPoints ( ) ; j + + )
{
if ( i = = j )
{
2012-11-26 18:58:24 +00:00
continue ;
}
w . ClipInPlace ( - planes [ j ] , 0 ) ;
}
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < w . GetNumPoints ( ) ; j + + )
{
2012-11-26 18:58:24 +00:00
bounds . AddPoint ( w [ j ] . ToVec3 ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! contents )
{
2012-11-26 18:58:24 +00:00
return ;
}
// create brush for position test
brush = AllocBrush ( model , mapBrush - > GetNumSides ( ) ) ;
brush - > checkcount = 0 ;
brush - > contents = contents ;
brush - > material = material ;
brush - > primitiveNum = primitiveNum ;
brush - > bounds = bounds ;
brush - > numPlanes = mapBrush - > GetNumSides ( ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mapBrush - > GetNumSides ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
brush - > planes [ i ] = planes [ i ] ;
}
AddBrushToNode ( model , model - > node , brush ) ;
}
/*
= = = = = = = = = = = = = = = =
CM_CountNodeBrushes
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static int CM_CountNodeBrushes ( const cm_node_t * node )
{
2012-11-26 18:58:24 +00:00
int count ;
2012-11-28 15:47:07 +00:00
cm_brushRef_t * bref ;
2012-11-26 18:58:24 +00:00
count = 0 ;
2012-11-28 15:47:07 +00:00
for ( bref = node - > brushes ; bref ; bref = bref - > next )
{
2012-11-26 18:58:24 +00:00
count + + ;
}
return count ;
}
/*
= = = = = = = = = = = = = = = =
CM_R_GetModelBounds
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void CM_R_GetNodeBounds ( idBounds * bounds , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_brushRef_t * bref ;
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
bounds - > AddPoint ( pref - > p - > bounds [ 0 ] ) ;
bounds - > AddPoint ( pref - > p - > bounds [ 1 ] ) ;
}
2012-11-28 15:47:07 +00:00
for ( bref = node - > brushes ; bref ; bref = bref - > next )
{
2012-11-26 18:58:24 +00:00
bounds - > AddPoint ( bref - > b - > bounds [ 0 ] ) ;
bounds - > AddPoint ( bref - > b - > bounds [ 1 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
CM_R_GetNodeBounds ( bounds , node - > children [ 1 ] ) ;
node = node - > children [ 0 ] ;
}
}
/*
= = = = = = = = = = = = = = = =
CM_GetNodeBounds
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void CM_GetNodeBounds ( idBounds * bounds , cm_node_t * node )
{
2012-11-26 18:58:24 +00:00
bounds - > Clear ( ) ;
CM_R_GetNodeBounds ( bounds , node ) ;
2012-11-28 15:47:07 +00:00
if ( bounds - > IsCleared ( ) )
{
2012-11-26 18:58:24 +00:00
bounds - > Zero ( ) ;
}
}
/*
= = = = = = = = = = = = = = = =
CM_GetNodeContents
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int CM_GetNodeContents ( cm_node_t * node )
{
2012-11-26 18:58:24 +00:00
int contents ;
2012-11-28 15:47:07 +00:00
cm_polygonRef_t * pref ;
cm_brushRef_t * bref ;
2012-11-26 18:58:24 +00:00
contents = 0 ;
2012-11-28 15:47:07 +00:00
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
contents | = pref - > p - > contents ;
}
2012-11-28 15:47:07 +00:00
for ( bref = node - > brushes ; bref ; bref = bref - > next )
{
2012-11-26 18:58:24 +00:00
contents | = bref - > b - > contents ;
}
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
contents | = CM_GetNodeContents ( node - > children [ 1 ] ) ;
node = node - > children [ 0 ] ;
}
return contents ;
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : RemapEdges
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : RemapEdges ( cm_node_t * node , int * edgeRemap )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
// if we checked this polygon already
2012-11-28 15:47:07 +00:00
if ( p - > checkcount = = checkCount )
{
2012-11-26 18:58:24 +00:00
continue ;
}
p - > checkcount = checkCount ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p - > numEdges ; i + + )
{
if ( p - > edges [ i ] < 0 )
{
p - > edges [ i ] = - edgeRemap [ abs ( p - > edges [ i ] ) ] ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
p - > edges [ i ] = edgeRemap [ p - > edges [ i ] ] ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RemapEdges ( node - > children [ 1 ] , edgeRemap ) ;
node = node - > children [ 0 ] ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : OptimizeArrays
due to polygon merging and polygon removal the vertex and edge array
can have a lot of unused entries .
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : OptimizeArrays ( cm_model_t * model )
{
2012-11-26 18:58:24 +00:00
int i , newNumVertices , newNumEdges , * v ;
2012-11-28 15:47:07 +00:00
int * remap ;
cm_edge_t * oldEdges ;
cm_vertex_t * oldVertices ;
remap = ( int * ) Mem_ClearedAlloc ( Max ( model - > numVertices , model - > numEdges ) * sizeof ( int ) , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
// get all used vertices
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < model - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
remap [ model - > edges [ i ] . vertexNum [ 0 ] ] = true ;
remap [ model - > edges [ i ] . vertexNum [ 1 ] ] = true ;
}
// create remap index and move vertices
newNumVertices = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < model - > numVertices ; i + + )
{
if ( remap [ i ] )
{
2012-11-26 18:58:24 +00:00
remap [ i ] = newNumVertices ;
model - > vertices [ newNumVertices ] = model - > vertices [ i ] ;
newNumVertices + + ;
}
}
model - > numVertices = newNumVertices ;
// change edge vertex indexes
2012-11-28 15:47:07 +00:00
for ( i = 1 ; i < model - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
v = model - > edges [ i ] . vertexNum ;
v [ 0 ] = remap [ v [ 0 ] ] ;
v [ 1 ] = remap [ v [ 1 ] ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create remap index and move edges
newNumEdges = 1 ;
2012-11-28 15:47:07 +00:00
for ( i = 1 ; i < model - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
// if the edge is used
2012-11-28 15:47:07 +00:00
if ( model - > edges [ i ] . numUsers )
{
2012-11-26 18:58:24 +00:00
remap [ i ] = newNumEdges ;
model - > edges [ newNumEdges ] = model - > edges [ i ] ;
newNumEdges + + ;
}
}
// change polygon edge indexes
checkCount + + ;
RemapEdges ( model - > node , remap ) ;
model - > numEdges = newNumEdges ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Mem_Free ( remap ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// realloc vertices
oldVertices = model - > vertices ;
model - > maxVertices = model - > numVertices ;
2012-11-28 15:47:07 +00:00
model - > vertices = ( cm_vertex_t * ) Mem_ClearedAlloc ( model - > numVertices * sizeof ( cm_vertex_t ) , TAG_COLLISION ) ;
if ( oldVertices )
{
memcpy ( model - > vertices , oldVertices , model - > numVertices * sizeof ( cm_vertex_t ) ) ;
2012-11-26 18:58:24 +00:00
Mem_Free ( oldVertices ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// realloc edges
oldEdges = model - > edges ;
model - > maxEdges = model - > numEdges ;
2012-11-28 15:47:07 +00:00
model - > edges = ( cm_edge_t * ) Mem_ClearedAlloc ( model - > numEdges * sizeof ( cm_edge_t ) , TAG_COLLISION ) ;
if ( oldEdges )
{
memcpy ( model - > edges , oldEdges , model - > numEdges * sizeof ( cm_edge_t ) ) ;
2012-11-26 18:58:24 +00:00
Mem_Free ( oldEdges ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FinishModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : FinishModel ( cm_model_t * model )
{
2012-11-26 18:58:24 +00:00
// try to merge polygons
checkCount + + ;
MergeTreePolygons ( model , model - > node ) ;
// find internal edges (no mesh can ever collide with internal edges)
checkCount + + ;
FindInternalEdges ( model , model - > node ) ;
// calculate edge normals
checkCount + + ;
CalculateEdgeNormals ( model , model - > node ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//common->Printf( "%s vertex hash spread is %d\n", model->name.c_str(), cm_vertexHash->GetSpread() );
//common->Printf( "%s edge hash spread is %d\n", model->name.c_str(), cm_edgeHash->GetSpread() );
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remove all unused vertices and edges
OptimizeArrays ( model ) ;
// get model bounds from brush and polygon bounds
CM_GetNodeBounds ( & model - > bounds , model - > node ) ;
// get model contents
model - > contents = CM_GetNodeContents ( model - > node ) ;
// total memory used by this model
2012-11-28 15:47:07 +00:00
model - > usedMemory = model - > numVertices * sizeof ( cm_vertex_t ) +
model - > numEdges * sizeof ( cm_edge_t ) +
2012-11-26 18:58:24 +00:00
model - > polygonMemory +
model - > brushMemory +
2012-11-28 15:47:07 +00:00
model - > numNodes * sizeof ( cm_node_t ) +
model - > numPolygonRefs * sizeof ( cm_polygonRef_t ) +
model - > numBrushRefs * sizeof ( cm_brushRef_t ) ;
2012-11-26 18:58:24 +00:00
}
static const byte BCM_VERSION = 100 ;
static const unsigned int BCM_MAGIC = ( ' B ' < < 24 ) | ( ' C ' < < 16 ) | ( ' M ' < < 16 ) | BCM_VERSION ;
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : LoadBinaryModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_model_t * idCollisionModelManagerLocal : : LoadBinaryModelFromFile ( idFile * file , ID_TIME_T sourceTimeStamp )
{
2012-11-26 18:58:24 +00:00
unsigned int magic = 0 ;
file - > ReadBig ( magic ) ;
2012-11-28 15:47:07 +00:00
if ( magic ! = BCM_MAGIC )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
ID_TIME_T storedTimeStamp = FILE_NOT_FOUND_TIMESTAMP ;
file - > ReadBig ( storedTimeStamp ) ;
2012-11-28 15:47:07 +00:00
if ( ! fileSystem - > InProductionMode ( ) & & storedTimeStamp ! = sourceTimeStamp )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
cm_model_t * model = AllocModel ( ) ;
2012-11-26 18:58:24 +00:00
file - > ReadString ( model - > name ) ;
file - > ReadBig ( model - > bounds ) ;
file - > ReadBig ( model - > contents ) ;
file - > ReadBig ( model - > isConvex ) ;
file - > ReadBig ( model - > numVertices ) ;
file - > ReadBig ( model - > numEdges ) ;
file - > ReadBig ( model - > numPolygons ) ;
file - > ReadBig ( model - > numBrushes ) ;
file - > ReadBig ( model - > numNodes ) ;
file - > ReadBig ( model - > numBrushRefs ) ;
file - > ReadBig ( model - > numPolygonRefs ) ;
file - > ReadBig ( model - > numInternalEdges ) ;
file - > ReadBig ( model - > numSharpEdges ) ;
file - > ReadBig ( model - > numRemovedPolys ) ;
file - > ReadBig ( model - > numMergedPolys ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model - > maxVertices = model - > numVertices ;
2012-11-28 15:47:07 +00:00
model - > vertices = ( cm_vertex_t * ) Mem_ClearedAlloc ( model - > maxVertices * sizeof ( cm_vertex_t ) , TAG_COLLISION ) ;
for ( int i = 0 ; i < model - > numVertices ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > ReadBig ( model - > vertices [ i ] . p ) ;
file - > ReadBig ( model - > vertices [ i ] . checkcount ) ;
file - > ReadBig ( model - > vertices [ i ] . side ) ;
file - > ReadBig ( model - > vertices [ i ] . sideSet ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model - > maxEdges = model - > numEdges ;
2012-11-28 15:47:07 +00:00
model - > edges = ( cm_edge_t * ) Mem_ClearedAlloc ( model - > maxEdges * sizeof ( cm_edge_t ) , TAG_COLLISION ) ;
for ( int i = 0 ; i < model - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > ReadBig ( model - > edges [ i ] . checkcount ) ;
file - > ReadBig ( model - > edges [ i ] . internal ) ;
file - > ReadBig ( model - > edges [ i ] . numUsers ) ;
file - > ReadBig ( model - > edges [ i ] . side ) ;
file - > ReadBig ( model - > edges [ i ] . sideSet ) ;
file - > ReadBig ( model - > edges [ i ] . vertexNum [ 0 ] ) ;
file - > ReadBig ( model - > edges [ i ] . vertexNum [ 1 ] ) ;
file - > ReadBig ( model - > edges [ i ] . normal ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
file - > ReadBig ( model - > polygonMemory ) ;
2012-11-28 15:47:07 +00:00
model - > polygonBlock = ( cm_polygonBlock_t * ) Mem_ClearedAlloc ( sizeof ( cm_polygonBlock_t ) + model - > polygonMemory , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
model - > polygonBlock - > bytesRemaining = model - > polygonMemory ;
2012-11-28 15:47:07 +00:00
model - > polygonBlock - > next = ( ( byte * ) model - > polygonBlock ) + sizeof ( cm_polygonBlock_t ) ;
2012-11-26 18:58:24 +00:00
file - > ReadBig ( model - > brushMemory ) ;
2012-11-28 15:47:07 +00:00
model - > brushBlock = ( cm_brushBlock_t * ) Mem_ClearedAlloc ( sizeof ( cm_brushBlock_t ) + model - > brushMemory , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
model - > brushBlock - > bytesRemaining = model - > brushMemory ;
2012-11-28 15:47:07 +00:00
model - > brushBlock - > next = ( ( byte * ) model - > brushBlock ) + sizeof ( cm_brushBlock_t ) ;
2012-11-26 18:58:24 +00:00
int numMaterials = 0 ;
file - > ReadBig ( numMaterials ) ;
2012-11-28 15:47:07 +00:00
idList < const idMaterial * > materials ;
2012-11-26 18:58:24 +00:00
materials . SetNum ( numMaterials ) ;
idStr materialName ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < materials . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > ReadString ( materialName ) ;
2012-11-28 15:47:07 +00:00
if ( materialName . IsEmpty ( ) )
{
2012-11-26 18:58:24 +00:00
materials [ i ] = NULL ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
materials [ i ] = declManager - > FindMaterial ( materialName ) ;
}
}
2012-11-28 15:47:07 +00:00
idList < cm_polygon_t * > polys ;
idList < cm_brush_t * > brushes ;
2012-11-26 18:58:24 +00:00
polys . SetNum ( model - > numPolygons ) ;
brushes . SetNum ( model - > numBrushes ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < polys . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
int materialIndex = 0 ;
file - > ReadBig ( materialIndex ) ;
int numEdges = 0 ;
file - > ReadBig ( numEdges ) ;
polys [ i ] = AllocPolygon ( model , numEdges ) ;
polys [ i ] - > numEdges = numEdges ;
polys [ i ] - > material = materials [ materialIndex ] ;
file - > ReadBig ( polys [ i ] - > bounds ) ;
file - > ReadBig ( polys [ i ] - > checkcount ) ;
file - > ReadBig ( polys [ i ] - > contents ) ;
file - > ReadBig ( polys [ i ] - > plane ) ;
file - > ReadBigArray ( polys [ i ] - > edges , polys [ i ] - > numEdges ) ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < brushes . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
int materialIndex = 0 ;
file - > ReadBig ( materialIndex ) ;
int numPlanes = 0 ;
file - > ReadBig ( numPlanes ) ;
brushes [ i ] = AllocBrush ( model , numPlanes ) ;
brushes [ i ] - > numPlanes = numPlanes ;
brushes [ i ] - > material = materials [ materialIndex ] ;
file - > ReadBig ( brushes [ i ] - > checkcount ) ;
file - > ReadBig ( brushes [ i ] - > bounds ) ;
file - > ReadBig ( brushes [ i ] - > contents ) ;
file - > ReadBig ( brushes [ i ] - > primitiveNum ) ;
file - > ReadBigArray ( brushes [ i ] - > planes , brushes [ i ] - > numPlanes ) ;
}
2012-11-28 15:47:07 +00:00
struct local
{
static void ReadNodeTree ( idFile * file , cm_model_t * model , cm_node_t * node , idList < cm_polygon_t * > & polys , idList < cm_brush_t * > & brushes )
{
2012-11-26 18:58:24 +00:00
file - > ReadBig ( node - > planeType ) ;
file - > ReadBig ( node - > planeDist ) ;
int i = 0 ;
2012-11-28 15:47:07 +00:00
while ( file - > ReadBig ( i ) = = sizeof ( i ) & & ( i > = 0 ) )
{
cm_polygonRef_t * pref = collisionModelManagerLocal . AllocPolygonReference ( model , model - > numPolygonRefs ) ;
2012-11-26 18:58:24 +00:00
pref - > p = polys [ i ] ;
pref - > next = node - > polygons ;
node - > polygons = pref ;
}
2012-11-28 15:47:07 +00:00
while ( file - > ReadBig ( i ) = = sizeof ( i ) & & ( i > = 0 ) )
{
cm_brushRef_t * bref = collisionModelManagerLocal . AllocBrushReference ( model , model - > numBrushRefs ) ;
2012-11-26 18:58:24 +00:00
bref - > b = brushes [ i ] ;
bref - > next = node - > brushes ;
node - > brushes = bref ;
}
2012-11-28 15:47:07 +00:00
if ( node - > planeType ! = - 1 )
{
2012-11-26 18:58:24 +00:00
node - > children [ 0 ] = collisionModelManagerLocal . AllocNode ( model , model - > numNodes ) ;
node - > children [ 1 ] = collisionModelManagerLocal . AllocNode ( model , model - > numNodes ) ;
node - > children [ 0 ] - > parent = node ;
node - > children [ 1 ] - > parent = node ;
ReadNodeTree ( file , model , node - > children [ 0 ] , polys , brushes ) ;
ReadNodeTree ( file , model , node - > children [ 1 ] , polys , brushes ) ;
}
}
} ;
model - > node = AllocNode ( model , model - > numNodes + 1 ) ;
local : : ReadNodeTree ( file , model , model - > node , polys , brushes ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We should have only allocated a single block, and used every entry in the block
// assert( model->nodeBlocks != NULL && model->nodeBlocks->next == NULL && model->nodeBlocks->nextNode == NULL );
assert ( model - > brushRefBlocks = = NULL | | ( model - > brushRefBlocks - > next = = NULL & & model - > brushRefBlocks - > nextRef = = NULL ) ) ;
assert ( model - > polygonRefBlocks = = NULL | | ( model - > polygonRefBlocks - > next = = NULL & & model - > polygonRefBlocks - > nextRef = = NULL ) ) ;
2012-12-16 16:31:21 +00:00
// RB: FIXME
# if !defined(__x86_64__) && !defined(_WIN64)
2012-11-26 18:58:24 +00:00
assert ( model - > polygonBlock - > bytesRemaining = = 0 ) ;
assert ( model - > brushBlock - > bytesRemaining = = 0 ) ;
2012-12-16 16:31:21 +00:00
# endif
// RB end
2012-11-28 15:47:07 +00:00
model - > usedMemory = model - > numVertices * sizeof ( cm_vertex_t ) +
model - > numEdges * sizeof ( cm_edge_t ) +
model - > polygonMemory +
model - > brushMemory +
model - > numNodes * sizeof ( cm_node_t ) +
model - > numPolygonRefs * sizeof ( cm_polygonRef_t ) +
model - > numBrushRefs * sizeof ( cm_brushRef_t ) ;
2012-11-26 18:58:24 +00:00
return model ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : LoadBinaryModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_model_t * idCollisionModelManagerLocal : : LoadBinaryModel ( const char * fileName , ID_TIME_T sourceTimeStamp )
{
2012-11-26 18:58:24 +00:00
idFileLocal file ( fileSystem - > OpenFileReadMemory ( fileName ) ) ;
2012-11-28 15:47:07 +00:00
if ( file = = NULL )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
return LoadBinaryModelFromFile ( file , sourceTimeStamp ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : WriteBinaryModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : WriteBinaryModelToFile ( cm_model_t * model , idFile * file , ID_TIME_T sourceTimeStamp )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( BCM_MAGIC ) ;
file - > WriteBig ( sourceTimeStamp ) ;
file - > WriteString ( model - > name ) ;
file - > WriteBig ( model - > bounds ) ;
file - > WriteBig ( model - > contents ) ;
file - > WriteBig ( model - > isConvex ) ;
file - > WriteBig ( model - > numVertices ) ;
file - > WriteBig ( model - > numEdges ) ;
file - > WriteBig ( model - > numPolygons ) ;
file - > WriteBig ( model - > numBrushes ) ;
file - > WriteBig ( model - > numNodes ) ;
file - > WriteBig ( model - > numBrushRefs ) ;
file - > WriteBig ( model - > numPolygonRefs ) ;
file - > WriteBig ( model - > numInternalEdges ) ;
file - > WriteBig ( model - > numSharpEdges ) ;
file - > WriteBig ( model - > numRemovedPolys ) ;
file - > WriteBig ( model - > numMergedPolys ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < model - > numVertices ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( model - > vertices [ i ] . p ) ;
file - > WriteBig ( model - > vertices [ i ] . checkcount ) ;
file - > WriteBig ( model - > vertices [ i ] . side ) ;
file - > WriteBig ( model - > vertices [ i ] . sideSet ) ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < model - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( model - > edges [ i ] . checkcount ) ;
file - > WriteBig ( model - > edges [ i ] . internal ) ;
file - > WriteBig ( model - > edges [ i ] . numUsers ) ;
file - > WriteBig ( model - > edges [ i ] . side ) ;
file - > WriteBig ( model - > edges [ i ] . sideSet ) ;
file - > WriteBig ( model - > edges [ i ] . vertexNum [ 0 ] ) ;
file - > WriteBig ( model - > edges [ i ] . vertexNum [ 1 ] ) ;
file - > WriteBig ( model - > edges [ i ] . normal ) ;
}
file - > WriteBig ( model - > polygonMemory ) ;
file - > WriteBig ( model - > brushMemory ) ;
2012-11-28 15:47:07 +00:00
struct local
{
static void BuildUniqueLists ( cm_node_t * node , idList < cm_polygon_t * > & polys , idList < cm_brush_t * > & brushes )
{
for ( cm_polygonRef_t * pr = node - > polygons ; pr ! = NULL ; pr = pr - > next )
{
2012-11-26 18:58:24 +00:00
polys . AddUnique ( pr - > p ) ;
}
2012-11-28 15:47:07 +00:00
for ( cm_brushRef_t * br = node - > brushes ; br ! = NULL ; br = br - > next )
{
2012-11-26 18:58:24 +00:00
brushes . AddUnique ( br - > b ) ;
}
2012-11-28 15:47:07 +00:00
if ( node - > planeType ! = - 1 )
{
2012-11-26 18:58:24 +00:00
BuildUniqueLists ( node - > children [ 0 ] , polys , brushes ) ;
BuildUniqueLists ( node - > children [ 1 ] , polys , brushes ) ;
}
}
2012-11-28 15:47:07 +00:00
static void WriteNodeTree ( idFile * file , cm_node_t * node , idList < cm_polygon_t * > & polys , idList < cm_brush_t * > & brushes )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( node - > planeType ) ;
file - > WriteBig ( node - > planeDist ) ;
2012-11-28 15:47:07 +00:00
for ( cm_polygonRef_t * pr = node - > polygons ; pr ! = NULL ; pr = pr - > next )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( polys . FindIndex ( pr - > p ) ) ;
}
file - > WriteBig ( - 1 ) ;
2012-11-28 15:47:07 +00:00
for ( cm_brushRef_t * br = node - > brushes ; br ! = NULL ; br = br - > next )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( brushes . FindIndex ( br - > b ) ) ;
}
file - > WriteBig ( - 1 ) ;
2012-11-28 15:47:07 +00:00
if ( node - > planeType ! = - 1 )
{
2012-11-26 18:58:24 +00:00
WriteNodeTree ( file , node - > children [ 0 ] , polys , brushes ) ;
WriteNodeTree ( file , node - > children [ 1 ] , polys , brushes ) ;
}
}
} ;
2012-11-28 15:47:07 +00:00
idList < cm_polygon_t * > polys ;
idList < cm_brush_t * > brushes ;
2012-11-26 18:58:24 +00:00
local : : BuildUniqueLists ( model - > node , polys , brushes ) ;
assert ( polys . Num ( ) = = model - > numPolygons ) ;
assert ( brushes . Num ( ) = = model - > numBrushes ) ;
2012-11-28 15:47:07 +00:00
idList < const idMaterial * > materials ;
for ( int i = 0 ; i < polys . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
materials . AddUnique ( polys [ i ] - > material ) ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < brushes . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
materials . AddUnique ( brushes [ i ] - > material ) ;
}
file - > WriteBig ( materials . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < materials . Num ( ) ; i + + )
{
if ( materials [ i ] = = NULL )
{
2012-11-26 18:58:24 +00:00
file - > WriteString ( " " ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
file - > WriteString ( materials [ i ] - > GetName ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < polys . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( ( int ) materials . FindIndex ( polys [ i ] - > material ) ) ;
file - > WriteBig ( polys [ i ] - > numEdges ) ;
file - > WriteBig ( polys [ i ] - > bounds ) ;
file - > WriteBig ( polys [ i ] - > checkcount ) ;
file - > WriteBig ( polys [ i ] - > contents ) ;
file - > WriteBig ( polys [ i ] - > plane ) ;
file - > WriteBigArray ( polys [ i ] - > edges , polys [ i ] - > numEdges ) ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < brushes . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
file - > WriteBig ( ( int ) materials . FindIndex ( brushes [ i ] - > material ) ) ;
file - > WriteBig ( brushes [ i ] - > numPlanes ) ;
file - > WriteBig ( brushes [ i ] - > checkcount ) ;
file - > WriteBig ( brushes [ i ] - > bounds ) ;
file - > WriteBig ( brushes [ i ] - > contents ) ;
file - > WriteBig ( brushes [ i ] - > primitiveNum ) ;
file - > WriteBigArray ( brushes [ i ] - > planes , brushes [ i ] - > numPlanes ) ;
}
local : : WriteNodeTree ( file , model - > node , polys , brushes ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : WriteBinaryModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : WriteBinaryModel ( cm_model_t * model , const char * fileName , ID_TIME_T sourceTimeStamp )
{
2012-11-26 18:58:24 +00:00
idFileLocal file ( fileSystem - > OpenFileWrite ( fileName , " fs_basepath " ) ) ;
2012-11-28 15:47:07 +00:00
if ( file = = NULL )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " Failed to open %s \n " , fileName ) ;
return ;
}
WriteBinaryModelToFile ( model , file , sourceTimeStamp ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : LoadRenderModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_model_t * idCollisionModelManagerLocal : : LoadRenderModel ( const char * fileName )
{
2012-11-26 18:58:24 +00:00
int i , j ;
2012-11-28 15:47:07 +00:00
idRenderModel * renderModel ;
const modelSurface_t * surf ;
2012-11-26 18:58:24 +00:00
idFixedWinding w ;
2012-11-28 15:47:07 +00:00
cm_node_t * node ;
cm_model_t * model ;
2012-11-26 18:58:24 +00:00
idPlane plane ;
idBounds bounds ;
bool collisionSurface ;
idStr extension ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// only load ASE and LWO models
idStr ( fileName ) . ExtractFileExtension ( extension ) ;
2012-11-28 15:47:07 +00:00
if ( ( extension . Icmp ( " ase " ) ! = 0 ) & & ( extension . Icmp ( " lwo " ) ! = 0 ) & & ( extension . Icmp ( " ma " ) ! = 0 ) )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderModel = renderModelManager - > CheckModel ( fileName ) ;
2012-11-28 15:47:07 +00:00
if ( ! renderModel )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStrStatic < MAX_OSPATH > generatedFileName = " generated/collision/ " ;
generatedFileName . AppendPath ( fileName ) ;
generatedFileName . SetFileExtension ( CMODEL_BINARYFILE_EXT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ID_TIME_T sourceTimeStamp = renderModel - > Timestamp ( ) ;
model = LoadBinaryModel ( generatedFileName , sourceTimeStamp ) ;
2012-11-28 15:47:07 +00:00
if ( model ! = NULL )
{
2012-11-26 18:58:24 +00:00
return model ;
}
idLib : : Printf ( " Writing %s \n " , generatedFileName . c_str ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model = AllocModel ( ) ;
model - > name = fileName ;
node = AllocNode ( model , NODE_BLOCK_SIZE_SMALL ) ;
node - > planeType = - 1 ;
model - > node = node ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model - > maxVertices = 0 ;
model - > numVertices = 0 ;
model - > maxEdges = 0 ;
model - > numEdges = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bounds = renderModel - > Bounds ( NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
collisionSurface = false ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < renderModel - > NumSurfaces ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
surf = renderModel - > Surface ( i ) ;
2012-11-28 15:47:07 +00:00
if ( surf - > shader - > GetSurfaceFlags ( ) & SURF_COLLISION )
{
2012-11-26 18:58:24 +00:00
collisionSurface = true ;
}
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < renderModel - > NumSurfaces ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
surf = renderModel - > Surface ( i ) ;
// if this surface has no contents
2012-11-28 15:47:07 +00:00
if ( ! ( surf - > shader - > GetContentFlags ( ) & CONTENTS_REMOVE_UTIL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// if the model has a collision surface and this surface is not a collision surface
2012-11-28 15:47:07 +00:00
if ( collisionSurface & & ! ( surf - > shader - > GetSurfaceFlags ( ) & SURF_COLLISION ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// get max verts and edges
model - > maxVertices + = surf - > geometry - > numVerts ;
model - > maxEdges + = surf - > geometry - > numIndexes ;
}
2012-11-28 15:47:07 +00:00
model - > vertices = ( cm_vertex_t * ) Mem_ClearedAlloc ( model - > maxVertices * sizeof ( cm_vertex_t ) , TAG_COLLISION ) ;
model - > edges = ( cm_edge_t * ) Mem_ClearedAlloc ( model - > maxEdges * sizeof ( cm_edge_t ) , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
// setup hash to speed up finding shared vertices and edges
SetupHash ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cm_vertexHash - > ResizeIndex ( model - > maxVertices ) ;
cm_edgeHash - > ResizeIndex ( model - > maxEdges ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ClearHash ( bounds ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < renderModel - > NumSurfaces ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
surf = renderModel - > Surface ( i ) ;
// if this surface has no contents
2012-11-28 15:47:07 +00:00
if ( ! ( surf - > shader - > GetContentFlags ( ) & CONTENTS_REMOVE_UTIL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
// if the model has a collision surface and this surface is not a collision surface
2012-11-28 15:47:07 +00:00
if ( collisionSurface & & ! ( surf - > shader - > GetSurfaceFlags ( ) & SURF_COLLISION ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < surf - > geometry - > numIndexes ; j + = 3 )
{
2012-11-26 18:58:24 +00:00
w . Clear ( ) ;
w + = surf - > geometry - > verts [ surf - > geometry - > indexes [ j + 2 ] ] . xyz ;
w + = surf - > geometry - > verts [ surf - > geometry - > indexes [ j + 1 ] ] . xyz ;
w + = surf - > geometry - > verts [ surf - > geometry - > indexes [ j + 0 ] ] . xyz ;
w . GetPlane ( plane ) ;
plane = - plane ;
PolygonFromWinding ( model , & w , plane , surf - > shader , 1 ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create a BSP tree for the model
model - > node = CreateAxialBSPTree ( model , model - > node ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model - > isConvex = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
FinishModel ( model ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// shutdown the hash
ShutdownHash ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
WriteBinaryModel ( model , generatedFileName , sourceTimeStamp ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return model ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : CollisionModelForMapEntity
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cm_model_t * idCollisionModelManagerLocal : : CollisionModelForMapEntity ( const idMapEntity * mapEnt )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
cm_model_t * model ;
2012-11-26 18:58:24 +00:00
idBounds bounds ;
2012-11-28 15:47:07 +00:00
const char * name ;
2012-11-26 18:58:24 +00:00
int i , brushCount ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the entity has no primitives
2012-11-28 15:47:07 +00:00
if ( mapEnt - > GetNumPrimitives ( ) < 1 )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get a name for the collision model
mapEnt - > epairs . GetString ( " model " , " " , & name ) ;
2012-11-28 15:47:07 +00:00
if ( ! name [ 0 ] )
{
2012-11-26 18:58:24 +00:00
mapEnt - > epairs . GetString ( " name " , " " , & name ) ;
2012-11-28 15:47:07 +00:00
if ( ! name [ 0 ] )
{
if ( ! numModels )
{
2012-11-26 18:58:24 +00:00
// first model is always the world
name = " worldMap " ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
name = " unnamed inline model " ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model = AllocModel ( ) ;
model - > node = AllocNode ( model , NODE_BLOCK_SIZE_SMALL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
CM_EstimateVertsAndEdges ( mapEnt , & model - > maxVertices , & model - > maxEdges ) ;
model - > numVertices = 0 ;
model - > numEdges = 0 ;
2012-11-28 15:47:07 +00:00
model - > vertices = ( cm_vertex_t * ) Mem_ClearedAlloc ( model - > maxVertices * sizeof ( cm_vertex_t ) , TAG_COLLISION ) ;
model - > edges = ( cm_edge_t * ) Mem_ClearedAlloc ( model - > maxEdges * sizeof ( cm_edge_t ) , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
cm_vertexHash - > ResizeIndex ( model - > maxVertices ) ;
cm_edgeHash - > ResizeIndex ( model - > maxEdges ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
model - > name = name ;
model - > isConvex = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// convert brushes
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mapEnt - > GetNumPrimitives ( ) ; i + + )
{
idMapPrimitive * mapPrim ;
mapPrim = mapEnt - > GetPrimitive ( i ) ;
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_BRUSH )
{
ConvertBrush ( model , static_cast < idMapBrush * > ( mapPrim ) , i ) ;
2012-11-26 18:58:24 +00:00
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create an axial bsp tree for the model if it has more than just a bunch brushes
brushCount = CM_CountNodeBrushes ( model - > node ) ;
2012-11-28 15:47:07 +00:00
if ( brushCount > 4 )
{
2012-11-26 18:58:24 +00:00
model - > node = CreateAxialBSPTree ( model , model - > node ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
model - > node - > planeType = - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get bounds for hash
2012-11-28 15:47:07 +00:00
if ( brushCount )
{
2012-11-26 18:58:24 +00:00
CM_GetNodeBounds ( & bounds , model - > node ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
bounds [ 0 ] . Set ( - 256 , - 256 , - 256 ) ;
bounds [ 1 ] . Set ( 256 , 256 , 256 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// different models do not share edges and vertices with each other, so clear the hash
ClearHash ( bounds ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create polygons from patches and brushes
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mapEnt - > GetNumPrimitives ( ) ; i + + )
{
idMapPrimitive * mapPrim ;
mapPrim = mapEnt - > GetPrimitive ( i ) ;
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_PATCH )
{
ConvertPatch ( model , static_cast < idMapPatch * > ( mapPrim ) , i ) ;
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_BRUSH )
{
ConvertBrushSides ( model , static_cast < idMapBrush * > ( mapPrim ) , i ) ;
2012-11-26 18:58:24 +00:00
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
FinishModel ( model ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return model ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : FindModel
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cmHandle_t idCollisionModelManagerLocal : : FindModel ( const char * name )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check if this model is already loaded
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numModels ; i + + )
{
if ( ! models [ i ] - > name . Icmp ( name ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
// if the model is already loaded
2012-11-28 15:47:07 +00:00
if ( i < numModels )
{
2012-11-26 18:58:24 +00:00
return i ;
}
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : PrintModelInfo
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : PrintModelInfo ( const cm_model_t * model )
{
common - > Printf ( " %6i vertices (%i KB) \n " , model - > numVertices , ( model - > numVertices * sizeof ( cm_vertex_t ) ) > > 10 ) ;
common - > Printf ( " %6i edges (%i KB) \n " , model - > numEdges , ( model - > numEdges * sizeof ( cm_edge_t ) ) > > 10 ) ;
common - > Printf ( " %6i polygons (%i KB) \n " , model - > numPolygons , model - > polygonMemory > > 10 ) ;
common - > Printf ( " %6i brushes (%i KB) \n " , model - > numBrushes , model - > brushMemory > > 10 ) ;
common - > Printf ( " %6i nodes (%i KB) \n " , model - > numNodes , ( model - > numNodes * sizeof ( cm_node_t ) ) > > 10 ) ;
common - > Printf ( " %6i polygon refs (%i KB) \n " , model - > numPolygonRefs , ( model - > numPolygonRefs * sizeof ( cm_polygonRef_t ) ) > > 10 ) ;
common - > Printf ( " %6i brush refs (%i KB) \n " , model - > numBrushRefs , ( model - > numBrushRefs * sizeof ( cm_brushRef_t ) ) > > 10 ) ;
2012-11-26 18:58:24 +00:00
common - > Printf ( " %6i internal edges \n " , model - > numInternalEdges ) ;
common - > Printf ( " %6i sharp edges \n " , model - > numSharpEdges ) ;
common - > Printf ( " %6i contained polygons removed \n " , model - > numRemovedPolys ) ;
common - > Printf ( " %6i polygons merged \n " , model - > numMergedPolys ) ;
2012-11-28 15:47:07 +00:00
common - > Printf ( " %6i KB total memory used \n " , model - > usedMemory > > 10 ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : AccumulateModelInfo
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : AccumulateModelInfo ( cm_model_t * model )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
memset ( model , 0 , sizeof ( * model ) ) ;
// accumulate statistics of all loaded models
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numModels ; i + + )
{
2012-11-26 18:58:24 +00:00
model - > numVertices + = models [ i ] - > numVertices ;
model - > numEdges + = models [ i ] - > numEdges ;
model - > numPolygons + = models [ i ] - > numPolygons ;
model - > polygonMemory + = models [ i ] - > polygonMemory ;
model - > numBrushes + = models [ i ] - > numBrushes ;
model - > brushMemory + = models [ i ] - > brushMemory ;
model - > numNodes + = models [ i ] - > numNodes ;
model - > numBrushRefs + = models [ i ] - > numBrushRefs ;
model - > numPolygonRefs + = models [ i ] - > numPolygonRefs ;
model - > numInternalEdges + = models [ i ] - > numInternalEdges ;
model - > numSharpEdges + = models [ i ] - > numSharpEdges ;
model - > numRemovedPolys + = models [ i ] - > numRemovedPolys ;
model - > numMergedPolys + = models [ i ] - > numMergedPolys ;
model - > usedMemory + = models [ i ] - > usedMemory ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ModelInfo
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ModelInfo ( cmHandle_t model )
{
2012-11-26 18:58:24 +00:00
cm_model_t modelInfo ;
2012-11-28 15:47:07 +00:00
if ( model = = - 1 )
{
2012-11-26 18:58:24 +00:00
AccumulateModelInfo ( & modelInfo ) ;
PrintModelInfo ( & modelInfo ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( model < 0 | | model > MAX_SUBMODELS | | model > maxModels )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::ModelInfo: invalid model handle \n " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::ModelInfo: invalid model \n " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
PrintModelInfo ( models [ model ] ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : ListModels
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : ListModels ( )
{
2012-11-26 18:58:24 +00:00
int i , totalMemory ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
totalMemory = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numModels ; i + + )
{
common - > Printf ( " %4d: %5d KB %s \n " , i , ( models [ i ] - > usedMemory > > 10 ) , models [ i ] - > name . c_str ( ) ) ;
2012-11-26 18:58:24 +00:00
totalMemory + = models [ i ] - > usedMemory ;
}
2012-11-28 15:47:07 +00:00
common - > Printf ( " %4d KB in %d models \n " , ( totalMemory > > 10 ) , numModels ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : BuildModels
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : BuildModels ( const idMapFile * mapFile )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
const idMapEntity * mapEnt ;
2012-11-26 18:58:24 +00:00
idTimer timer ;
timer . Start ( ) ;
2012-11-28 15:47:07 +00:00
if ( ! LoadCollisionModelFile ( mapFile - > GetName ( ) , mapFile - > GetGeometryCRC ( ) ) )
{
if ( ! mapFile - > GetNumEntities ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// load the .proc file bsp for data optimisation
LoadProcBSP ( mapFile - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// convert brushes and patches to collision data
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < mapFile - > GetNumEntities ( ) ; i + + )
{
mapEnt = mapFile - > GetEntity ( i ) ;
if ( numModels > = MAX_SUBMODELS )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " idCollisionModelManagerLocal::BuildModels: more than %d collision models " , MAX_SUBMODELS ) ;
break ;
}
models [ numModels ] = CollisionModelForMapEntity ( mapEnt ) ;
2012-11-28 15:47:07 +00:00
if ( models [ numModels ] )
{
2012-11-26 18:58:24 +00:00
numModels + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// free the proc bsp which is only used for data optimization
Mem_Free ( procNodes ) ;
procNodes = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// write the collision models to a file
WriteCollisionModelsToFile ( mapFile - > GetName ( ) , 0 , numModels , mapFile - > GetGeometryCRC ( ) ) ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
timer . Stop ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// print statistics on collision data
cm_model_t model ;
AccumulateModelInfo ( & model ) ;
common - > Printf ( " collision data: \n " ) ;
common - > Printf ( " %6i models \n " , numModels ) ;
PrintModelInfo ( & model ) ;
common - > Printf ( " %.0f msec to load collision data. \n " , timer . Milliseconds ( ) ) ;
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : Preload
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : Preload ( const char * mapName )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! preLoad_Collision . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
idStrStatic < MAX_OSPATH > manifestName = mapName ;
manifestName . Replace ( " game/ " , " maps/ " ) ;
manifestName . Replace ( " maps/maps/ " , " maps/ " ) ;
manifestName . SetFileExtension ( " .preload " ) ;
idPreloadManifest manifest ;
manifest . LoadManifest ( manifestName ) ;
2012-11-28 15:47:07 +00:00
if ( manifest . NumResources ( ) > = 0 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " Preloading collision models... \n " ) ;
int start = Sys_Milliseconds ( ) ;
int numLoaded = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < manifest . NumResources ( ) ; i + + )
{
const preloadEntry_s & p = manifest . GetPreloadByIndex ( i ) ;
if ( p . resType = = PRELOAD_COLLISION )
{
2012-11-26 18:58:24 +00:00
LoadModel ( p . resourceName ) ;
numLoaded + + ;
}
}
int end = Sys_Milliseconds ( ) ;
common - > Printf ( " %05d collision models preloaded ( or were already loaded ) in %5.1f seconds \n " , numLoaded , ( end - start ) * 0.001 ) ;
common - > Printf ( " ---------------------------------------- \n " ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : LoadMap
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCollisionModelManagerLocal : : LoadMap ( const idMapFile * mapFile )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( mapFile = = NULL )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " idCollisionModelManagerLocal::LoadMap: NULL mapFile " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check whether we can keep the current collision map based on the mapName and mapFileTime
2012-11-28 15:47:07 +00:00
if ( loaded )
{
if ( mapName . Icmp ( mapFile - > GetName ( ) ) = = 0 )
{
if ( mapFile - > GetFileTime ( ) = = mapFileTime )
{
2012-11-26 18:58:24 +00:00
common - > DPrintf ( " Using loaded version \n " ) ;
return ;
}
common - > DPrintf ( " Reloading modified map \n " ) ;
}
FreeMap ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear the collision map
Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// models
maxModels = MAX_SUBMODELS ;
numModels = 0 ;
2012-11-28 15:47:07 +00:00
models = ( cm_model_t * * ) Mem_ClearedAlloc ( ( maxModels + 1 ) * sizeof ( cm_model_t * ) , TAG_COLLISION ) ;
2012-11-26 18:58:24 +00:00
// setup hash to speed up finding shared vertices and edges
SetupHash ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > UpdateLevelLoadPacifier ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// setup trace model structure
SetupTrmModelStructure ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > UpdateLevelLoadPacifier ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// build collision models
BuildModels ( mapFile ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > UpdateLevelLoadPacifier ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// save name and time stamp
mapName = mapFile - > GetName ( ) ;
mapFileTime = mapFile - > GetFileTime ( ) ;
loaded = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// shutdown the hash
ShutdownHash ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetModelName
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idCollisionModelManagerLocal : : GetModelName ( cmHandle_t model ) const
{
if ( model < 0 | | model > MAX_SUBMODELS | | model > = numModels | | ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelBounds: invalid model handle \n " ) ;
return " " ;
}
return models [ model ] - > name . c_str ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetModelBounds
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : GetModelBounds ( cmHandle_t model , idBounds & bounds ) const
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( model < 0 | | model > MAX_SUBMODELS | | model > = numModels | | ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelBounds: invalid model handle \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bounds = models [ model ] - > bounds ;
return true ;
}
/*
= = = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetModelContents
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : GetModelContents ( cmHandle_t model , int & contents ) const
{
if ( model < 0 | | model > MAX_SUBMODELS | | model > = numModels | | ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelContents: invalid model handle \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
contents = models [ model ] - > contents ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetModelVertex
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : GetModelVertex ( cmHandle_t model , int vertexNum , idVec3 & vertex ) const
{
if ( model < 0 | | model > MAX_SUBMODELS | | model > = numModels | | ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelVertex: invalid model handle \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
if ( vertexNum < 0 | | vertexNum > = models [ model ] - > numVertices )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelVertex: invalid vertex number \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertex = models [ model ] - > vertices [ vertexNum ] . p ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetModelEdge
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : GetModelEdge ( cmHandle_t model , int edgeNum , idVec3 & start , idVec3 & end ) const
{
if ( model < 0 | | model > MAX_SUBMODELS | | model > = numModels | | ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelEdge: invalid model handle \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
edgeNum = abs ( edgeNum ) ;
2012-11-28 15:47:07 +00:00
if ( edgeNum > = models [ model ] - > numEdges )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelEdge: invalid edge number \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
start = models [ model ] - > vertices [ models [ model ] - > edges [ edgeNum ] . vertexNum [ 0 ] ] . p ;
end = models [ model ] - > vertices [ models [ model ] - > edges [ edgeNum ] . vertexNum [ 1 ] ] . p ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : GetModelPolygon
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : GetModelPolygon ( cmHandle_t model , int polygonNum , idFixedWinding & winding ) const
{
2012-11-26 18:58:24 +00:00
int i , edgeNum ;
2012-11-28 15:47:07 +00:00
cm_polygon_t * poly ;
if ( model < 0 | | model > MAX_SUBMODELS | | model > = numModels | | ! models [ model ] )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::GetModelPolygon: invalid model handle \n " ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
poly = * reinterpret_cast < cm_polygon_t * * > ( & polygonNum ) ;
2012-11-26 18:58:24 +00:00
winding . Clear ( ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < poly - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
edgeNum = poly - > edges [ i ] ;
2012-11-28 15:47:07 +00:00
winding + = models [ model ] - > vertices [ models [ model ] - > edges [ abs ( edgeNum ) ] . vertexNum [ INT32_SIGNBITSET ( edgeNum ) ] ] . p ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : LoadModel
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
cmHandle_t idCollisionModelManagerLocal : : LoadModel ( const char * modelName )
{
2012-11-26 18:58:24 +00:00
int handle ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
handle = FindModel ( modelName ) ;
2012-11-28 15:47:07 +00:00
if ( handle > = 0 )
{
2012-11-26 18:58:24 +00:00
return handle ;
}
2012-11-28 15:47:07 +00:00
if ( numModels > = MAX_SUBMODELS )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " idCollisionModelManagerLocal::LoadModel: no free slots \n " ) ;
return 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStrStatic < MAX_OSPATH > generatedFileName = " generated/collision/ " ;
generatedFileName . AppendPath ( modelName ) ;
generatedFileName . SetFileExtension ( CMODEL_BINARYFILE_EXT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ID_TIME_T sourceTimeStamp = fileSystem - > GetTimestamp ( modelName ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
models [ numModels ] = LoadBinaryModel ( generatedFileName , sourceTimeStamp ) ;
2012-11-28 15:47:07 +00:00
if ( models [ numModels ] ! = NULL )
{
2012-11-26 18:58:24 +00:00
numModels + + ;
2012-11-28 15:47:07 +00:00
if ( cvarSystem - > GetCVarBool ( " fs_buildresources " ) )
{
2012-11-26 18:58:24 +00:00
// for resource gathering write this model to the preload file for this map
fileSystem - > AddCollisionPreload ( modelName ) ;
}
return ( numModels - 1 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// try to load a .cm file
2012-11-28 15:47:07 +00:00
if ( LoadCollisionModelFile ( modelName , 0 ) )
{
2012-11-26 18:58:24 +00:00
handle = FindModel ( modelName ) ;
2012-11-28 15:47:07 +00:00
if ( handle > = 0 & & handle < numModels )
{
cm_model_t * cm = models [ handle ] ;
2012-11-26 18:58:24 +00:00
WriteBinaryModel ( cm , generatedFileName , sourceTimeStamp ) ;
return handle ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
common - > Warning ( " idCollisionModelManagerLocal::LoadModel: collision file for '%s' contains different model " , modelName ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// try to load a .ASE or .LWO model and convert it to a collision model
models [ numModels ] = LoadRenderModel ( modelName ) ;
2012-11-28 15:47:07 +00:00
if ( models [ numModels ] ! = NULL )
{
2012-11-26 18:58:24 +00:00
numModels + + ;
return ( numModels - 1 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return 0 ;
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : TrmFromModel_r
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : TrmFromModel_r ( idTraceModel & trm , cm_node_t * node )
{
cm_polygonRef_t * pref ;
cm_polygon_t * p ;
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
while ( 1 )
{
for ( pref = node - > polygons ; pref ; pref = pref - > next )
{
2012-11-26 18:58:24 +00:00
p = pref - > p ;
2012-11-28 15:47:07 +00:00
if ( p - > checkcount = = checkCount )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
p - > checkcount = checkCount ;
2012-11-28 15:47:07 +00:00
if ( trm . numPolys > = MAX_TRACEMODEL_POLYS )
{
2012-11-26 18:58:24 +00:00
return false ;
}
// copy polygon properties
trm . polys [ trm . numPolys ] . bounds = p - > bounds ;
trm . polys [ trm . numPolys ] . normal = p - > plane . Normal ( ) ;
trm . polys [ trm . numPolys ] . dist = p - > plane . Dist ( ) ;
trm . polys [ trm . numPolys ] . numEdges = p - > numEdges ;
// copy edge index
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < p - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
trm . polys [ trm . numPolys ] . edges [ i ] = p - > edges [ i ] ;
}
trm . numPolys + + ;
}
2012-11-28 15:47:07 +00:00
if ( node - > planeType = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( ! TrmFromModel_r ( trm , node - > children [ 1 ] ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
node = node - > children [ 0 ] ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : TrmFromModel
NOTE : polygon merging can merge colinear edges and as such might cause dangling edges .
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : TrmFromModel ( const cm_model_t * model , idTraceModel & trm )
{
int i , j , numEdgeUsers [ MAX_TRACEMODEL_EDGES + 1 ] ;
2012-11-26 18:58:24 +00:00
// if the model has too many vertices to fit in a trace model
2012-11-28 15:47:07 +00:00
if ( model - > numVertices > MAX_TRACEMODEL_VERTS )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::TrmFromModel: model %s has too many vertices. \n " , model - > name . c_str ( ) ) ;
PrintModelInfo ( model ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// plus one because the collision model accounts for the first unused edge
2012-11-28 15:47:07 +00:00
if ( model - > numEdges > MAX_TRACEMODEL_EDGES + 1 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::TrmFromModel: model %s has too many edges. \n " , model - > name . c_str ( ) ) ;
PrintModelInfo ( model ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
trm . type = TRM_CUSTOM ;
trm . numVerts = 0 ;
trm . numEdges = 1 ;
trm . numPolys = 0 ;
trm . bounds . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy polygons
checkCount + + ;
2012-11-28 15:47:07 +00:00
if ( ! TrmFromModel_r ( trm , model - > node ) )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::TrmFromModel: model %s has too many polygons. \n " , model - > name . c_str ( ) ) ;
PrintModelInfo ( model ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy vertices
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < model - > numVertices ; i + + )
{
2012-11-26 18:58:24 +00:00
trm . verts [ i ] = model - > vertices [ i ] . p ;
trm . bounds . AddPoint ( trm . verts [ i ] ) ;
}
trm . numVerts = model - > numVertices ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy edges
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < model - > numEdges ; i + + )
{
2012-11-26 18:58:24 +00:00
trm . edges [ i ] . v [ 0 ] = model - > edges [ i ] . vertexNum [ 0 ] ;
trm . edges [ i ] . v [ 1 ] = model - > edges [ i ] . vertexNum [ 1 ] ;
}
// minus one because the collision model accounts for the first unused edge
trm . numEdges = model - > numEdges - 1 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// each edge should be used exactly twice
2012-11-28 15:47:07 +00:00
memset ( numEdgeUsers , 0 , sizeof ( numEdgeUsers ) ) ;
for ( i = 0 ; i < trm . numPolys ; i + + )
{
for ( j = 0 ; j < trm . polys [ i ] . numEdges ; j + + )
{
2012-11-26 18:58:24 +00:00
numEdgeUsers [ abs ( trm . polys [ i ] . edges [ j ] ) ] + + ;
}
}
2012-11-28 15:47:07 +00:00
for ( i = 1 ; i < = trm . numEdges ; i + + )
{
if ( numEdgeUsers [ i ] ! = 2 )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::TrmFromModel: model %s has dangling edges, the model has to be an enclosed hull. \n " , model - > name . c_str ( ) ) ;
PrintModelInfo ( model ) ;
return false ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// assume convex
trm . isConvex = true ;
// check if really convex
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < trm . numPolys ; i + + )
{
2012-11-26 18:58:24 +00:00
// to be convex no vertices should be in front of any polygon plane
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < trm . numVerts ; j + + )
{
if ( trm . polys [ i ] . normal * trm . verts [ j ] - trm . polys [ i ] . dist > 0.01f )
{
2012-11-26 18:58:24 +00:00
trm . isConvex = false ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( j < trm . numVerts )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// offset to center of model
trm . offset = trm . bounds . GetCenter ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
trm . GenerateEdgeNormals ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = =
idCollisionModelManagerLocal : : TrmFromModel
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idCollisionModelManagerLocal : : TrmFromModel ( const char * modelName , idTraceModel & trm )
{
2012-11-26 18:58:24 +00:00
cmHandle_t handle ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
handle = LoadModel ( modelName ) ;
2012-11-28 15:47:07 +00:00
if ( ! handle )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " idCollisionModelManagerLocal::TrmFromModel: model %s not found. \n " , modelName ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return TrmFromModel ( models [ handle ] , trm ) ;
}