doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AASBuild.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 "AASBuild_local.h"
33 
34 #define BFL_PATCH 0x1000
35 
36 //===============================================================
37 //
38 // idAASBuild
39 //
40 //===============================================================
41 
42 /*
43 ============
44 idAASBuild::idAASBuild
45 ============
46 */
48  file = NULL;
49  procNodes = NULL;
50  numProcNodes = 0;
54  ledgeMap = NULL;
55 }
56 
57 /*
58 ============
59 idAASBuild::~idAASBuild
60 ============
61 */
63  Shutdown();
64 }
65 
66 /*
67 ================
68 idAASBuild::Shutdown
69 ================
70 */
71 void idAASBuild::Shutdown( void ) {
72  aasSettings = NULL;
73  if ( file ) {
74  delete file;
75  file = NULL;
76  }
77  DeleteProcBSP();
81  ledgeList.Clear();
82  if ( ledgeMap ) {
83  delete ledgeMap;
84  ledgeMap = NULL;
85  }
86 }
87 
88 /*
89 ================
90 idAASBuild::ParseProcNodes
91 ================
92 */
94  int i;
95 
96  src->ExpectTokenString( "{" );
97 
99  if ( idAASBuild::numProcNodes < 0 ) {
100  src->Error( "idAASBuild::ParseProcNodes: bad numProcNodes" );
101  }
103 
104  for ( i = 0; i < idAASBuild::numProcNodes; i++ ) {
105  aasProcNode_t *node;
106 
107  node = &(idAASBuild::procNodes[i]);
108 
109  src->Parse1DMatrix( 4, node->plane.ToFloatPtr() );
110  node->children[0] = src->ParseInt();
111  node->children[1] = src->ParseInt();
112  }
113 
114  src->ExpectTokenString( "}" );
115 }
116 
117 /*
118 ================
119 idAASBuild::LoadProcBSP
120 ================
121 */
122 bool idAASBuild::LoadProcBSP( const char *name, ID_TIME_T minFileTime ) {
123  idStr fileName;
124  idToken token;
125  idLexer *src;
126 
127  // load it
128  fileName = name;
129  fileName.SetFileExtension( PROC_FILE_EXT );
130  src = new idLexer( fileName, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
131  if ( !src->IsLoaded() ) {
132  common->Warning("idAASBuild::LoadProcBSP: couldn't load %s", fileName.c_str() );
133  delete src;
134  return false;
135  }
136 
137  // if the file is too old
138  if ( src->GetFileTime() < minFileTime ) {
139  delete src;
140  return false;
141  }
142 
143  if ( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) ) {
144  common->Warning( "idAASBuild::LoadProcBSP: bad id '%s' instead of '%s'", token.c_str(), PROC_FILE_ID );
145  delete src;
146  return false;
147  }
148 
149  // parse the file
150  while ( 1 ) {
151  if ( !src->ReadToken( &token ) ) {
152  break;
153  }
154 
155  if ( token == "model" ) {
156  src->SkipBracedSection();
157  continue;
158  }
159 
160  if ( token == "shadowModel" ) {
161  src->SkipBracedSection();
162  continue;
163  }
164 
165  if ( token == "interAreaPortals" ) {
166  src->SkipBracedSection();
167  continue;
168  }
169 
170  if ( token == "nodes" ) {
172  break;
173  }
174 
175  src->Error( "idAASBuild::LoadProcBSP: bad token \"%s\"", token.c_str() );
176  }
177 
178  delete src;
179 
180  return true;
181 }
182 
183 /*
184 ============
185 idAASBuild::DeleteProcBSP
186 ============
187 */
189  if ( procNodes ) {
190  Mem_Free( procNodes );
191  procNodes = NULL;
192  }
193  numProcNodes = 0;
194 }
195 
196 /*
197 ============
198 idAASBuild::ChoppedAwayByProcBSP
199 ============
200 */
201 bool idAASBuild::ChoppedAwayByProcBSP( int nodeNum, idFixedWinding *w, const idVec3 &normal, const idVec3 &origin, const float radius ) {
202  int res;
203  idFixedWinding back;
204  aasProcNode_t *node;
205  float dist;
206 
207  do {
208  node = idAASBuild::procNodes + nodeNum;
209  dist = node->plane.Normal() * origin + node->plane[3];
210  if ( dist > radius ) {
211  res = SIDE_FRONT;
212  }
213  else if ( dist < -radius ) {
214  res = SIDE_BACK;
215  }
216  else {
217  res = w->Split( &back, node->plane, ON_EPSILON );
218  }
219  if ( res == SIDE_FRONT ) {
220  nodeNum = node->children[0];
221  }
222  else if ( res == SIDE_BACK ) {
223  nodeNum = node->children[1];
224  }
225  else if ( res == SIDE_ON ) {
226  // continue with the side the winding faces
227  if ( node->plane.Normal() * normal > 0.0f ) {
228  nodeNum = node->children[0];
229  }
230  else {
231  nodeNum = node->children[1];
232  }
233  }
234  else {
235  // if either node is not solid
236  if ( node->children[0] < 0 || node->children[1] < 0 ) {
237  return false;
238  }
239  // only recurse if the node is not solid
240  if ( node->children[1] > 0 ) {
241  if ( !idAASBuild::ChoppedAwayByProcBSP( node->children[1], &back, normal, origin, radius ) ) {
242  return false;
243  }
244  }
245  nodeNum = node->children[0];
246  }
247  } while ( nodeNum > 0 );
248  if ( nodeNum < 0 ) {
249  return false;
250  }
251  return true;
252 }
253 
254 /*
255 ============
256 idAASBuild::ClipBrushSidesWithProcBSP
257 ============
258 */
260  int i, clippedSides;
261  idBrush *brush;
262  idFixedWinding neww;
263  idBounds bounds;
264  float radius;
265  idVec3 origin;
266 
267  // if the .proc file has no BSP tree
268  if ( idAASBuild::procNodes == NULL ) {
269  return;
270  }
271 
272  clippedSides = 0;
273  for ( brush = brushList.Head(); brush; brush = brush->Next() ) {
274  for ( i = 0; i < brush->GetNumSides(); i++ ) {
275 
276  if ( !brush->GetSide(i)->GetWinding() ) {
277  continue;
278  }
279 
280  // make a local copy of the winding
281  neww = *brush->GetSide(i)->GetWinding();
282  neww.GetBounds( bounds );
283  origin = (bounds[1] - bounds[0]) * 0.5f;
284  radius = origin.Length() + ON_EPSILON;
285  origin = bounds[0] + origin;
286 
287  if ( ChoppedAwayByProcBSP( 0, &neww, brush->GetSide(i)->GetPlane().Normal(), origin, radius ) ) {
288  brush->GetSide(i)->SetFlag( SFL_USED_SPLITTER );
289  clippedSides++;
290  }
291  }
292  }
293 
294  common->Printf( "%6d brush sides clipped\n", clippedSides );
295 }
296 
297 /*
298 ============
299 idAASBuild::ContentsForAAS
300 ============
301 */
302 int idAASBuild::ContentsForAAS( int contents ) {
303  int c;
304 
306  return AREACONTENTS_SOLID;
307  }
308  c = 0;
309  if ( contents & CONTENTS_WATER ) {
310  c |= AREACONTENTS_WATER;
311  }
312  if ( contents & CONTENTS_AREAPORTAL ) {
314  }
315  if ( contents & CONTENTS_AAS_OBSTACLE ) {
317  }
318  return c;
319 }
320 
321 /*
322 ============
323 idAASBuild::AddBrushForMapBrush
324 ============
325 */
326 idBrushList idAASBuild::AddBrushesForMapBrush( const idMapBrush *mapBrush, const idVec3 &origin, const idMat3 &axis, int entityNum, int primitiveNum, idBrushList brushList ) {
327  int contents, i;
328  idMapBrushSide *mapSide;
329  const idMaterial *mat;
330  idList<idBrushSide *> sideList;
331  idBrush *brush;
332  idPlane plane;
333 
334  contents = 0;
335  for ( i = 0; i < mapBrush->GetNumSides(); i++ ) {
336  mapSide = mapBrush->GetSide(i);
337  mat = declManager->FindMaterial( mapSide->GetMaterial() );
338  contents |= mat->GetContentFlags();
339  plane = mapSide->GetPlane();
341  sideList.Append( new idBrushSide( plane, -1 ) );
342  }
343 
344  contents = ContentsForAAS( contents );
345  if ( !contents ) {
346  for ( i = 0; i < sideList.Num(); i++ ) {
347  delete sideList[i];
348  }
349  return brushList;
350  }
351 
352  brush = new idBrush();
353  brush->SetContents( contents );
354 
355  if ( !brush->FromSides( sideList ) ) {
356  common->Warning( "brush primitive %d on entity %d is degenerate", primitiveNum, entityNum );
357  delete brush;
358  return brushList;
359  }
360 
361  brush->SetEntityNum( entityNum );
362  brush->SetPrimitiveNum( primitiveNum );
363  brush->Transform( origin, axis );
364  brushList.AddToTail( brush );
365 
366  return brushList;
367 }
368 
369 /*
370 ============
371 idAASBuild::AddBrushesForPatch
372 ============
373 */
374 idBrushList idAASBuild::AddBrushesForMapPatch( const idMapPatch *mapPatch, const idVec3 &origin, const idMat3 &axis, int entityNum, int primitiveNum, idBrushList brushList ) {
375  int i, j, contents, validBrushes;
376  float dot;
377  int v1, v2, v3, v4;
379  idPlane plane;
380  idVec3 d1, d2;
381  idBrush *brush;
382  idSurface_Patch mesh;
383  const idMaterial *mat;
384 
385  mat = declManager->FindMaterial( mapPatch->GetMaterial() );
386  contents = ContentsForAAS( mat->GetContentFlags() );
387 
388  if ( !contents ) {
389  return brushList;
390  }
391 
392  mesh = idSurface_Patch( *mapPatch );
393 
394  // if the patch has an explicit number of subdivisions use it to avoid cracks
395  if ( mapPatch->GetExplicitlySubdivided() ) {
396  mesh.SubdivideExplicit( mapPatch->GetHorzSubdivisions(), mapPatch->GetVertSubdivisions(), false, true );
397  } else {
399  }
400 
401  validBrushes = 0;
402 
403  for ( i = 0; i < mesh.GetWidth() - 1; i++ ) {
404  for ( j = 0; j < mesh.GetHeight() - 1; j++ ) {
405 
406  v1 = j * mesh.GetWidth() + i;
407  v2 = v1 + 1;
408  v3 = v1 + mesh.GetWidth() + 1;
409  v4 = v1 + mesh.GetWidth();
410 
411  d1 = mesh[v2].xyz - mesh[v1].xyz;
412  d2 = mesh[v3].xyz - mesh[v1].xyz;
413  plane.SetNormal( d1.Cross(d2) );
414  if ( plane.Normalize() != 0.0f ) {
415  plane.FitThroughPoint( mesh[v1].xyz );
416  dot = plane.Distance( mesh[v4].xyz );
417  // if we can turn it into a quad
418  if ( idMath::Fabs(dot) < 0.1f ) {
419  w.Clear();
420  w += mesh[v1].xyz;
421  w += mesh[v2].xyz;
422  w += mesh[v3].xyz;
423  w += mesh[v4].xyz;
424 
425  brush = new idBrush();
426  brush->SetContents( contents );
427  if ( brush->FromWinding( w, plane ) ) {
428  brush->SetEntityNum( entityNum );
429  brush->SetPrimitiveNum( primitiveNum );
430  brush->SetFlag( BFL_PATCH );
431  brush->Transform( origin, axis );
432  brushList.AddToTail( brush );
433  validBrushes++;
434  }
435  else {
436  delete brush;
437  }
438  continue;
439  }
440  else {
441  // create one of the triangles
442  w.Clear();
443  w += mesh[v1].xyz;
444  w += mesh[v2].xyz;
445  w += mesh[v3].xyz;
446 
447  brush = new idBrush();
448  brush->SetContents( contents );
449  if ( brush->FromWinding( w, plane ) ) {
450  brush->SetEntityNum( entityNum );
451  brush->SetPrimitiveNum( primitiveNum );
452  brush->SetFlag( BFL_PATCH );
453  brush->Transform( origin, axis );
454  brushList.AddToTail( brush );
455  validBrushes++;
456  }
457  else {
458  delete brush;
459  }
460  }
461  }
462  // create the other triangle
463  d1 = mesh[v3].xyz - mesh[v1].xyz;
464  d2 = mesh[v4].xyz - mesh[v1].xyz;
465  plane.SetNormal( d1.Cross(d2) );
466  if ( plane.Normalize() != 0.0f ) {
467  plane.FitThroughPoint( mesh[v1].xyz );
468 
469  w.Clear();
470  w += mesh[v1].xyz;
471  w += mesh[v3].xyz;
472  w += mesh[v4].xyz;
473 
474  brush = new idBrush();
475  brush->SetContents( contents );
476  if ( brush->FromWinding( w, plane ) ) {
477  brush->SetEntityNum( entityNum );
478  brush->SetPrimitiveNum( primitiveNum );
479  brush->SetFlag( BFL_PATCH );
480  brush->Transform( origin, axis );
481  brushList.AddToTail( brush );
482  validBrushes++;
483  }
484  else {
485  delete brush;
486  }
487  }
488  }
489  }
490 
491  if ( !validBrushes ) {
492  common->Warning( "patch primitive %d on entity %d is completely degenerate", primitiveNum, entityNum );
493  }
494 
495  return brushList;
496 }
497 
498 /*
499 ============
500 idAASBuild::AddBrushesForMapEntity
501 ============
502 */
503 idBrushList idAASBuild::AddBrushesForMapEntity( const idMapEntity *mapEnt, int entityNum, idBrushList brushList ) {
504  int i;
505  idVec3 origin;
506  idMat3 axis;
507 
508  if ( mapEnt->GetNumPrimitives() < 1 ) {
509  return brushList;
510  }
511 
512  mapEnt->epairs.GetVector( "origin", "0 0 0", origin );
513  if ( !mapEnt->epairs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", axis ) ) {
514  float angle = mapEnt->epairs.GetFloat( "angle" );
515  if ( angle != 0.0f ) {
516  axis = idAngles( 0.0f, angle, 0.0f ).ToMat3();
517  } else {
518  axis.Identity();
519  }
520  }
521 
522  for ( i = 0; i < mapEnt->GetNumPrimitives(); i++ ) {
523  idMapPrimitive *mapPrim;
524 
525  mapPrim = mapEnt->GetPrimitive(i);
526  if ( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
527  brushList = AddBrushesForMapBrush( static_cast<idMapBrush*>(mapPrim), origin, axis, entityNum, i, brushList );
528  continue;
529  }
530  if ( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH ) {
531  if ( aasSettings->usePatches ) {
532  brushList = AddBrushesForMapPatch( static_cast<idMapPatch*>(mapPrim), origin, axis, entityNum, i, brushList );
533  }
534  continue;
535  }
536  }
537 
538  return brushList;
539 }
540 
541 /*
542 ============
543 idAASBuild::AddBrushesForMapFile
544 ============
545 */
547  int i;
548 
549  common->Printf( "[Brush Load]\n" );
550 
551  brushList = AddBrushesForMapEntity( mapFile->GetEntity( 0 ), 0, brushList );
552 
553  for ( i = 1; i < mapFile->GetNumEntities(); i++ ) {
554  const char *classname = mapFile->GetEntity( i )->epairs.GetString( "classname" );
555 
556  if ( idStr::Icmp( classname, "func_aas_obstacle" ) == 0 ) {
557  brushList = AddBrushesForMapEntity( mapFile->GetEntity( i ), i, brushList );
558  }
559  }
560 
561  common->Printf( "%6d brushes\n", brushList.Num() );
562 
563  return brushList;
564 }
565 
566 /*
567 ============
568 idAASBuild::CheckForEntities
569 ============
570 */
571 bool idAASBuild::CheckForEntities( const idMapFile *mapFile, idStrList &entityClassNames ) const {
572  int i;
573  idStr classname;
574 
576 
577  for ( i = 0; i < mapFile->GetNumEntities(); i++ ) {
578  if ( !mapFile->GetEntity(i)->epairs.GetString( "classname", "", classname ) ) {
579  continue;
580  }
581 
582  if ( aasSettings->ValidEntity( classname ) ) {
583  entityClassNames.AddUnique( classname );
584  }
585  }
586 
588 
589  return ( entityClassNames.Num() != 0 );
590 }
591 
592 /*
593 ============
594 MergeAllowed
595 ============
596 */
597 bool MergeAllowed( idBrush *b1, idBrush *b2 ) {
598  return ( b1->GetContents() == b2->GetContents() && !( ( b1->GetFlags() | b2->GetFlags() ) & BFL_PATCH ) );
599 }
600 
601 /*
602 ============
603 ExpandedChopAllowed
604 ============
605 */
607  return ( b1->GetContents() == b2->GetContents() );
608 }
609 
610 /*
611 ============
612 ExpandedMergeAllowed
613 ============
614 */
616  return ( b1->GetContents() == b2->GetContents() );
617 }
618 
619 /*
620 ============
621 idAASBuild::ChangeMultipleBoundingBoxContents
622 ============
623 */
625  while( node ) {
626  if ( !( node->GetContents() & mask ) ) {
627  node->SetContents( node->GetContents() & ~AREACONTENTS_SOLID );
628  }
630  node = node->GetChild( 1 );
631  }
632 }
633 
634 /*
635 ============
636 idAASBuild::Build
637 ============
638 */
639 bool idAASBuild::Build( const idStr &fileName, const idAASSettings *settings ) {
640  int i, bit, mask, startTime;
641  idMapFile * mapFile;
642  idBrushList brushList;
643  idList<idBrushList*> expandedBrushes;
644  idBrush *b;
645  idBrushBSP bsp;
646  idStr name;
647  idAASReach reach;
648  idAASCluster cluster;
649  idStrList entityClassNames;
650 
651  startTime = Sys_Milliseconds();
652 
653  Shutdown();
654 
655  aasSettings = settings;
656 
657  name = fileName;
658  name.SetFileExtension( "map" );
659 
660  mapFile = new idMapFile;
661  if ( !mapFile->Parse( name ) ) {
662  delete mapFile;
663  common->Error( "Couldn't load map file: '%s'", name.c_str() );
664  return false;
665  }
666 
667  // check if this map has any entities that use this AAS file
668  if ( !CheckForEntities( mapFile, entityClassNames ) ) {
669  delete mapFile;
670  common->Printf( "no entities in map that use %s\n", settings->fileExtension.c_str() );
671  return true;
672  }
673 
674  // load map file brushes
675  brushList = AddBrushesForMapFile( mapFile, brushList );
676 
677  // if empty map
678  if ( brushList.Num() == 0 ) {
679  delete mapFile;
680  common->Error( "%s is empty", name.c_str() );
681  return false;
682  }
683 
684  // merge as many brushes as possible before expansion
685  brushList.Merge( MergeAllowed );
686 
687  // if there is a .proc file newer than the .map file
688  if ( LoadProcBSP( fileName, mapFile->GetFileTime() ) ) {
689  ClipBrushSidesWithProcBSP( brushList );
690  DeleteProcBSP();
691  }
692 
693  // make copies of the brush list
694  expandedBrushes.Append( &brushList );
695  for ( i = 1; i < aasSettings->numBoundingBoxes; i++ ) {
696  expandedBrushes.Append( brushList.Copy() );
697  }
698 
699  // expand brushes for the axial bounding boxes
700  mask = AREACONTENTS_SOLID;
701  for ( i = 0; i < expandedBrushes.Num(); i++ ) {
702  for ( b = expandedBrushes[i]->Head(); b; b = b->Next() ) {
704  bit = 1 << ( i + AREACONTENTS_BBOX_BIT );
705  mask |= bit;
706  b->SetContents( b->GetContents() | bit );
707  }
708  }
709 
710  // move all brushes back into the original list
711  for ( i = 1; i < aasSettings->numBoundingBoxes; i++ ) {
712  brushList.AddToTail( *expandedBrushes[i] );
713  delete expandedBrushes[i];
714  }
715 
716  if ( aasSettings->writeBrushMap ) {
718  }
719 
720  // build BSP tree from brushes
722 
723  // only solid nodes with all bits set for all bounding boxes need to stay solid
725 
726  // portalize the bsp tree
727  bsp.Portalize();
728 
729  // remove subspaces not reachable by entities
730  if ( !bsp.RemoveOutside( mapFile, AREACONTENTS_SOLID, entityClassNames ) ) {
731  bsp.LeakFile( name );
732  delete mapFile;
733  common->Printf( "%s has no outside", name.c_str() );
734  return false;
735  }
736 
737  // gravitational subdivision
739 
740  // merge portals where possible
742 
743  // melt portal windings
745 
746  if ( aasSettings->writeBrushMap ) {
747  WriteLedgeMap( fileName, "_" + aasSettings->fileExtension + "_ledge" );
748  }
749 
750  // ledge subdivisions
751  LedgeSubdivision( bsp );
752 
753  // merge leaf nodes
754  MergeLeafNodes( bsp );
755 
756  // merge portals where possible
758 
759  // melt portal windings
761 
762  // store the file from the bsp tree
763  StoreFile( bsp );
765 
766  // calculate reachability
767  reach.Build( mapFile, file );
768 
769  // build clusters
770  cluster.Build( file );
771 
772  // optimize the file
773  if ( !aasSettings->noOptimize ) {
774  file->Optimize();
775  }
776 
777  // write the file
779  file->Write( name, mapFile->GetGeometryCRC() );
780 
781  // delete the map file
782  delete mapFile;
783 
784  common->Printf( "%6d seconds to create AAS\n", (Sys_Milliseconds() - startTime) / 1000 );
785 
786  return true;
787 }
788 
789 /*
790 ============
791 idAASBuild::BuildReachability
792 ============
793 */
794 bool idAASBuild::BuildReachability( const idStr &fileName, const idAASSettings *settings ) {
795  int startTime;
796  idMapFile * mapFile;
797  idStr name;
798  idAASReach reach;
799  idAASCluster cluster;
800 
801  startTime = Sys_Milliseconds();
802 
803  aasSettings = settings;
804 
805  name = fileName;
806  name.SetFileExtension( "map" );
807 
808  mapFile = new idMapFile;
809  if ( !mapFile->Parse( name ) ) {
810  delete mapFile;
811  common->Error( "Couldn't load map file: '%s'", name.c_str() );
812  return false;
813  }
814 
815  file = new idAASFileLocal();
816 
818  if ( !file->Load( name, 0 ) ) {
819  delete mapFile;
820  common->Error( "Couldn't load AAS file: '%s'", name.c_str() );
821  return false;
822  }
823 
825 
826  // calculate reachability
827  reach.Build( mapFile, file );
828 
829  // build clusters
830  cluster.Build( file );
831 
832  // write the file
833  file->Write( name, mapFile->GetGeometryCRC() );
834 
835  // delete the map file
836  delete mapFile;
837 
838  common->Printf( "%6d seconds to calculate reachability\n", (Sys_Milliseconds() - startTime) / 1000 );
839 
840  return true;
841 }
842 
843 /*
844 ============
845 ParseOptions
846 ============
847 */
848 int ParseOptions( const idCmdArgs &args, idAASSettings &settings ) {
849  int i;
850  idStr str;
851 
852  for ( i = 1; i < args.Argc(); i++ ) {
853 
854  str = args.Argv( i );
855  str.StripLeading( '-' );
856 
857  if ( str.Icmp( "usePatches" ) == 0 ) {
858  settings.usePatches = true;
859  common->Printf( "usePatches = true\n" );
860  } else if ( str.Icmp( "writeBrushMap" ) == 0 ) {
861  settings.writeBrushMap = true;
862  common->Printf( "writeBrushMap = true\n" );
863  } else if ( str.Icmp( "playerFlood" ) == 0 ) {
864  settings.playerFlood = true;
865  common->Printf( "playerFlood = true\n" );
866  } else if ( str.Icmp( "noOptimize" ) == 0 ) {
867  settings.noOptimize = true;
868  common->Printf( "noOptimize = true\n" );
869  }
870  }
871  return args.Argc() - 1;
872 }
873 
874 /*
875 ============
876 RunAAS_f
877 ============
878 */
879 void RunAAS_f( const idCmdArgs &args ) {
880  int i;
881  idAASBuild aas;
882  idAASSettings settings;
883  idStr mapName;
884 
885  if ( args.Argc() <= 1 ) {
886  common->Printf( "runAAS [options] <mapfile>\n"
887  "options:\n"
888  " -usePatches = use bezier patches for collision detection.\n"
889  " -writeBrushMap = write a brush map with the AAS geometry.\n"
890  " -playerFlood = use player spawn points as valid AAS positions.\n" );
891  return;
892  }
893 
894  common->ClearWarnings( "compiling AAS" );
895 
896  common->SetRefreshOnPrint( true );
897 
898  // get the aas settings definitions
899  const idDict *dict = gameEdit->FindEntityDefDict( "aas_types", false );
900  if ( !dict ) {
901  common->Error( "Unable to find entityDef for 'aas_types'" );
902  }
903 
904  const idKeyValue *kv = dict->MatchPrefix( "type" );
905  while( kv != NULL ) {
906  const idDict *settingsDict = gameEdit->FindEntityDefDict( kv->GetValue(), false );
907  if ( !settingsDict ) {
908  common->Warning( "Unable to find '%s' in def/aas.def", kv->GetValue().c_str() );
909  } else {
910  settings.FromDict( kv->GetValue(), settingsDict );
911  i = ParseOptions( args, settings );
912  mapName = args.Argv(i);
913  mapName.BackSlashesToSlashes();
914  if ( mapName.Icmpn( "maps/", 4 ) != 0 ) {
915  mapName = "maps/" + mapName;
916  }
917  aas.Build( mapName, &settings );
918  }
919 
920  kv = dict->MatchPrefix( "type", kv );
921  if ( kv ) {
922  common->Printf( "=======================================================\n" );
923  }
924  }
925  common->SetRefreshOnPrint( false );
927 }
928 
929 /*
930 ============
931 RunAASDir_f
932 ============
933 */
934 void RunAASDir_f( const idCmdArgs &args ) {
935  int i;
936  idAASBuild aas;
937  idAASSettings settings;
938  idFileList *mapFiles;
939 
940  if ( args.Argc() <= 1 ) {
941  common->Printf( "runAASDir <folder>\n" );
942  return;
943  }
944 
945  common->ClearWarnings( "compiling AAS" );
946 
947  common->SetRefreshOnPrint( true );
948 
949  // get the aas settings definitions
950  const idDict *dict = gameEdit->FindEntityDefDict( "aas_types", false );
951  if ( !dict ) {
952  common->Error( "Unable to find entityDef for 'aas_types'" );
953  }
954 
955  // scan for .map files
956  mapFiles = fileSystem->ListFiles( idStr("maps/") + args.Argv(1), ".map" );
957 
958  // create AAS files for all the .map files
959  for ( i = 0; i < mapFiles->GetNumFiles(); i++ ) {
960  if ( i ) {
961  common->Printf( "=======================================================\n" );
962  }
963 
964  const idKeyValue *kv = dict->MatchPrefix( "type" );
965  while( kv != NULL ) {
966  const idDict *settingsDict = gameEdit->FindEntityDefDict( kv->GetValue(), false );
967  if ( !settingsDict ) {
968  common->Warning( "Unable to find '%s' in def/aas.def", kv->GetValue().c_str() );
969  } else {
970  settings.FromDict( kv->GetValue(), settingsDict );
971  aas.Build( idStr( "maps/" ) + args.Argv( 1 ) + "/" + mapFiles->GetFile( i ), &settings );
972  }
973 
974  kv = dict->MatchPrefix( "type", kv );
975  if ( kv ) {
976  common->Printf( "=======================================================\n" );
977  }
978  }
979  }
980 
981  fileSystem->FreeFileList( mapFiles );
982 
983  common->SetRefreshOnPrint( false );
985 }
986 
987 /*
988 ============
989 RunReach_f
990 ============
991 */
992 void RunReach_f( const idCmdArgs &args ) {
993  int i;
994  idAASBuild aas;
995  idAASSettings settings;
996 
997  if ( args.Argc() <= 1 ) {
998  common->Printf( "runReach [options] <mapfile>\n" );
999  return;
1000  }
1001 
1002  common->ClearWarnings( "calculating AAS reachability" );
1003 
1004  common->SetRefreshOnPrint( true );
1005 
1006  // get the aas settings definitions
1007  const idDict *dict = gameEdit->FindEntityDefDict( "aas_types", false );
1008  if ( !dict ) {
1009  common->Error( "Unable to find entityDef for 'aas_types'" );
1010  }
1011 
1012  const idKeyValue *kv = dict->MatchPrefix( "type" );
1013  while( kv != NULL ) {
1014  const idDict *settingsDict = gameEdit->FindEntityDefDict( kv->GetValue(), false );
1015  if ( !settingsDict ) {
1016  common->Warning( "Unable to find '%s' in def/aas.def", kv->GetValue().c_str() );
1017  } else {
1018  settings.FromDict( kv->GetValue(), settingsDict );
1019  i = ParseOptions( args, settings );
1020  aas.BuildReachability( idStr("maps/") + args.Argv(i), &settings );
1021  }
1022 
1023  kv = dict->MatchPrefix( "type", kv );
1024  if ( kv ) {
1025  common->Printf( "=======================================================\n" );
1026  }
1027  }
1028 
1029  common->SetRefreshOnPrint( false );
1030  common->PrintWarnings();
1031 }
int GetNumSides(void) const
Definition: MapFile.h:106
#define BFL_PATCH
Definition: AASBuild.cpp:34
int ParseOptions(const idCmdArgs &args, idAASSettings &settings)
Definition: AASBuild.cpp:848
const idPlane & GetPlane(void) const
Definition: MapFile.h:78
void GetBounds(idBounds &bounds) const
Definition: Winding.cpp:700
void MergePortals(int skipContents)
Definition: BrushBSP.cpp:1813
int GetType(void) const
Definition: MapFile.h:63
float GetFloat(const char *key, const char *defaultString="0") const
Definition: Dict.h:248
const float DEFAULT_CURVE_MAX_ERROR_CD
Definition: MapFile.h:50
bool BuildReachability(const idStr &fileName, const idAASSettings *settings)
Definition: AASBuild.cpp:794
bool StoreFile(const idBrushBSP &bsp)
idMapEntity * GetEntity(int i) const
Definition: MapFile.h:198
idStr & SetFileExtension(const char *extension)
Definition: Str.cpp:743
virtual idFileList * ListFiles(const char *relativePath, const char *extension, bool sort=false, bool fullRelativePath=false, const char *gamedir=NULL)=0
unsigned int GetGeometryCRC(void) const
Definition: MapFile.h:205
const idVec3 & Normal(void) const
Definition: Plane.h:239
void MergeLeafNodes(idBrushBSP &bsp)
int numMergedLeafNodes
idBrushList AddBrushesForMapFile(const idMapFile *mapFile, idBrushList brushList)
Definition: AASBuild.cpp:546
idMapBrushSide * GetSide(int i) const
Definition: MapFile.h:108
int GetVertSubdivisions(void) const
Definition: MapFile.h:127
int GetContents(void) const
Definition: BrushBSP.h:106
void StripLeading(const char c)
Definition: Str.cpp:469
void Transform(const idVec3 &origin, const idMat3 &axis)
Definition: Brush.cpp:406
GLenum GLint GLuint mask
Definition: glext.h:5864
void MeltPortals(int skipContents)
Definition: BrushBSP.cpp:2142
bool RemoveOutside(const idMapFile *mapFile, int contents, const idStrList &classNames)
Definition: BrushBSP.cpp:1591
#define SIDE_BACK
Definition: Plane.h:48
bool ValidEntity(const char *classname) const
Definition: AASFile.cpp:522
float Distance(const idVec3 &v) const
Definition: Plane.h:324
idBrushList AddBrushesForMapPatch(const idMapPatch *mapPatch, const idVec3 &origin, const idMat3 &axis, int entityNum, int primitiveNum, idBrushList brushList)
Definition: AASBuild.cpp:374
const idWinding * GetWinding(void) const
Definition: Brush.h:78
int GetNumFiles(void) const
Definition: FileSystem.h:126
int Parse1DMatrix(int x, float *m)
Definition: Lexer.cpp:1300
const ID_TIME_T GetFileTime(void)
Definition: Lexer.h:290
bool Build(const idMapFile *mapFile, idAASFileLocal *file)
Definition: AASReach.cpp:877
bool LoadProcBSP(const char *name, ID_TIME_T minFileTime)
Definition: AASBuild.cpp:122
int Sys_Milliseconds(void)
const idKeyValue * MatchPrefix(const char *prefix, const idKeyValue *lastMatch=NULL) const
Definition: Dict.cpp:523
void ExpandForAxialBox(const idBounds &bounds)
Definition: Brush.cpp:949
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
#define AREACONTENTS_OBSTACLE
Definition: AASFile.h:81
int ContentsForAAS(int contents)
Definition: AASBuild.cpp:302
int SkipBracedSection(bool parseFirstBrace=true)
Definition: Lexer.cpp:1134
int GetHorzSubdivisions(void) const
Definition: MapFile.h:126
const float * ToFloatPtr(void) const
Definition: Plane.h:383
int GetFlags(void) const
Definition: Brush.h:106
void RunAASDir_f(const idCmdArgs &args)
Definition: AASBuild.cpp:934
Definition: Vector.h:316
#define AREACONTENTS_SOLID
Definition: AASFile.h:78
void SetEntityNum(int num)
Definition: Brush.h:109
bool ExpandedChopAllowed(idBrush *b1, idBrush *b2)
Definition: AASBuild.cpp:606
const char * GetMaterial(void) const
Definition: MapFile.h:124
Definition: Token.h:71
idAASSettings settings
Definition: AASFile.h:348
void SetFlag(int flag)
Definition: Brush.h:107
idBrushSide * GetSide(int i) const
Definition: Brush.h:116
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
void LedgeSubdivision(idBrushBSP &bsp)
GLuint src
Definition: glext.h:5390
void SetNormal(const idVec3 &normal)
Definition: Plane.h:233
idVec3 Cross(const idVec3 &a) const
Definition: Vector.h:619
void Identity(void)
Definition: Matrix.h:591
void WriteBrushMap(const idStr &fileName, const idStr &ext, int contents)
Definition: BrushBSP.cpp:1014
bool FromDict(const char *name, const idDict *dict)
Definition: AASFile.cpp:379
idBounds boundingBoxes[MAX_AAS_BOUNDING_BOXES]
Definition: AASFile.h:215
int i
Definition: process.py:33
int ParseInt(void)
Definition: Lexer.cpp:1227
idBrushList AddBrushesForMapEntity(const idMapEntity *mapEnt, int entityNum, idBrushList brushList)
Definition: AASBuild.cpp:503
int Split(idFixedWinding *back, const idPlane &plane, const float epsilon=ON_EPSILON)
Definition: Winding.cpp:1484
idBrushBSPNode * GetRootNode(void) const
Definition: BrushBSP.h:176
int Icmp(const char *text) const
Definition: Str.h:667
void SubdivideExplicit(int horzSubdivisions, int vertSubdivisions, bool genNormals, bool removeLinear=false)
void WriteLedgeMap(const idStr &fileName, const idStr &ext)
#define DEGENERATE_DIST_EPSILON
Definition: Plane.h:45
#define PROC_FILE_EXT
Definition: RenderWorld.h:40
idStr & BackSlashesToSlashes(void)
Definition: Str.cpp:727
idDict epairs
Definition: MapFile.h:166
void SetContents(int contents)
Definition: BrushBSP.h:105
#define PROC_FILE_ID
Definition: RenderWorld.h:41
idGameEdit * gameEdit
Definition: GameEdit.cpp:668
virtual const idDict * FindEntityDefDict(const char *name, bool makeDefault=true) const
Definition: GameEdit.cpp:735
bool Build(const idStr &fileName, const idAASSettings *settings)
Definition: AASBuild.cpp:639
idList< idLedge > ledgeList
int GetHeight(void) const
int com_editors
Definition: Common.cpp:97
int numGravitationalSubdivisions
int Icmpn(const char *text, int n) const
Definition: Str.h:672
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
Definition: Lexer.h:137
bool usePatches
Definition: AASFile.h:216
void Error(const char *str,...) id_attribute((format(printf
Definition: Lexer.cpp:215
bool Write(const idStr &fileName, unsigned int mapFileCRC)
Definition: AASFile.cpp:627
idAASFileLocal * file
idBrush * Head(void) const
Definition: Brush.h:168
bool FromWinding(const idWinding &w, const idPlane &windingPlane)
Definition: Brush.cpp:330
#define AREACONTENTS_BBOX_BIT
Definition: AASFile.h:85
void Subdivide(float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals=false)
const GLubyte * c
Definition: glext.h:4677
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
bool ExpandedMergeAllowed(idBrush *b1, idBrush *b2)
Definition: AASBuild.cpp:615
float Length(void) const
Definition: Vector.h:631
bool writeBrushMap
Definition: AASFile.h:217
int GetNumEntities(void) const
Definition: MapFile.h:196
const float DEFAULT_CURVE_MAX_LENGTH_CD
Definition: MapFile.h:52
bool Parse(const char *filename, bool ignoreRegion=false, bool osPath=false)
Definition: MapFile.cpp:720
bool CheckForEntities(const idMapFile *mapFile, idStrList &entityClassNames) const
Definition: AASBuild.cpp:571
void AddToTail(idBrush *brush)
Definition: Brush.cpp:1055
void ChangeMultipleBoundingBoxContents_r(idBrushBSPNode *node, int mask)
Definition: AASBuild.cpp:624
static float Fabs(float f)
Definition: Math.h:779
idStr fileExtension
Definition: AASFile.h:222
idCommon * common
Definition: Common.cpp:206
#define SFL_USED_SPLITTER
Definition: Brush.h:60
void Portalize(void)
Definition: BrushBSP.cpp:1346
Definition: Dict.h:65
#define NULL
Definition: Lib.h:88
ID_TIME_T GetFileTime(void) const
Definition: MapFile.h:202
void SetPrimitiveNum(int num)
Definition: Brush.h:110
const int GetContentFlags(void) const
Definition: Material.h:497
virtual void Clear(void)
Definition: Winding.h:398
idVec3 GetVector(const char *key, const char *defaultString=NULL) const
Definition: Dict.h:260
void SetContents(int contents)
Definition: Brush.h:111
bool Load(const idStr &fileName, unsigned int mapFileCRC)
Definition: AASFile.cpp:1099
Definition: Plane.h:71
const char * GetFile(int index) const
Definition: FileSystem.h:127
void ParseProcNodes(idLexer *src)
Definition: AASBuild.cpp:93
virtual void virtual void virtual void virtual void PrintWarnings(void)=0
int numLedgeSubdivisions
bool GetExplicitlySubdivided(void) const
Definition: MapFile.h:128
const idAASSettings * aasSettings
const idStr & GetValue(void) const
Definition: Dict.h:53
int Argc(void) const
Definition: CmdArgs.h:48
void Shutdown(void)
Definition: AASBuild.cpp:71
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
virtual void FreeFileList(idFileList *fileList)=0
aasProcNode_t * procNodes
void SetFlag(int flag)
Definition: Brush.h:73
virtual void Printf(const char *fmt,...) id_attribute((format(printf
int GetContents(void) const
Definition: Brush.h:112
float Normalize(bool fixDegenerate=true)
Definition: Plane.h:247
#define AREACONTENTS_WATER
Definition: AASFile.h:79
bool ChoppedAwayByProcBSP(int nodeNum, idFixedWinding *w, const idVec3 &normal, const idVec3 &origin, const float radius)
Definition: AASBuild.cpp:201
GLfloat GLfloat v1
Definition: glext.h:3607
idDeclManager * declManager
bool Build(idAASFileLocal *file)
Definition: AASCluster.cpp:466
~idAASBuild(void)
Definition: AASBuild.cpp:62
GLubyte GLubyte b
Definition: glext.h:4662
idBrush * Next(void) const
Definition: Brush.h:133
void GravitationalSubdivision(idBrushBSP &bsp)
void LeakFile(const idStr &fileName)
Definition: BrushBSP.cpp:1363
int ExpectTokenString(const char *string)
Definition: Lexer.cpp:919
GLfloat GLfloat GLfloat GLfloat v3
Definition: glext.h:3609
int Append(const type &obj)
Definition: List.h:646
#define SIDE_ON
Definition: Plane.h:49
Definition: Matrix.h:333
idMapPrimitive * GetPrimitive(int i) const
Definition: MapFile.h:174
void RunAAS_f(const idCmdArgs &args)
Definition: AASBuild.cpp:879
int AddUnique(const type &obj)
Definition: List.h:742
tuple f
Definition: idal.py:89
#define ON_EPSILON
Definition: Plane.h:44
idBrushBSPNode * GetChild(int index) const
Definition: BrushBSP.h:103
idBrushList AddBrushesForMapBrush(const idMapBrush *mapBrush, const idVec3 &origin, const idMat3 &axis, int entityNum, int primitiveNum, idBrushList brushList)
Definition: AASBuild.cpp:326
int Num(void) const
Definition: List.h:265
idMat3 ToMat3(void) const
Definition: Angles.cpp:199
idBrushList * Copy(void) const
Definition: Brush.cpp:1192
const GLcharARB * name
Definition: glext.h:3629
void ClipBrushSidesWithProcBSP(idBrushList &brushList)
Definition: AASBuild.cpp:259
idBrushMap * ledgeMap
Definition: Str.h:116
void RunReach_f(const idCmdArgs &args)
Definition: AASBuild.cpp:992
const idPlane & GetPlane(void) const
Definition: Brush.h:75
void * Mem_ClearedAlloc(const int size)
Definition: Heap.cpp:1149
const char * GetMaterial(void) const
Definition: MapFile.h:76
int numBoundingBoxes
Definition: AASFile.h:214
const char * c_str(void) const
Definition: Str.h:487
void Build(idBrushList brushList, int skipContents, bool(*ChopAllowed)(idBrush *b1, idBrush *b2), bool(*MergeAllowed)(idBrush *b1, idBrush *b2))
Definition: BrushBSP.cpp:964
bool noOptimize
Definition: AASFile.h:219
void Merge(bool(*MergeAllowed)(idBrush *b1, idBrush *b2))
Definition: Brush.cpp:1397
GLuint res
Definition: glext.h:5385
const char * Argv(int arg) const
Definition: CmdArgs.h:50
GLint j
Definition: qgl.h:264
float dot(float a[], float b[])
Definition: Model_lwo.cpp:3883
virtual void ClearWarnings(const char *reason)=0
virtual void SetRefreshOnPrint(bool set)=0
idMat3 GetMatrix(const char *key, const char *defaultString=NULL) const
Definition: Dict.h:284
int IsLoaded(void)
Definition: Lexer.h:158
bool FixDegeneracies(float distEpsilon)
Definition: Plane.h:260
int GetNumSides(void) const
Definition: Brush.h:115
bool MergeAllowed(idBrush *b1, idBrush *b2)
Definition: AASBuild.cpp:597
virtual void Error(const char *fmt,...) id_attribute((format(printf
int GetNumPrimitives(void) const
Definition: MapFile.h:173
#define SIDE_FRONT
Definition: Plane.h:47
bool playerFlood
Definition: AASFile.h:218
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
Definition: Brush.h:98
int ReadToken(idToken *token)
Definition: Lexer.cpp:820
bool FromSides(idList< idBrushSide * > &sideList)
Definition: Brush.cpp:313
idAASBuild(void)
Definition: AASBuild.cpp:47
#define AREACONTENTS_CLUSTERPORTAL
Definition: AASFile.h:80
int GetWidth(void) const
int Num(void) const
Definition: Brush.h:166
void FitThroughPoint(const idVec3 &p)
Definition: Plane.h:297
void DeleteProcBSP(void)
Definition: AASBuild.cpp:188
void Clear(void)
Definition: List.h:184