doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
portals.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
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.
13 
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.
18 
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/>.
21 
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.
23 
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.
25 
26 ===========================================================================
27 */
28 
29 #include "../../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "dmap.h"
33 
34 
37 
38 
41 
42 /*
43 ===========
44 AllocPortal
45 ===========
46 */
48 {
49  uPortal_t *p;
50 
54 
55  p = (uPortal_t *)Mem_Alloc (sizeof(uPortal_t ));
56  memset (p, 0, sizeof(uPortal_t ));
57 
58  return p;
59 }
60 
61 
63 {
64  if (p->winding)
65  delete p->winding;
67  Mem_Free (p);
68 }
69 
70 //==============================================================
71 
72 /*
73 =============
74 Portal_Passable
75 
76 Returns true if the portal has non-opaque leafs on both sides
77 =============
78 */
79 static bool Portal_Passable( uPortal_t *p ) {
80  if (!p->onnode) {
81  return false; // to global outsideleaf
82  }
83 
84  if (p->nodes[0]->planenum != PLANENUM_LEAF
85  || p->nodes[1]->planenum != PLANENUM_LEAF) {
86  common->Error( "Portal_EntityFlood: not a leaf");
87  }
88 
89  if ( !p->nodes[0]->opaque && !p->nodes[1]->opaque ) {
90  return true;
91  }
92 
93  return false;
94 }
95 
96 
97 //=============================================================================
98 
100 
101 /*
102 =============
103 AddPortalToNodes
104 =============
105 */
106 void AddPortalToNodes (uPortal_t *p, node_t *front, node_t *back) {
107  if (p->nodes[0] || p->nodes[1]) {
108  common->Error( "AddPortalToNode: allready included");
109  }
110 
111  p->nodes[0] = front;
112  p->next[0] = front->portals;
113  front->portals = p;
114 
115  p->nodes[1] = back;
116  p->next[1] = back->portals;
117  back->portals = p;
118 }
119 
120 
121 /*
122 =============
123 RemovePortalFromNode
124 =============
125 */
127 {
128  uPortal_t **pp, *t;
129 
130 // remove reference to the current portal
131  pp = &l->portals;
132  while (1)
133  {
134  t = *pp;
135  if (!t)
136  common->Error( "RemovePortalFromNode: portal not in leaf");
137 
138  if ( t == portal )
139  break;
140 
141  if (t->nodes[0] == l)
142  pp = &t->next[0];
143  else if (t->nodes[1] == l)
144  pp = &t->next[1];
145  else
146  common->Error( "RemovePortalFromNode: portal not bounding leaf");
147  }
148 
149  if ( portal->nodes[0] == l ) {
150  *pp = portal->next[0];
151  portal->nodes[0] = NULL;
152  } else if ( portal->nodes[1] == l ) {
153  *pp = portal->next[1];
154  portal->nodes[1] = NULL;
155  } else {
156  common->Error( "RemovePortalFromNode: mislinked" );
157  }
158 }
159 
160 //============================================================================
161 
163 {
164  int i;
165  idWinding *w;
166 
167  w = p->winding;
168  for ( i = 0; i < w->GetNumPoints(); i++ )
169  common->Printf("(%5.0f,%5.0f,%5.0f)\n",(*w)[i][0], (*w)[i][1], (*w)[i][2]);
170 }
171 
172 /*
173 ================
174 MakeHeadnodePortals
175 
176 The created portals will face the global outside_node
177 ================
178 */
179 #define SIDESPACE 8
180 static void MakeHeadnodePortals( tree_t *tree ) {
181  idBounds bounds;
182  int i, j, n;
183  uPortal_t *p, *portals[6];
184  idPlane bplanes[6], *pl;
185  node_t *node;
186 
187  node = tree->headnode;
188 
190  tree->outside_node.brushlist = NULL;
191  tree->outside_node.portals = NULL;
192  tree->outside_node.opaque = false;
193 
194  // if no nodes, don't go any farther
195  if ( node->planenum == PLANENUM_LEAF ) {
196  return;
197  }
198 
199  // pad with some space so there will never be null volume leafs
200  for (i=0 ; i<3 ; i++) {
201  bounds[0][i] = tree->bounds[0][i] - SIDESPACE;
202  bounds[1][i] = tree->bounds[1][i] + SIDESPACE;
203  if ( bounds[0][i] >= bounds[1][i] ) {
204  common->Error( "Backwards tree volume" );
205  }
206  }
207 
208  for (i=0 ; i<3 ; i++) {
209  for (j=0 ; j<2 ; j++) {
210  n = j*3 + i;
211 
212  p = AllocPortal ();
213  portals[n] = p;
214 
215  pl = &bplanes[n];
216  memset (pl, 0, sizeof(*pl));
217  if (j) {
218  (*pl)[i] = -1;
219  (*pl)[3] = bounds[j][i];
220  } else {
221  (*pl)[i] = 1;
222  (*pl)[3] = -bounds[j][i];
223  }
224  p->plane = *pl;
225  p->winding = new idWinding( *pl );
226  AddPortalToNodes (p, node, &tree->outside_node);
227  }
228  }
229 
230  // clip the basewindings by all the other planes
231  for (i=0 ; i<6 ; i++) {
232  for (j=0 ; j<6 ; j++) {
233  if (j == i) {
234  continue;
235  }
236  portals[i]->winding = portals[i]->winding->Clip( bplanes[j], ON_EPSILON );
237  }
238  }
239 }
240 
241 //===================================================
242 
243 
244 /*
245 ================
246 BaseWindingForNode
247 ================
248 */
249 #define BASE_WINDING_EPSILON 0.001f
250 #define SPLIT_WINDING_EPSILON 0.001f
251 
253  idWinding *w;
254  node_t *n;
255 
256  w = new idWinding( dmapGlobals.mapPlanes[node->planenum] );
257 
258  // clip by all the parents
259  for ( n = node->parent ; n && w ; ) {
260  idPlane &plane = dmapGlobals.mapPlanes[n->planenum];
261 
262  if ( n->children[0] == node ) {
263  // take front
264  w = w->Clip( plane, BASE_WINDING_EPSILON );
265  } else {
266  // take back
267  idPlane back = -plane;
268  w = w->Clip( back, BASE_WINDING_EPSILON );
269  }
270  node = n;
271  n = n->parent;
272  }
273 
274  return w;
275 }
276 
277 //============================================================
278 
279 /*
280 ==================
281 MakeNodePortal
282 
283 create the new portal by taking the full plane winding for the cutting plane
284 and clipping it by all of parents of this node
285 ==================
286 */
287 static void MakeNodePortal( node_t *node ) {
288  uPortal_t *new_portal, *p;
289  idWinding *w;
290  idVec3 normal;
291  int side;
292 
293  w = BaseWindingForNode (node);
294 
295  // clip the portal by all the other portals in the node
296  for (p = node->portals ; p && w; p = p->next[side])
297  {
298  idPlane plane;
299 
300  if (p->nodes[0] == node)
301  {
302  side = 0;
303  plane = p->plane;
304  }
305  else if (p->nodes[1] == node)
306  {
307  side = 1;
308  plane = -p->plane;
309  }
310  else {
311  common->Error( "CutNodePortals_r: mislinked portal");
312  side = 0; // quiet a compiler warning
313  }
314 
315  w = w->Clip( plane, CLIP_EPSILON );
316  }
317 
318  if (!w)
319  {
320  return;
321  }
322 
323  if ( w->IsTiny() )
324  {
325  c_tinyportals++;
326  delete w;
327  return;
328  }
329 
330 
331  new_portal = AllocPortal ();
332  new_portal->plane = dmapGlobals.mapPlanes[node->planenum];
333  new_portal->onnode = node;
334  new_portal->winding = w;
335  AddPortalToNodes (new_portal, node->children[0], node->children[1]);
336 }
337 
338 
339 /*
340 ==============
341 SplitNodePortals
342 
343 Move or split the portals that bound node so that the node's
344 children have portals instead of node.
345 ==============
346 */
347 static void SplitNodePortals( node_t *node ) {
348  uPortal_t *p, *next_portal, *new_portal;
349  node_t *f, *b, *other_node;
350  int side;
351  idPlane *plane;
352  idWinding *frontwinding, *backwinding;
353 
354  plane = &dmapGlobals.mapPlanes[node->planenum];
355  f = node->children[0];
356  b = node->children[1];
357 
358  for ( p = node->portals ; p ; p = next_portal ) {
359  if (p->nodes[0] == node ) {
360  side = 0;
361  } else if ( p->nodes[1] == node ) {
362  side = 1;
363  } else {
364  common->Error( "SplitNodePortals: mislinked portal" );
365  side = 0; // quiet a compiler warning
366  }
367  next_portal = p->next[side];
368 
369  other_node = p->nodes[!side];
370  RemovePortalFromNode (p, p->nodes[0]);
371  RemovePortalFromNode (p, p->nodes[1]);
372 
373  //
374  // cut the portal into two portals, one on each side of the cut plane
375  //
376  p->winding->Split( *plane, SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
377 
378  if ( frontwinding && frontwinding->IsTiny() )
379  {
380  delete frontwinding;
381  frontwinding = NULL;
382  c_tinyportals++;
383  }
384 
385  if ( backwinding && backwinding->IsTiny() )
386  {
387  delete backwinding;
388  backwinding = NULL;
389  c_tinyportals++;
390  }
391 
392  if ( !frontwinding && !backwinding )
393  { // tiny windings on both sides
394  continue;
395  }
396 
397  if (!frontwinding)
398  {
399  delete backwinding;
400  if (side == 0)
401  AddPortalToNodes (p, b, other_node);
402  else
403  AddPortalToNodes (p, other_node, b);
404  continue;
405  }
406  if (!backwinding)
407  {
408  delete frontwinding;
409  if (side == 0)
410  AddPortalToNodes (p, f, other_node);
411  else
412  AddPortalToNodes (p, other_node, f);
413  continue;
414  }
415 
416  // the winding is split
417  new_portal = AllocPortal ();
418  *new_portal = *p;
419  new_portal->winding = backwinding;
420  delete p->winding;
421  p->winding = frontwinding;
422 
423  if (side == 0)
424  {
425  AddPortalToNodes (p, f, other_node);
426  AddPortalToNodes (new_portal, b, other_node);
427  }
428  else
429  {
430  AddPortalToNodes (p, other_node, f);
431  AddPortalToNodes (new_portal, other_node, b);
432  }
433  }
434 
435  node->portals = NULL;
436 }
437 
438 
439 /*
440 ================
441 CalcNodeBounds
442 ================
443 */
444 void CalcNodeBounds (node_t *node)
445 {
446  uPortal_t *p;
447  int s;
448  int i;
449 
450  // calc mins/maxs for both leafs and nodes
451  node->bounds.Clear();
452  for (p = node->portals ; p ; p = p->next[s]) {
453  s = (p->nodes[1] == node);
454  for ( i = 0; i < p->winding->GetNumPoints(); i++ ) {
455  node->bounds.AddPoint( (*p->winding)[i].ToVec3() );
456  }
457  }
458 }
459 
460 
461 /*
462 ==================
463 MakeTreePortals_r
464 ==================
465 */
467 {
468  int i;
469 
470  CalcNodeBounds( node );
471 
472  if ( node->bounds[0][0] >= node->bounds[1][0]) {
473  common->Warning( "node without a volume" );
474  }
475 
476  for ( i = 0; i < 3; i++ ) {
477  if ( node->bounds[0][i] < MIN_WORLD_COORD || node->bounds[1][i] > MAX_WORLD_COORD ) {
478  common->Warning( "node with unbounded volume");
479  break;
480  }
481  }
482  if ( node->planenum == PLANENUM_LEAF ) {
483  return;
484  }
485 
486  MakeNodePortal (node);
487  SplitNodePortals (node);
488 
489  MakeTreePortals_r (node->children[0]);
490  MakeTreePortals_r (node->children[1]);
491 }
492 
493 /*
494 ==================
495 MakeTreePortals
496 ==================
497 */
499 {
500  common->Printf( "----- MakeTreePortals -----\n");
501  MakeHeadnodePortals (tree);
502  MakeTreePortals_r (tree->headnode);
503 }
504 
505 /*
506 =========================================================
507 
508 FLOOD ENTITIES
509 
510 =========================================================
511 */
512 
514 
515 /*
516 =============
517 FloodPortals_r
518 =============
519 */
520 void FloodPortals_r (node_t *node, int dist) {
521  uPortal_t *p;
522  int s;
523 
524  if ( node->occupied ) {
525  return;
526  }
527 
528  if ( node->opaque ) {
529  return;
530  }
531 
532  c_floodedleafs++;
533  node->occupied = dist;
534 
535  for (p=node->portals ; p ; p = p->next[s]) {
536  s = (p->nodes[1] == node);
537  FloodPortals_r (p->nodes[!s], dist+1);
538  }
539 }
540 
541 /*
542 =============
543 PlaceOccupant
544 =============
545 */
546 bool PlaceOccupant( node_t *headnode, idVec3 origin, uEntity_t *occupant ) {
547  node_t *node;
548  float d;
549  idPlane *plane;
550 
551  // find the leaf to start in
552  node = headnode;
553  while ( node->planenum != PLANENUM_LEAF ) {
554  plane = &dmapGlobals.mapPlanes[node->planenum];
555  d = plane->Distance( origin );
556  if ( d >= 0.0f ) {
557  node = node->children[0];
558  } else {
559  node = node->children[1];
560  }
561  }
562 
563  if ( node->opaque ) {
564  return false;
565  }
566  node->occupant = occupant;
567 
568  FloodPortals_r (node, 1);
569 
570  return true;
571 }
572 
573 /*
574 =============
575 FloodEntities
576 
577 Marks all nodes that can be reached by entites
578 =============
579 */
580 bool FloodEntities( tree_t *tree ) {
581  int i;
582  idVec3 origin;
583  const char *cl;
584  bool inside;
585  node_t *headnode;
586 
587  headnode = tree->headnode;
588  common->Printf ("--- FloodEntities ---\n");
589  inside = false;
590  tree->outside_node.occupied = 0;
591 
592  c_floodedleafs = 0;
593  bool errorShown = false;
594  for (i=1 ; i<dmapGlobals.num_entities ; i++) {
595  idMapEntity *mapEnt;
596 
597  mapEnt = dmapGlobals.uEntities[i].mapEntity;
598  if ( !mapEnt->epairs.GetVector( "origin", "", origin) ) {
599  continue;
600  }
601 
602  // any entity can have "noFlood" set to skip it
603  if ( mapEnt->epairs.GetString( "noFlood", "", &cl ) ) {
604  continue;
605  }
606 
607  mapEnt->epairs.GetString( "classname", "", &cl );
608 
609  if ( !strcmp( cl, "light" ) ) {
610  const char *v;
611 
612  // don't place lights that have a light_start field, because they can still
613  // be valid if their origin is outside the world
614  mapEnt->epairs.GetString( "light_start", "", &v);
615  if ( v[0] ) {
616  continue;
617  }
618 
619  // don't place fog lights, because they often
620  // have origins outside the light
621  mapEnt->epairs.GetString( "texture", "", &v);
622  if ( v[0] ) {
623  const idMaterial *mat = declManager->FindMaterial( v );
624  if ( mat->IsFogLight() ) {
625  continue;
626  }
627  }
628  }
629 
630  if (PlaceOccupant (headnode, origin, &dmapGlobals.uEntities[i])) {
631  inside = true;
632  }
633 
634  if (tree->outside_node.occupied && !errorShown) {
635  errorShown = true;
636  common->Printf("Leak on entity # %d\n", i);
637  const char *p;
638 
639  mapEnt->epairs.GetString( "classname", "", &p);
640  common->Printf("Entity classname was: %s\n", p);
641  mapEnt->epairs.GetString( "name", "", &p);
642  common->Printf("Entity name was: %s\n", p);
643  idVec3 origin;
644  if ( mapEnt->epairs.GetVector( "origin", "", origin)) {
645  common->Printf("Entity origin is: %f %f %f\n\n\n", origin.x, origin.y, origin.z);
646  }
647  }
648  }
649 
650  common->Printf("%5i flooded leafs\n", c_floodedleafs );
651 
652  if (!inside)
653  {
654  common->Printf ("no entities in open -- no filling\n");
655  }
656  else if (tree->outside_node.occupied)
657  {
658  common->Printf ("entity reached from outside -- no filling\n");
659  }
660 
661  return (bool)(inside && !tree->outside_node.occupied);
662 }
663 
664 /*
665 =========================================================
666 
667 FLOOD AREAS
668 
669 =========================================================
670 */
671 
672 static int c_areas;
673 static int c_areaFloods;
674 
675 /*
676 =================
677 FindSideForPortal
678 =================
679 */
680 static side_t *FindSideForPortal( uPortal_t *p ) {
681  int i, j, k;
682  node_t *node;
683  uBrush_t *b, *orig;
684  side_t *s, *s2;
685 
686  // scan both bordering nodes brush lists for a portal brush
687  // that shares the plane
688  for ( i = 0 ; i < 2 ; i++ ) {
689  node = p->nodes[i];
690  for ( b = node->brushlist ; b ; b = b->next ) {
691  if ( !( b->contents & CONTENTS_AREAPORTAL ) ) {
692  continue;
693  }
694  orig = b->original;
695  for ( j = 0 ; j < orig->numsides ; j++ ) {
696  s = orig->sides + j;
697  if ( !s->visibleHull ) {
698  continue;
699  }
700  if ( !( s->material->GetContentFlags() & CONTENTS_AREAPORTAL ) ) {
701  continue;
702  }
703  if ( ( s->planenum & ~1 ) != ( p->onnode->planenum & ~1 ) ) {
704  continue;
705  }
706  // remove the visible hull from any other portal sides of this portal brush
707  for ( k = 0; k < orig->numsides; k++ ) {
708  if ( k == j ) {
709  continue;
710  }
711  s2 = orig->sides + k;
712  if ( s2->visibleHull == NULL ) {
713  continue;
714  }
715  if ( !( s2->material->GetContentFlags() & CONTENTS_AREAPORTAL ) ) {
716  continue;
717  }
718  common->Warning( "brush has multiple area portal sides at %s", s2->visibleHull->GetCenter().ToString() );
719  delete s2->visibleHull;
720  s2->visibleHull = NULL;
721  }
722  return s;
723  }
724  }
725  }
726  return NULL;
727 }
728 
729 /*
730 =============
731 FloodAreas_r
732 =============
733 */
734 void FloodAreas_r (node_t *node)
735 {
736  uPortal_t *p;
737  int s;
738 
739  if ( node->area != -1 ) {
740  return; // allready got it
741  }
742  if ( node->opaque ) {
743  return;
744  }
745 
746  c_areaFloods++;
747  node->area = c_areas;
748 
749  for ( p=node->portals ; p ; p = p->next[s] ) {
750  node_t *other;
751 
752  s = (p->nodes[1] == node);
753  other = p->nodes[!s];
754 
755  if ( !Portal_Passable(p) ) {
756  continue;
757  }
758 
759  // can't flood through an area portal
760  if ( FindSideForPortal( p ) ) {
761  continue;
762  }
763 
764  FloodAreas_r( other );
765  }
766 }
767 
768 /*
769 =============
770 FindAreas_r
771 
772 Just decend the tree, and for each node that hasn't had an
773 area set, flood fill out from there
774 =============
775 */
776 void FindAreas_r( node_t *node ) {
777  if ( node->planenum != PLANENUM_LEAF ) {
778  FindAreas_r (node->children[0]);
779  FindAreas_r (node->children[1]);
780  return;
781  }
782 
783  if ( node->opaque ) {
784  return;
785  }
786 
787  if ( node->area != -1 ) {
788  return; // allready got it
789  }
790 
791  c_areaFloods = 0;
792  FloodAreas_r (node);
793  common->Printf( "area %i has %i leafs\n", c_areas, c_areaFloods );
794  c_areas++;
795 }
796 
797 /*
798 ============
799 CheckAreas_r
800 ============
801 */
802 void CheckAreas_r( node_t *node ) {
803  if ( node->planenum != PLANENUM_LEAF ) {
804  CheckAreas_r (node->children[0]);
805  CheckAreas_r (node->children[1]);
806  return;
807  }
808  if ( !node->opaque && node->area < 0 ) {
809  common->Error( "CheckAreas_r: area = %i", node->area );
810  }
811 }
812 
813 /*
814 ============
815 ClearAreas_r
816 
817 Set all the areas to -1 before filling
818 ============
819 */
820 void ClearAreas_r( node_t *node ) {
821  if ( node->planenum != PLANENUM_LEAF ) {
822  ClearAreas_r (node->children[0]);
823  ClearAreas_r (node->children[1]);
824  return;
825  }
826  node->area = -1;
827 }
828 
829 //=============================================================
830 
831 
832 /*
833 =================
834 FindInterAreaPortals_r
835 
836 =================
837 */
838 static void FindInterAreaPortals_r( node_t *node ) {
839  uPortal_t *p;
840  int s;
841  int i;
842  idWinding *w;
843  interAreaPortal_t *iap;
844  side_t *side;
845 
846  if ( node->planenum != PLANENUM_LEAF ) {
847  FindInterAreaPortals_r( node->children[0] );
848  FindInterAreaPortals_r( node->children[1] );
849  return;
850  }
851 
852  if ( node->opaque ) {
853  return;
854  }
855 
856  for ( p=node->portals ; p ; p = p->next[s] ) {
857  node_t *other;
858 
859  s = (p->nodes[1] == node);
860  other = p->nodes[!s];
861 
862  if ( other->opaque ) {
863  continue;
864  }
865 
866  // only report areas going from lower number to higher number
867  // so we don't report the portal twice
868  if ( other->area <= node->area ) {
869  continue;
870  }
871 
872  side = FindSideForPortal( p );
873 // w = p->winding;
874  if ( !side ) {
875  common->Warning( "FindSideForPortal failed at %s", p->winding->GetCenter().ToString() );
876  continue;
877  }
878  w = side->visibleHull;
879  if ( !w ) {
880  continue;
881  }
882 
883  // see if we have created this portal before
884  for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
885  iap = &interAreaPortals[i];
886 
887  if ( side == iap->side &&
888  ( ( p->nodes[0]->area == iap->area0 && p->nodes[1]->area == iap->area1 )
889  || ( p->nodes[1]->area == iap->area0 && p->nodes[0]->area == iap->area1 ) ) ) {
890  break;
891  }
892  }
893 
894  if ( i != numInterAreaPortals ) {
895  continue; // already emited
896  }
897 
898  iap = &interAreaPortals[numInterAreaPortals];
899  numInterAreaPortals++;
900  if ( side->planenum == p->onnode->planenum ) {
901  iap->area0 = p->nodes[0]->area;
902  iap->area1 = p->nodes[1]->area;
903  } else {
904  iap->area0 = p->nodes[1]->area;
905  iap->area1 = p->nodes[0]->area;
906  }
907  iap->side = side;
908 
909  }
910 }
911 
912 
913 
914 
915 
916 /*
917 =============
918 FloodAreas
919 
920 Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
921 Sets e->areas.numAreas
922 =============
923 */
924 void FloodAreas( uEntity_t *e ) {
925  common->Printf ("--- FloodAreas ---\n");
926 
927  // set all areas to -1
928  ClearAreas_r( e->tree->headnode );
929 
930  // flood fill from non-opaque areas
931  c_areas = 0;
932  FindAreas_r( e->tree->headnode );
933 
934  common->Printf ("%5i areas\n", c_areas);
935  e->numAreas = c_areas;
936 
937  // make sure we got all of them
938  CheckAreas_r( e->tree->headnode );
939 
940  // identify all portals between areas if this is the world
941  if ( e == &dmapGlobals.uEntities[0] ) {
942  numInterAreaPortals = 0;
943  FindInterAreaPortals_r( e->tree->headnode );
944  }
945 }
946 
947 /*
948 ======================================================
949 
950 FILL OUTSIDE
951 
952 ======================================================
953 */
954 
955 static int c_outside;
956 static int c_inside;
957 static int c_solid;
958 
959 void FillOutside_r (node_t *node)
960 {
961  if (node->planenum != PLANENUM_LEAF)
962  {
963  FillOutside_r (node->children[0]);
964  FillOutside_r (node->children[1]);
965  return;
966  }
967 
968  // anything not reachable by an entity
969  // can be filled away
970  if (!node->occupied) {
971  if ( !node->opaque ) {
972  c_outside++;
973  node->opaque = true;
974  } else {
975  c_solid++;
976  }
977  } else {
978  c_inside++;
979  }
980 
981 }
982 
983 /*
984 =============
985 FillOutside
986 
987 Fill (set node->opaque = true) all nodes that can't be reached by entities
988 =============
989 */
990 void FillOutside( uEntity_t *e ) {
991  c_outside = 0;
992  c_inside = 0;
993  c_solid = 0;
994  common->Printf ("--- FillOutside ---\n");
995  FillOutside_r( e->tree->headnode );
996  common->Printf ("%5i solid leafs\n", c_solid);
997  common->Printf ("%5i leafs filled\n", c_outside);
998  common->Printf ("%5i inside leafs\n", c_inside);
999 }
#define strcmp
Definition: Str.h:41
side_t * side
Definition: dmap.h:341
node_t * headnode
Definition: dmap.h:173
int contents
Definition: dmap.h:122
void PrintPortal(uPortal_t *p)
Definition: portals.cpp:162
node_t * nodes[2]
Definition: dmap.h:166
const GLdouble * v
Definition: glext.h:2936
void MakeTreePortals_r(node_t *node)
Definition: portals.cpp:466
idBounds bounds
Definition: dmap.h:175
float Distance(const idVec3 &v) const
Definition: Plane.h:324
int occupied
Definition: dmap.h:156
int c_active_portals
Definition: portals.cpp:39
GLenum GLsizei n
Definition: glext.h:3705
float z
Definition: Vector.h:320
Definition: dmap.h:172
node_t * onnode
Definition: dmap.h:165
int planenum
Definition: dmap.h:103
#define MAX_WORLD_COORD
Definition: Lib.h:98
Definition: Vector.h:316
struct uPortal_s * next[2]
Definition: dmap.h:167
#define MAX_INTER_AREA_PORTALS
Definition: dmap.h:337
uEntity_t * occupant
Definition: dmap.h:157
void Clear(void)
Definition: Bounds.h:201
int c_peak_portals
Definition: portals.cpp:40
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
GLdouble s
Definition: glext.h:2935
idWinding * Clip(const idPlane &plane, const float epsilon=ON_EPSILON, const bool keepOn=false)
Definition: Winding.cpp:234
uPortal_t * AllocPortal(void)
Definition: portals.cpp:47
float x
Definition: Vector.h:318
void FillOutside_r(node_t *node)
Definition: portals.cpp:959
int i
Definition: process.py:33
int planenum
Definition: dmap.h:140
void CalcNodeBounds(node_t *node)
Definition: portals.cpp:444
idPlaneSet mapPlanes
Definition: dmap.h:239
#define MIN_WORLD_COORD
Definition: Lib.h:99
#define BASE_WINDING_EPSILON
Definition: portals.cpp:249
list l
Definition: prepare.py:17
idDict epairs
Definition: MapFile.h:166
const idMaterial * material
Definition: dmap.h:105
bool AddPoint(const idVec3 &v)
Definition: Bounds.h:226
void FloodAreas_r(node_t *node)
Definition: portals.cpp:734
int GetNumPoints(void) const
Definition: Winding.h:238
bool FloodEntities(tree_t *tree)
Definition: portals.cpp:580
struct node_s * children[2]
Definition: dmap.h:146
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
void FloodAreas(uEntity_t *e)
Definition: portals.cpp:924
#define SPLIT_WINDING_EPSILON
Definition: portals.cpp:250
void FindAreas_r(node_t *node)
Definition: portals.cpp:776
idWinding * BaseWindingForNode(node_t *node)
Definition: portals.cpp:252
idCommon * common
Definition: Common.cpp:206
idWinding * visibleHull
Definition: dmap.h:109
void RemovePortalFromNode(uPortal_t *portal, node_t *l)
Definition: portals.cpp:126
#define NULL
Definition: Lib.h:88
struct uPortal_s * portals
Definition: dmap.h:159
#define CLIP_EPSILON
Definition: dmap.h:281
const int GetContentFlags(void) const
Definition: Material.h:497
float y
Definition: Vector.h:319
idVec3 GetVector(const char *key, const char *defaultString=NULL) const
Definition: Dict.h:260
Definition: Plane.h:71
side_t sides[6]
Definition: dmap.h:128
#define SIDESPACE
Definition: portals.cpp:179
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
void ClearAreas_r(node_t *node)
Definition: portals.cpp:820
int c_tinyportals
Definition: portals.cpp:99
idWinding * winding
Definition: dmap.h:168
uBrush_t * brushlist
Definition: dmap.h:152
Definition: dmap.h:102
idBounds bounds
Definition: dmap.h:142
bool opaque
Definition: dmap.h:150
void FreePortal(uPortal_t *p)
Definition: portals.cpp:62
virtual void Printf(const char *fmt,...) id_attribute((format(printf
struct bspbrush_s * next
Definition: dmap.h:114
int numsides
Definition: dmap.h:127
int c_floodedleafs
Definition: portals.cpp:513
const char * ToString(int precision=2) const
Definition: Vector.cpp:221
idDeclManager * declManager
GLubyte GLubyte b
Definition: glext.h:4662
uEntity_t * uEntities
Definition: dmap.h:242
bool IsTiny(void) const
Definition: Winding.cpp:1202
int numInterAreaPortals
Definition: portals.cpp:36
#define PLANENUM_LEAF
Definition: dmap.h:81
void FillOutside(uEntity_t *e)
Definition: portals.cpp:990
int Split(const idPlane &plane, const float epsilon, idWinding **front, idWinding **back) const
Definition: Winding.cpp:92
struct tree_s * tree
Definition: dmap.h:51
struct bspbrush_s * original
Definition: dmap.h:115
interAreaPortal_t interAreaPortals[MAX_INTER_AREA_PORTALS]
Definition: portals.cpp:35
struct node_s * parent
Definition: dmap.h:141
tuple f
Definition: idal.py:89
#define ON_EPSILON
Definition: Plane.h:44
Definition: dmap.h:46
int num_entities
Definition: dmap.h:241
bool PlaceOccupant(node_t *headnode, idVec3 origin, uEntity_t *occupant)
Definition: portals.cpp:546
idVec3 GetCenter(void) const
Definition: Winding.cpp:639
void CheckAreas_r(node_t *node)
Definition: portals.cpp:802
bool IsFogLight() const
Definition: Material.h:458
void AddPortalToNodes(uPortal_t *p, node_t *front, node_t *back)
Definition: portals.cpp:106
void FloodPortals_r(node_t *node, int dist)
Definition: portals.cpp:520
Definition: dmap.h:138
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
dmapGlobals_t dmapGlobals
Definition: dmap.cpp:34
int area
Definition: dmap.h:155
virtual void Error(const char *fmt,...) id_attribute((format(printf
GLfloat GLfloat p
Definition: glext.h:4674
idMapEntity * mapEntity
Definition: dmap.h:47
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
void MakeTreePortals(tree_t *tree)
Definition: portals.cpp:498
GLdouble GLdouble t
Definition: glext.h:2943
idPlane plane
Definition: dmap.h:164
int numAreas
Definition: dmap.h:53
node_t outside_node
Definition: dmap.h:174