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"
38 // if a brush just barely pokes onto the other side,
39 // let it slide by without chopping
40 #define PLANESIDE_EPSILON 0.001
51 int CountBrushList (uBrush_t *brushes)
56 for ( ; brushes ; brushes = brushes->next)
62 int BrushSizeForSides( int numsides ) {
65 // allocate a structure with a variable number of sides at the end
66 // c = (int)&(((uBrush_t *)0)->sides[numsides]); // bounds checker complains about this
67 c = sizeof( uBrush_t ) + sizeof( side_t ) * (numsides - 6);
77 uBrush_t *AllocBrush (int numsides)
82 c = BrushSizeForSides( numsides );
84 bb = (uBrush_t *)Mem_Alloc(c);
95 void FreeBrush (uBrush_t *brushes)
99 for ( i = 0 ; i < brushes->numsides ; i++ ) {
100 if ( brushes->sides[i].winding ) {
101 delete brushes->sides[i].winding;
103 if ( brushes->sides[i].visibleHull ) {
104 delete brushes->sides[i].visibleHull;
117 void FreeBrushList (uBrush_t *brushes)
121 for ( ; brushes ; brushes = next)
123 next = brushes->next;
133 Duplicates the brush, the sides, and the windings
136 uBrush_t *CopyBrush (uBrush_t *brush)
142 size = BrushSizeForSides( brush->numsides );
144 newbrush = AllocBrush (brush->numsides);
145 memcpy (newbrush, brush, size);
147 for (i=0 ; i<brush->numsides ; i++)
149 if (brush->sides[i].winding)
150 newbrush->sides[i].winding = brush->sides[i].winding->Copy();
162 void DrawBrushList (uBrush_t *brush)
168 for ( ; brush ; brush=brush->next)
170 for (i=0 ; i<brush->numsides ; i++)
172 s = &brush->sides[i];
175 GLS_Winding (s->winding, 0);
187 void PrintBrush (uBrush_t *brush)
191 common->Printf( "brush: %p\n", brush );
192 for ( i=0;i<brush->numsides ; i++ ) {
193 brush->sides[i].winding->Print();
194 common->Printf ("\n");
202 Sets the mins/maxs based on the windings
203 returns false if the brush doesn't enclose a valid volume
206 bool BoundBrush (uBrush_t *brush) {
210 brush->bounds.Clear();
211 for ( i = 0; i < brush->numsides; i++ ) {
212 w = brush->sides[i].winding;
215 for ( j = 0; j < w->GetNumPoints(); j++ )
216 brush->bounds.AddPoint( (*w)[j].ToVec3() );
219 for ( i = 0; i < 3; i++ ) {
220 if (brush->bounds[0][i] < MIN_WORLD_COORD || brush->bounds[1][i] > MAX_WORLD_COORD
221 || brush->bounds[0][i] >= brush->bounds[1][i] ) {
233 makes basewindigs for sides and mins / maxs for the brush
234 returns false if the brush doesn't enclose a valid volume
237 bool CreateBrushWindings (uBrush_t *brush) {
243 for ( i = 0; i < brush->numsides; i++ ) {
244 side = &brush->sides[i];
245 plane = &dmapGlobals.mapPlanes[side->planenum];
246 w = new idWinding( *plane );
247 for ( j = 0; j < brush->numsides && w; j++ ) {
251 if ( brush->sides[j].planenum == ( brush->sides[i].planenum ^ 1 ) ) {
252 continue; // back side clipaway
254 plane = &dmapGlobals.mapPlanes[brush->sides[j].planenum^1];
255 w = w->Clip( *plane, 0 );//CLIP_EPSILON);
257 if ( side->winding ) {
258 delete side->winding;
263 return BoundBrush( brush );
270 Creates a new axial brush
273 uBrush_t *BrushFromBounds( const idBounds &bounds ) {
280 for (i=0 ; i<3 ; i++) {
281 plane[0] = plane[1] = plane[2] = 0;
283 plane[3] = -bounds[1][i];
284 b->sides[i].planenum = FindFloatPlane( plane );
287 plane[3] = bounds[0][i];
288 b->sides[3+i].planenum = FindFloatPlane( plane );
291 CreateBrushWindings (b);
302 float BrushVolume (uBrush_t *brush) {
306 float d, area, volume;
312 // grab the first valid point as the corner
315 for ( i = 0; i < brush->numsides; i++ ) {
316 w = brush->sides[i].winding;
323 VectorCopy ( (*w)[0], corner);
325 // make tetrahedrons to all other faces
328 for ( ; i < brush->numsides; i++ )
330 w = brush->sides[i].winding;
333 plane = &dmapGlobals.mapPlanes[brush->sides[i].planenum];
334 d = -plane->Distance( corner );
348 FIXME: use new brush format
351 void WriteBspBrushMap( const char *name, uBrush_t *list ) {
357 common->Printf ("writing %s\n", name);
358 f = fileSystem->OpenFileWrite( name );
361 common->Error( "Can't write %s\b", name);
364 f->Printf( "{\n\"classname\" \"worldspawn\"\n" );
366 for ( ; list ; list=list->next )
369 for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
371 w = new idWinding( dmapGlobals.mapPlanes[s->planenum] );
373 f->Printf ("( %i %i %i ) ", (int)(*w)[0][0], (int)(*w)[0][1], (int)(*w)[0][2]);
374 f->Printf ("( %i %i %i ) ", (int)(*w)[1][0], (int)(*w)[1][1], (int)(*w)[1][2]);
375 f->Printf ("( %i %i %i ) ", (int)(*w)[2][0], (int)(*w)[2][1], (int)(*w)[2][2]);
377 f->Printf ("notexture 0 0 0 1 1\n" );
384 fileSystem->CloseFile(f);
389 //=====================================================================================
393 FilterBrushIntoTree_r
397 int FilterBrushIntoTree_r( uBrush_t *b, node_t *node ) {
398 uBrush_t *front, *back;
405 // add it to the leaf list
406 if ( node->planenum == PLANENUM_LEAF ) {
407 b->next = node->brushlist;
410 // classify the leaf by the structural brush
418 // split it by the node plane
419 SplitBrush ( b, node->planenum, &front, &back );
423 c += FilterBrushIntoTree_r( front, node->children[0] );
424 c += FilterBrushIntoTree_r( back, node->children[1] );
431 =====================
432 FilterBrushesIntoTree
434 Mark the leafs as opaque and areaportals and put brush
435 fragments in each leaf so portal surfaces can be matched
437 =====================
439 void FilterBrushesIntoTree( uEntity_t *e ) {
443 int c_unique, c_clusters;
445 common->Printf( "----- FilterBrushesIntoTree -----\n");
449 for ( prim = e->primitives ; prim ; prim = prim->next ) {
455 newb = CopyBrush( b );
456 r = FilterBrushIntoTree_r( newb, e->tree->headnode );
460 common->Printf( "%5i total brushes\n", c_unique );
461 common->Printf( "%5i cluster references\n", c_clusters );
471 tree_t *AllocTree (void)
475 tree = (tree_t *)Mem_Alloc(sizeof(*tree));
476 memset (tree, 0, sizeof(*tree));
477 tree->bounds.Clear();
487 node_t *AllocNode (void)
491 node = (node_t *)Mem_Alloc(sizeof(*node));
492 memset (node, 0, sizeof(*node));
497 //============================================================
505 int BrushMostlyOnSide (uBrush_t *brush, idPlane &plane) {
513 for ( i = 0; i < brush->numsides; i++ ) {
514 w = brush->sides[i].winding;
517 for ( j = 0; j < w->GetNumPoints(); j++ )
519 d = plane.Distance( (*w)[j].ToVec3() );
539 Generates two new brushes, leaving the original
543 void SplitBrush (uBrush_t *brush, int planenum, uBrush_t **front, uBrush_t **back) {
546 idWinding *w, *cw[2], *midwinding;
548 float d, d_front, d_back;
550 *front = *back = NULL;
551 idPlane &plane = dmapGlobals.mapPlanes[planenum];
554 d_front = d_back = 0;
555 for ( i = 0; i < brush->numsides; i++ )
557 w = brush->sides[i].winding;
561 for ( j = 0; j < w->GetNumPoints(); j++ ) {
562 d = plane.Distance( (*w)[j].ToVec3() );
563 if (d > 0 && d > d_front)
565 if (d < 0 && d < d_back)
569 if (d_front < 0.1) // PLANESIDE_EPSILON)
571 *back = CopyBrush( brush );
574 if (d_back > -0.1) // PLANESIDE_EPSILON)
576 *front = CopyBrush( brush );
580 // create a new winding from the split plane
582 w = new idWinding( plane );
583 for ( i = 0; i < brush->numsides && w; i++ ) {
584 idPlane &plane2 = dmapGlobals.mapPlanes[brush->sides[i].planenum ^ 1];
585 w = w->Clip( plane2, 0 ); // PLANESIDE_EPSILON);
588 if ( !w || w->IsTiny() ) {
589 // the brush isn't really split
592 side = BrushMostlyOnSide( brush, plane );
593 if (side == PSIDE_FRONT)
594 *front = CopyBrush (brush);
595 if (side == PSIDE_BACK)
596 *back = CopyBrush (brush);
601 common->Printf ("WARNING: huge winding\n");
608 for ( i = 0; i < 2; i++ ) {
609 b[i] = AllocBrush (brush->numsides+1);
610 memcpy( b[i], brush, sizeof( uBrush_t ) - sizeof( brush->sides ) );
613 b[i]->original = brush->original;
616 // split all the current windings
618 for ( i = 0; i < brush->numsides; i++ ) {
619 s = &brush->sides[i];
623 w->Split( plane, 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1] );
624 for ( j = 0; j < 2; j++ ) {
629 if ( cw[j]->IsTiny() )
635 cs = &b[j]->sides[b[j]->numsides];
643 // see if we have valid polygons on both sides
645 for (i=0 ; i<2 ; i++)
647 if ( !BoundBrush (b[i]) ) {
651 if ( b[i]->numsides < 3 )
658 if ( !(b[0] && b[1]) )
661 common->Printf ("split removed brush\n");
663 common->Printf ("split not on both sides\n");
667 *front = CopyBrush (brush);
672 *back = CopyBrush (brush);
677 // add the midwinding to both sides
678 for (i=0 ; i<2 ; i++)
680 cs = &b[i]->sides[b[i]->numsides];
683 cs->planenum = planenum^i^1;
686 cs->winding = midwinding->Copy();
688 cs->winding = midwinding;
695 for (i=0 ; i<2 ; i++)
697 v1 = BrushVolume (b[i]);
702 // common->Printf ("tiny volume after clip\n");