2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 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.
26 ===========================================================================
29 #include "../../../idlib/precompiled.h"
39 void RemovePortalFromNode( uPortal_t *portal, node_t *l );
41 node_t *NodeForPoint( node_t *node, idVec3 origin ) {
44 while( node->planenum != PLANENUM_LEAF ) {
45 idPlane &plane = dmapGlobals.mapPlanes[node->planenum];
46 d = plane.Distance( origin );
48 node = node->children[0];
50 node = node->children[1];
64 void FreeTreePortals_r (node_t *node)
70 if (node->planenum != PLANENUM_LEAF)
72 FreeTreePortals_r (node->children[0]);
73 FreeTreePortals_r (node->children[1]);
77 for (p=node->portals ; p ; p=nextp)
79 s = (p->nodes[1] == node);
82 RemovePortalFromNode (p, p->nodes[!s]);
93 void FreeTree_r (node_t *node)
96 if (node->planenum != PLANENUM_LEAF)
98 FreeTree_r (node->children[0]);
99 FreeTree_r (node->children[1]);
103 FreeBrushList (node->brushlist);
116 void FreeTree( tree_t *tree ) {
120 FreeTreePortals_r (tree->headnode);
121 FreeTree_r (tree->headnode);
125 //===============================================================
127 void PrintTree_r (node_t *node, int depth)
132 for (i=0 ; i<depth ; i++)
134 if (node->planenum == PLANENUM_LEAF)
136 if (!node->brushlist)
137 common->Printf("NULL\n");
140 for (bb=node->brushlist ; bb ; bb=bb->next)
141 common->Printf("%i ", bb->original->brushnum);
142 common->Printf("\n");
147 idPlane &plane = dmapGlobals.mapPlanes[node->planenum];
148 common->Printf( "#%i (%5.2f %5.2f %5.2f %5.2f)\n", node->planenum,
149 plane[0], plane[1], plane[2], plane[3] );
150 PrintTree_r( node->children[0], depth+1 );
151 PrintTree_r( node->children[1], depth+1 );
159 bspface_t *AllocBspFace( void ) {
162 f = (bspface_t *)Mem_Alloc(sizeof(*f));
163 memset( f, 0, sizeof(*f) );
173 void FreeBspFace( bspface_t *f ) {
186 #define BLOCK_SIZE 1024
187 int SelectSplitPlaneNum( node_t *node, bspface_t *list ) {
190 bspface_t *bestSplit;
191 int splits, facing, front, back;
194 int value, bestValue;
201 // if it is crossing a 1k block boundary, force a split
202 // this prevents epsilon problems from extending an
203 // arbitrary distance across the map
205 halfSize = ( node->bounds[1] - node->bounds[0] ) * 0.5f;
206 for ( int axis = 0; axis < 3; axis++ ) {
207 if ( halfSize[axis] > BLOCK_SIZE ) {
208 dist = BLOCK_SIZE * ( floor( ( node->bounds[0][axis] + halfSize[axis] ) / BLOCK_SIZE ) + 1.0f );
210 dist = BLOCK_SIZE * ( floor( node->bounds[0][axis] / BLOCK_SIZE ) + 1.0f );
212 if ( dist > node->bounds[0][axis] + 1.0f && dist < node->bounds[1][axis] - 1.0f ) {
213 plane[0] = plane[1] = plane[2] = 0.0f;
216 planenum = FindFloatPlane( plane );
221 // pick one of the face planes
222 // if we have any portal faces at all, only
223 // select from them, otherwise select from
229 for ( split = list ; split ; split = split->next ) {
230 split->checked = false;
231 if ( split->portal ) {
236 for ( split = list ; split ; split = split->next ) {
237 if ( split->checked ) {
240 if ( havePortals != split->portal ) {
243 mapPlane = &dmapGlobals.mapPlanes[ split->planenum ];
248 for ( check = list ; check ; check = check->next ) {
249 if ( check->planenum == split->planenum ) {
251 check->checked = true; // won't need to test this plane again
254 side = check->w->PlaneSide( *mapPlane );
255 if ( side == SIDE_CROSS ) {
257 } else if ( side == SIDE_FRONT ) {
259 } else if ( side == SIDE_BACK ) {
263 value = 5*facing - 5*splits; // - abs(front-back);
264 if ( mapPlane->Type() < PLANETYPE_TRUEAXIAL ) {
265 value+=5; // axial is better
268 if ( value > bestValue ) {
274 if ( bestValue == -999999 ) {
278 return bestSplit->planenum;
286 void BuildFaceTree_r( node_t *node, bspface_t *list ) {
291 bspface_t *childLists[2];
292 idWinding *frontWinding, *backWinding;
296 splitPlaneNum = SelectSplitPlaneNum( node, list );
297 // if we don't have any more faces, this is a node
298 if ( splitPlaneNum == -1 ) {
299 node->planenum = PLANENUM_LEAF;
304 // partition the list
305 node->planenum = splitPlaneNum;
306 idPlane &plane = dmapGlobals.mapPlanes[ splitPlaneNum ];
307 childLists[0] = NULL;
308 childLists[1] = NULL;
309 for ( split = list ; split ; split = next ) {
312 if ( split->planenum == node->planenum ) {
313 FreeBspFace( split );
317 side = split->w->PlaneSide( plane );
319 if ( side == SIDE_CROSS ) {
320 split->w->Split( plane, CLIP_EPSILON * 2, &frontWinding, &backWinding );
321 if ( frontWinding ) {
322 newFace = AllocBspFace();
323 newFace->w = frontWinding;
324 newFace->next = childLists[0];
325 newFace->planenum = split->planenum;
326 childLists[0] = newFace;
329 newFace = AllocBspFace();
330 newFace->w = backWinding;
331 newFace->next = childLists[1];
332 newFace->planenum = split->planenum;
333 childLists[1] = newFace;
335 FreeBspFace( split );
336 } else if ( side == SIDE_FRONT ) {
337 split->next = childLists[0];
338 childLists[0] = split;
339 } else if ( side == SIDE_BACK ) {
340 split->next = childLists[1];
341 childLists[1] = split;
346 // recursively process children
347 for ( i = 0 ; i < 2 ; i++ ) {
348 node->children[i] = AllocNode();
349 node->children[i]->parent = node;
350 node->children[i]->bounds = node->bounds;
353 // split the bounds if we have a nice axial plane
354 for ( i = 0 ; i < 3 ; i++ ) {
355 if ( idMath::Fabs( plane[i] - 1.0 ) < 0.001 ) {
356 node->children[0]->bounds[0][i] = plane.Dist();
357 node->children[1]->bounds[1][i] = plane.Dist();
362 for ( i = 0 ; i < 2 ; i++ ) {
363 BuildFaceTree_r ( node->children[i], childLists[i]);
372 List will be freed before returning
375 tree_t *FaceBSP( bspface_t *list ) {
382 start = Sys_Milliseconds();
384 common->Printf( "--- FaceBSP ---\n" );
389 tree->bounds.Clear();
390 for ( face = list ; face ; face = face->next ) {
392 for ( i = 0 ; i < face->w->GetNumPoints() ; i++ ) {
393 tree->bounds.AddPoint( (*face->w)[i].ToVec3() );
396 common->Printf( "%5i faces\n", count );
398 tree->headnode = AllocNode();
399 tree->headnode->bounds = tree->bounds;
402 BuildFaceTree_r ( tree->headnode, list );
404 common->Printf( "%5i leafs\n", c_faceLeafs );
406 end = Sys_Milliseconds();
408 common->Printf( "%5.1f seconds faceBsp\n", ( end - start ) / 1000.0 );
413 //==========================================================================
417 MakeStructuralBspFaceList
420 bspface_t *MakeStructuralBspFaceList( primitive_t *list ) {
425 bspface_t *f, *flist;
428 for ( ; list ; list = list->next ) {
433 if ( !b->opaque && !( b->contents & CONTENTS_AREAPORTAL ) ) {
436 for ( i = 0 ; i < b->numsides ; i++ ) {
442 if ( ( b->contents & CONTENTS_AREAPORTAL ) && ! ( s->material->GetContentFlags() & CONTENTS_AREAPORTAL ) ) {
446 if ( s->material->GetContentFlags() & CONTENTS_AREAPORTAL ) {
450 f->planenum = s->planenum & ~1;
461 MakeVisibleBspFaceList
464 bspface_t *MakeVisibleBspFaceList( primitive_t *list ) {
469 bspface_t *f, *flist;
472 for ( ; list ; list = list->next ) {
477 if ( !b->opaque && !( b->contents & CONTENTS_AREAPORTAL ) ) {
480 for ( i = 0 ; i < b->numsides ; i++ ) {
487 if ( s->material->GetContentFlags() & CONTENTS_AREAPORTAL ) {
491 f->planenum = s->planenum & ~1;