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"
36 After parsing, there will be a list of entities that each has
39 Primitives are either brushes, triangle soups, or model references.
41 Curves are tesselated to triangle soups at load time, but model
45 brushes, each of which has a side definition.
50 // private declarations
53 #define MAX_BUILD_SIDES 300
55 static int entityPrimitive; // to track editor brush numbers
56 static int c_numMapPatches;
57 static int c_areaportals;
59 static uEntity_t *uEntity;
61 // brushes are parsed into a temporary array of sides,
62 // which will have duplicates removed before the final brush is allocated
63 static uBrush_t *buildBrush;
66 #define NORMAL_EPSILON 0.00001f
67 #define DIST_EPSILON 0.01f
75 int FindFloatPlane( const idPlane &plane, bool *fixedDegeneracies ) {
77 bool fixed = p.FixDegeneracies( DIST_EPSILON );
78 if ( fixed && fixedDegeneracies ) {
79 *fixedDegeneracies = true;
81 return dmapGlobals.mapPlanes.FindPlane( p, NORMAL_EPSILON, DIST_EPSILON );
88 The contents on all sides of a brush should be the same
89 Sets contentsShader, contents, opaque
92 static void SetBrushContents( uBrush_t *b ) {
99 contents = s->material->GetContentFlags();
101 b->contentShader = s->material;
104 // a brush is only opaque if all sides are opaque
107 for ( i=1 ; i<b->numsides ; i++, s++ ) {
110 if ( !s->material ) {
114 c2 = s->material->GetContentFlags();
115 if (c2 != contents) {
120 if ( s->material->Coverage() != MC_OPAQUE ) {
125 if ( contents & CONTENTS_AREAPORTAL ) {
129 b->contents = contents;
133 //============================================================================
140 static void FreeBuildBrush( void ) {
143 for ( i = 0 ; i < buildBrush->numsides ; i++ ) {
144 if ( buildBrush->sides[i].winding ) {
145 delete buildBrush->sides[i].winding;
148 buildBrush->numsides = 0;
155 Produces a final brush based on the buildBrush->sides array
156 and links it to the current entity
159 static uBrush_t *FinishBrush( void ) {
163 // create windings for sides and bounds for brush
164 if ( !CreateBrushWindings( buildBrush ) ) {
165 // don't keep this brush
170 if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
171 if (dmapGlobals.num_entities != 1) {
172 common->Printf("Entity %i, Brush %i: areaportals only allowed in world\n"
173 , dmapGlobals.num_entities - 1, entityPrimitive);
180 b = CopyBrush( buildBrush );
184 b->entitynum = dmapGlobals.num_entities-1;
185 b->brushnum = entityPrimitive;
189 prim = (primitive_t *)Mem_Alloc( sizeof( *prim ) );
190 memset( prim, 0, sizeof( *prim ) );
191 prim->next = uEntity->primitives;
192 uEntity->primitives = prim;
201 AdjustEntityForOrigin
204 static void AdjustEntityForOrigin( uEntity_t *ent ) {
210 for ( prim = ent->primitives ; prim ; prim = prim->next ) {
215 for ( i = 0; i < b->numsides; i++ ) {
220 plane = dmapGlobals.mapPlanes[s->planenum];
221 plane[3] += plane.Normal() * ent->origin;
223 s->planenum = FindFloatPlane( plane );
225 s->texVec.v[0][3] += DotProduct( ent->origin, s->texVec.v[0] );
226 s->texVec.v[1][3] += DotProduct( ent->origin, s->texVec.v[1] );
228 // remove any integral shift
229 s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
230 s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
232 CreateBrushWindings(b);
238 RemoveDuplicateBrushPlanes
240 Returns false if the brush has a mirrored set of planes,
241 meaning it encloses no volume.
242 Also removes planes without any normal
245 static bool RemoveDuplicateBrushPlanes( uBrush_t * b ) {
251 for ( i = 1 ; i < b->numsides ; i++ ) {
253 // check for a degenerate plane
254 if ( sides[i].planenum == -1) {
255 common->Printf("Entity %i, Brush %i: degenerate plane\n"
256 , b->entitynum, b->brushnum);
258 for ( k = i + 1 ; k < b->numsides ; k++ ) {
259 sides[k-1] = sides[k];
266 // check for duplication and mirroring
267 for ( j = 0 ; j < i ; j++ ) {
268 if ( sides[i].planenum == sides[j].planenum ) {
269 common->Printf("Entity %i, Brush %i: duplicate plane\n"
270 , b->entitynum, b->brushnum);
271 // remove the second duplicate
272 for ( k = i + 1 ; k < b->numsides ; k++ ) {
273 sides[k-1] = sides[k];
280 if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
281 // mirror plane, brush is invalid
282 common->Printf("Entity %i, Brush %i: mirrored plane\n"
283 , b->entitynum, b->brushnum);
297 static void ParseBrush( const idMapBrush *mapBrush, int primitiveNum ) {
300 const idMapBrushSide *ms;
302 bool fixedDegeneracies = false;
304 buildBrush->entitynum = dmapGlobals.num_entities-1;
305 buildBrush->brushnum = entityPrimitive;
306 buildBrush->numsides = mapBrush->GetNumSides();
307 for ( i = 0 ; i < mapBrush->GetNumSides() ; i++ ) {
308 s = &buildBrush->sides[i];
309 ms = mapBrush->GetSide(i);
311 memset( s, 0, sizeof( *s ) );
312 s->planenum = FindFloatPlane( ms->GetPlane(), &fixedDegeneracies );
313 s->material = declManager->FindMaterial( ms->GetMaterial() );
314 ms->GetTextureVectors( s->texVec.v );
315 // remove any integral shift, which will help with grouping
316 s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
317 s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
320 // if there are mirrored planes, the entire brush is invalid
321 if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
325 // get the content for the entire brush
326 SetBrushContents( buildBrush );
333 if ( fixedDegeneracies && dmapGlobals.verboseentities ) {
334 common->Warning( "brush %d has degenerate plane equations", primitiveNum );
343 static void ParseSurface( const idMapPatch *patch, const idSurface *surface, const idMaterial *material ) {
348 prim = (primitive_t *)Mem_Alloc( sizeof( *prim ) );
349 memset( prim, 0, sizeof( *prim ) );
350 prim->next = uEntity->primitives;
351 uEntity->primitives = prim;
353 for ( i = 0; i < surface->GetNumIndexes(); i += 3 ) {
355 tri->v[2] = (*surface)[surface->GetIndexes()[i+0]];
356 tri->v[1] = (*surface)[surface->GetIndexes()[i+2]];
357 tri->v[0] = (*surface)[surface->GetIndexes()[i+1]];
358 tri->material = material;
359 tri->next = prim->tris;
363 // set merge groups if needed, to prevent multiple sides from being
364 // merged into a single surface in the case of gui shaders, mirrors, and autosprites
365 if ( material->IsDiscrete() ) {
366 for ( tri = prim->tris ; tri ; tri = tri->next ) {
367 tri->mergeGroup = (void *)patch;
377 static void ParsePatch( const idMapPatch *patch, int primitiveNum ) {
378 const idMaterial *mat;
380 if ( dmapGlobals.noCurves ) {
386 mat = declManager->FindMaterial( patch->GetMaterial() );
388 idSurface_Patch *cp = new idSurface_Patch( *patch );
390 if ( patch->GetExplicitlySubdivided() ) {
391 cp->SubdivideExplicit( patch->GetHorzSubdivisions(), patch->GetVertSubdivisions(), true );
393 cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
396 ParseSurface( patch, cp, mat );
406 static bool ProcessMapEntity( idMapEntity *mapEnt ) {
407 idMapPrimitive *prim;
409 uEntity = &dmapGlobals.uEntities[dmapGlobals.num_entities];
410 memset( uEntity, 0, sizeof(*uEntity) );
411 uEntity->mapEntity = mapEnt;
412 dmapGlobals.num_entities++;
414 for ( entityPrimitive = 0; entityPrimitive < mapEnt->GetNumPrimitives(); entityPrimitive++ ) {
415 prim = mapEnt->GetPrimitive(entityPrimitive);
417 if ( prim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
418 ParseBrush( static_cast<idMapBrush*>(prim), entityPrimitive );
420 else if ( prim->GetType() == idMapPrimitive::TYPE_PATCH ) {
421 ParsePatch( static_cast<idMapPatch*>(prim), entityPrimitive );
425 // never put an origin on the world, even if the editor left one there
426 if ( dmapGlobals.num_entities != 1 ) {
427 uEntity->mapEntity->epairs.GetVector( "origin", "", uEntity->origin );
433 //===================================================================
441 static void CreateMapLight( const idMapEntity *mapEnt ) {
445 // designers can add the "noPrelight" flag to signal that
446 // the lights will move around, so we don't want
447 // to bother chopping up the surfaces under it or creating
449 mapEnt->epairs.GetBool( "noPrelight", "0", dynamic );
454 light = new mapLight_t;
455 light->name[0] = '\0';
456 light->shadowTris = NULL;
458 // parse parms exactly as the game do
459 // use the game's epair parsing code so
460 // we can use the same renderLight generation
461 gameEdit->ParseSpawnArgsToRenderLight( &mapEnt->epairs, &light->def.parms );
463 R_DeriveLightData( &light->def );
465 // get the name for naming the shadow surfaces
468 mapEnt->epairs.GetString( "name", "", &name );
470 idStr::Copynz( light->name, name, sizeof( light->name ) );
471 if ( !light->name[0] ) {
472 common->Error( "Light at (%f,%f,%f) didn't have a name",
473 light->def.parms.origin[0], light->def.parms.origin[1], light->def.parms.origin[2] );
476 // use the renderer code to get the bounding planes for the light
477 // based on all the parameters
478 R_RenderLightFrustum( light->parms, light->frustum );
479 light->lightShader = light->parms.shader;
482 dmapGlobals.mapLights.Append( light );
492 static void CreateMapLights( const idMapFile *dmapFile ) {
494 const idMapEntity *mapEnt;
497 for ( i = 0 ; i < dmapFile->GetNumEntities() ; i++ ) {
498 mapEnt = dmapFile->GetEntity(i);
499 mapEnt->epairs.GetString( "classname", "", &value);
500 if ( !idStr::Icmp( value, "light" ) ) {
501 CreateMapLight( mapEnt );
513 bool LoadDMapFile( const char *filename ) {
516 int brushes, triSurfs;
520 common->Printf( "--- LoadDMapFile ---\n" );
521 common->Printf( "loading %s\n", filename );
523 // load and parse the map file into canonical form
524 dmapGlobals.dmapFile = new idMapFile();
525 if ( !dmapGlobals.dmapFile->Parse(filename) ) {
526 delete dmapGlobals.dmapFile;
527 dmapGlobals.dmapFile = NULL;
528 common->Warning( "Couldn't load map file: '%s'", filename );
532 dmapGlobals.mapPlanes.Clear();
533 dmapGlobals.mapPlanes.SetGranularity( 1024 );
535 // process the canonical form into utility form
536 dmapGlobals.num_entities = 0;
540 size = dmapGlobals.dmapFile->GetNumEntities() * sizeof( dmapGlobals.uEntities[0] );
541 dmapGlobals.uEntities = (uEntity_t *)Mem_Alloc( size );
542 memset( dmapGlobals.uEntities, 0, size );
544 // allocate a very large temporary brush for building
545 // the brushes as they are loaded
546 buildBrush = AllocBrush( MAX_BUILD_SIDES );
548 for ( i = 0 ; i < dmapGlobals.dmapFile->GetNumEntities() ; i++ ) {
549 ProcessMapEntity( dmapGlobals.dmapFile->GetEntity(i) );
552 CreateMapLights( dmapGlobals.dmapFile );
558 for ( prim = dmapGlobals.uEntities[0].primitives ; prim ; prim = prim->next ) {
561 mapBounds.AddBounds( prim->brush->bounds );
562 } else if ( prim->tris ) {
567 common->Printf( "%5i total world brushes\n", brushes );
568 common->Printf( "%5i total world triSurfs\n", triSurfs );
569 common->Printf( "%5i patches\n", c_numMapPatches );
570 common->Printf( "%5i entities\n", dmapGlobals.num_entities );
571 common->Printf( "%5i planes\n", dmapGlobals.mapPlanes.Num() );
572 common->Printf( "%5i areaportals\n", c_areaportals );
573 common->Printf( "size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", mapBounds[0][0], mapBounds[0][1],mapBounds[0][2],
574 mapBounds[1][0], mapBounds[1][1], mapBounds[1][2] );
581 FreeOptimizeGroupList
584 void FreeOptimizeGroupList( optimizeGroup_t *groups ) {
585 optimizeGroup_t *next;
587 for ( ; groups ; groups = next ) {
588 next = groups->nextGroup;
589 FreeTriList( groups->triList );
599 void FreeDMapFile( void ) {
602 FreeBrush( buildBrush );
605 // free the entities and brushes
606 for ( i = 0 ; i < dmapGlobals.num_entities ; i++ ) {
608 primitive_t *prim, *nextPrim;
610 ent = &dmapGlobals.uEntities[i];
612 FreeTree( ent->tree );
615 for ( prim = ent->primitives ; prim ; prim = nextPrim ) {
616 nextPrim = prim->next;
618 FreeBrush( prim->brush );
621 FreeTriList( prim->tris );
626 // free area surfaces
628 for ( j = 0 ; j < ent->numAreas ; j++ ) {
631 area = &ent->areas[j];
632 FreeOptimizeGroupList( area->groups );
635 Mem_Free( ent->areas );
639 Mem_Free( dmapGlobals.uEntities );
641 dmapGlobals.num_entities = 0;
643 // free the map lights
644 for ( i = 0; i < dmapGlobals.mapLights.Num(); i++ ) {
645 R_FreeLightDefDerivedData( &dmapGlobals.mapLights[i]->def );
647 dmapGlobals.mapLights.DeleteContents( true );