]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/compilers/dmap/map.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / compilers / dmap / map.cpp
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 /*
35
36   After parsing, there will be a list of entities that each has
37   a list of primitives.
38   
39   Primitives are either brushes, triangle soups, or model references.
40
41   Curves are tesselated to triangle soups at load time, but model
42   references are 
43   Brushes will have 
44   
45         brushes, each of which has a side definition.
46
47 */
48
49 //
50 // private declarations
51 //
52
53 #define MAX_BUILD_SIDES         300
54
55 static  int             entityPrimitive;                // to track editor brush numbers
56 static  int             c_numMapPatches;
57 static  int             c_areaportals;
58
59 static  uEntity_t       *uEntity;
60
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;
64
65
66 #define NORMAL_EPSILON                  0.00001f
67 #define DIST_EPSILON                    0.01f
68
69
70 /*
71 ===========
72 FindFloatPlane
73 ===========
74 */
75 int FindFloatPlane( const idPlane &plane, bool *fixedDegeneracies ) {
76         idPlane p = plane;
77         bool fixed = p.FixDegeneracies( DIST_EPSILON );
78         if ( fixed && fixedDegeneracies ) {
79                 *fixedDegeneracies = true;
80         }
81         return dmapGlobals.mapPlanes.FindPlane( p, NORMAL_EPSILON, DIST_EPSILON );
82 }
83
84 /*
85 ===========
86 SetBrushContents
87
88 The contents on all sides of a brush should be the same
89 Sets contentsShader, contents, opaque
90 ===========
91 */
92 static void SetBrushContents( uBrush_t *b ) {
93         int                     contents, c2;
94         side_t          *s;
95         int                     i;
96         bool    mixed;
97
98         s = &b->sides[0];
99         contents = s->material->GetContentFlags();
100
101         b->contentShader = s->material;
102         mixed = false;
103
104         // a brush is only opaque if all sides are opaque
105         b->opaque = true;
106
107         for ( i=1 ; i<b->numsides ; i++, s++ ) {
108                 s = &b->sides[i];
109
110                 if ( !s->material ) {
111                         continue;
112                 }
113
114                 c2 = s->material->GetContentFlags();
115                 if (c2 != contents) {
116                         mixed = true;
117                         contents |= c2;
118                 }
119
120                 if ( s->material->Coverage() != MC_OPAQUE ) {
121                         b->opaque = false;
122                 }
123         }
124
125         if ( contents & CONTENTS_AREAPORTAL ) {
126                 c_areaportals++;
127         }
128
129         b->contents = contents;
130 }
131
132
133 //============================================================================
134
135 /*
136 ===============
137 FreeBuildBrush
138 ===============
139 */
140 static void FreeBuildBrush( void ) {
141         int             i;
142
143         for ( i = 0 ; i < buildBrush->numsides ; i++ ) {
144                 if ( buildBrush->sides[i].winding ) {
145                         delete buildBrush->sides[i].winding;
146                 }
147         }
148         buildBrush->numsides = 0;
149 }
150
151 /*
152 ===============
153 FinishBrush
154
155 Produces a final brush based on the buildBrush->sides array
156 and links it to the current entity
157 ===============
158 */
159 static uBrush_t *FinishBrush( void ) {
160         uBrush_t        *b;
161         primitive_t     *prim;
162
163         // create windings for sides and bounds for brush
164         if ( !CreateBrushWindings( buildBrush ) ) {
165                 // don't keep this brush
166                 FreeBuildBrush();
167                 return NULL;
168         }
169
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);
174                         FreeBuildBrush();
175                         return NULL;
176                 }
177         }
178
179         // keep it
180         b = CopyBrush( buildBrush );
181
182         FreeBuildBrush();
183
184         b->entitynum = dmapGlobals.num_entities-1;
185         b->brushnum = entityPrimitive;
186
187         b->original = b;
188
189         prim = (primitive_t *)Mem_Alloc( sizeof( *prim ) );
190         memset( prim, 0, sizeof( *prim ) );
191         prim->next = uEntity->primitives;
192         uEntity->primitives = prim;
193
194         prim->brush = b;
195
196         return b;
197 }
198
199 /*
200 ================
201 AdjustEntityForOrigin
202 ================
203 */
204 static void AdjustEntityForOrigin( uEntity_t *ent ) {
205         primitive_t     *prim;
206         uBrush_t        *b;
207         int                     i;
208         side_t          *s;
209
210         for ( prim = ent->primitives ; prim ; prim = prim->next ) {
211                 b = prim->brush;
212                 if ( !b ) {
213                         continue;
214                 }
215                 for ( i = 0; i < b->numsides; i++ ) {
216                         idPlane plane;
217
218                         s = &b->sides[i];
219
220                         plane = dmapGlobals.mapPlanes[s->planenum];
221                         plane[3] += plane.Normal() * ent->origin;
222                                 
223                         s->planenum = FindFloatPlane( plane );
224
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] );
227
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] );
231                 }
232                 CreateBrushWindings(b);
233         }
234 }
235
236 /*
237 =================
238 RemoveDuplicateBrushPlanes
239
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
243 =================
244 */
245 static bool RemoveDuplicateBrushPlanes( uBrush_t * b ) {
246         int                     i, j, k;
247         side_t          *sides;
248
249         sides = b->sides;
250
251         for ( i = 1 ; i < b->numsides ; i++ ) {
252
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);
257                         // remove it
258                         for ( k = i + 1 ; k < b->numsides ; k++ ) {
259                                 sides[k-1] = sides[k];
260                         }
261                         b->numsides--;
262                         i--;
263                         continue;
264                 }
265
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];
274                                 }
275                                 b->numsides--;
276                                 i--;
277                                 break;
278                         }
279
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);
284                                 return false;
285                         }
286                 }
287         }
288         return true;
289 }
290
291
292 /*
293 =================
294 ParseBrush
295 =================
296 */
297 static void ParseBrush( const idMapBrush *mapBrush, int primitiveNum ) {
298         uBrush_t        *b;
299         side_t          *s;
300         const idMapBrushSide    *ms;
301         int                     i;
302         bool            fixedDegeneracies = false;
303
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);
310
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] );
318         }
319
320         // if there are mirrored planes, the entire brush is invalid
321         if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
322                 return;
323         }
324
325         // get the content for the entire brush
326         SetBrushContents( buildBrush );
327
328         b = FinishBrush();
329         if ( !b ) {
330                 return;
331         }
332
333         if ( fixedDegeneracies && dmapGlobals.verboseentities ) {
334                 common->Warning( "brush %d has degenerate plane equations", primitiveNum );
335         }
336 }
337
338 /*
339 ================
340 ParseSurface
341 ================
342 */
343 static void ParseSurface( const idMapPatch *patch, const idSurface *surface, const idMaterial *material ) {
344         int                             i;
345         mapTri_t                *tri;
346         primitive_t             *prim;
347
348         prim = (primitive_t *)Mem_Alloc( sizeof( *prim ) );
349         memset( prim, 0, sizeof( *prim ) );
350         prim->next = uEntity->primitives;
351         uEntity->primitives = prim;
352
353         for ( i = 0; i < surface->GetNumIndexes(); i += 3 ) {
354                 tri = AllocTri();
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;
360                 prim->tris = tri;
361         }
362
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;
368                 }
369         }
370 }
371
372 /*
373 ================
374 ParsePatch
375 ================
376 */
377 static void ParsePatch( const idMapPatch *patch, int primitiveNum ) {
378         const idMaterial *mat;
379
380         if ( dmapGlobals.noCurves ) {
381                 return;
382         }
383
384         c_numMapPatches++;
385
386         mat = declManager->FindMaterial( patch->GetMaterial() );
387
388         idSurface_Patch *cp = new idSurface_Patch( *patch );
389
390         if ( patch->GetExplicitlySubdivided() ) {
391                 cp->SubdivideExplicit( patch->GetHorzSubdivisions(), patch->GetVertSubdivisions(), true );
392         } else {
393                 cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
394         }
395
396         ParseSurface( patch, cp, mat );
397
398         delete cp;
399 }
400
401 /*
402 ================
403 ProcessMapEntity
404 ================
405 */
406 static bool     ProcessMapEntity( idMapEntity *mapEnt ) {
407         idMapPrimitive  *prim;
408
409         uEntity = &dmapGlobals.uEntities[dmapGlobals.num_entities];
410         memset( uEntity, 0, sizeof(*uEntity) );
411         uEntity->mapEntity = mapEnt;
412         dmapGlobals.num_entities++;
413
414         for ( entityPrimitive = 0; entityPrimitive < mapEnt->GetNumPrimitives(); entityPrimitive++ ) {
415                 prim = mapEnt->GetPrimitive(entityPrimitive);
416
417                 if ( prim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
418                         ParseBrush( static_cast<idMapBrush*>(prim), entityPrimitive );
419                 }
420                 else if ( prim->GetType() == idMapPrimitive::TYPE_PATCH ) {
421                         ParsePatch( static_cast<idMapPatch*>(prim), entityPrimitive );
422                 }
423         }
424
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 );
428         }
429
430         return true;
431 }
432
433 //===================================================================
434
435 /*
436 ==============
437 CreateMapLight
438
439 ==============
440 */
441 static void CreateMapLight( const idMapEntity *mapEnt ) {
442         mapLight_t      *light;
443         bool    dynamic;
444
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
448         // shadow volumes
449         mapEnt->epairs.GetBool( "noPrelight", "0", dynamic );
450         if ( dynamic ) {
451                 return;
452         }
453
454         light = new mapLight_t;
455         light->name[0] = '\0';
456         light->shadowTris = NULL;
457
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 );
462
463         R_DeriveLightData( &light->def );
464
465         // get the name for naming the shadow surfaces
466         const char      *name;
467
468         mapEnt->epairs.GetString( "name", "", &name );
469
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] );
474         }
475 #if 0
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;
480 #endif
481
482         dmapGlobals.mapLights.Append( light );
483
484 }
485
486 /*
487 ==============
488 CreateMapLights
489
490 ==============
491 */
492 static void CreateMapLights( const idMapFile *dmapFile ) {
493         int             i;
494         const idMapEntity *mapEnt;
495         const char      *value;
496
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 );
502                 }
503
504         }
505
506 }
507
508 /*
509 ================
510 LoadDMapFile
511 ================
512 */
513 bool LoadDMapFile( const char *filename ) {             
514         primitive_t     *prim;
515         idBounds        mapBounds;
516         int                     brushes, triSurfs;
517         int                     i;
518         int                     size;
519
520         common->Printf( "--- LoadDMapFile ---\n" );
521         common->Printf( "loading %s\n", filename ); 
522
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 );
529                 return false;
530         }
531
532         dmapGlobals.mapPlanes.Clear();
533         dmapGlobals.mapPlanes.SetGranularity( 1024 );
534
535         // process the canonical form into utility form
536         dmapGlobals.num_entities = 0;
537         c_numMapPatches = 0;
538         c_areaportals = 0;
539
540         size = dmapGlobals.dmapFile->GetNumEntities() * sizeof( dmapGlobals.uEntities[0] );
541         dmapGlobals.uEntities = (uEntity_t *)Mem_Alloc( size );
542         memset( dmapGlobals.uEntities, 0, size );
543
544         // allocate a very large temporary brush for building
545         // the brushes as they are loaded
546         buildBrush = AllocBrush( MAX_BUILD_SIDES );
547
548         for ( i = 0 ; i < dmapGlobals.dmapFile->GetNumEntities() ; i++ ) {
549                 ProcessMapEntity( dmapGlobals.dmapFile->GetEntity(i) );
550         }
551
552         CreateMapLights( dmapGlobals.dmapFile );
553
554         brushes = 0;
555         triSurfs = 0;
556
557         mapBounds.Clear();
558         for ( prim = dmapGlobals.uEntities[0].primitives ; prim ; prim = prim->next ) {
559                 if ( prim->brush ) {
560                         brushes++;
561                         mapBounds.AddBounds( prim->brush->bounds );
562                 } else if ( prim->tris ) {
563                         triSurfs++;
564                 }
565         }
566
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] );
575
576         return true;
577 }
578
579 /*
580 ================
581 FreeOptimizeGroupList
582 ================
583 */
584 void FreeOptimizeGroupList( optimizeGroup_t *groups ) {
585         optimizeGroup_t *next;
586
587         for ( ; groups ; groups = next ) {
588                 next = groups->nextGroup;
589                 FreeTriList( groups->triList );
590                 Mem_Free( groups );
591         }
592 }
593
594 /*
595 ================
596 FreeDMapFile
597 ================
598 */
599 void FreeDMapFile( void ) {
600         int             i, j;
601
602         FreeBrush( buildBrush );
603         buildBrush = NULL;
604
605         // free the entities and brushes
606         for ( i = 0 ; i < dmapGlobals.num_entities ; i++ ) {
607                 uEntity_t       *ent;
608                 primitive_t     *prim, *nextPrim;
609
610                 ent = &dmapGlobals.uEntities[i];
611
612                 FreeTree( ent->tree );
613
614                 // free primitives
615                 for ( prim = ent->primitives ; prim ; prim = nextPrim ) {
616                         nextPrim = prim->next;
617                         if ( prim->brush ) {
618                                 FreeBrush( prim->brush );
619                         }
620                         if ( prim->tris ) {
621                                 FreeTriList( prim->tris );
622                         }
623                         Mem_Free( prim );
624                 }
625
626                 // free area surfaces
627                 if ( ent->areas ) {
628                         for ( j = 0 ; j < ent->numAreas ; j++ ) {
629                                 uArea_t *area;
630
631                                 area = &ent->areas[j];
632                                 FreeOptimizeGroupList( area->groups );
633
634                         }
635                         Mem_Free( ent->areas );
636                 }
637         }
638
639         Mem_Free( dmapGlobals.uEntities );
640
641         dmapGlobals.num_entities = 0;
642
643         // free the map lights
644         for ( i = 0; i < dmapGlobals.mapLights.Num(); i++ ) {
645                 R_FreeLightDefDerivedData( &dmapGlobals.mapLights[i]->def );
646         }
647         dmapGlobals.mapLights.DeleteContents( true );
648 }