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 "sys/platform.h"
30 #include "framework/Game.h"
31 
32 #include "tools/compilers/dmap/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 */
FindFloatPlane(const idPlane & plane,bool * fixedDegeneracies)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 */
SetBrushContents(uBrush_t * b)92 static void SetBrushContents( uBrush_t *b ) {
93 	int			contents, c2;
94 	side_t		*s;
95 	int			i;
96 
97 	s = &b->sides[0];
98 	contents = s->material->GetContentFlags();
99 
100 	b->contentShader = s->material;
101 
102 	// a brush is only opaque if all sides are opaque
103 	b->opaque = true;
104 
105 	for ( i=1 ; i<b->numsides ; i++, s++ ) {
106 		s = &b->sides[i];
107 
108 		if ( !s->material ) {
109 			continue;
110 		}
111 
112 		c2 = s->material->GetContentFlags();
113 		if (c2 != contents) {
114 			contents |= c2;
115 		}
116 
117 		if ( s->material->Coverage() != MC_OPAQUE ) {
118 			b->opaque = false;
119 		}
120 	}
121 
122 	if ( contents & CONTENTS_AREAPORTAL ) {
123 		c_areaportals++;
124 	}
125 
126 	b->contents = contents;
127 }
128 
129 
130 //============================================================================
131 
132 /*
133 ===============
134 FreeBuildBrush
135 ===============
136 */
FreeBuildBrush(void)137 static void FreeBuildBrush( void ) {
138 	int		i;
139 
140 	for ( i = 0 ; i < buildBrush->numsides ; i++ ) {
141 		if ( buildBrush->sides[i].winding ) {
142 			delete buildBrush->sides[i].winding;
143 		}
144 	}
145 	buildBrush->numsides = 0;
146 }
147 
148 /*
149 ===============
150 FinishBrush
151 
152 Produces a final brush based on the buildBrush->sides array
153 and links it to the current entity
154 ===============
155 */
FinishBrush(void)156 static uBrush_t *FinishBrush( void ) {
157 	uBrush_t	*b;
158 	primitive_t	*prim;
159 
160 	// create windings for sides and bounds for brush
161 	if ( !CreateBrushWindings( buildBrush ) ) {
162 		// don't keep this brush
163 		FreeBuildBrush();
164 		return NULL;
165 	}
166 
167 	if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
168 		if (dmapGlobals.num_entities != 1) {
169 			common->Printf("Entity %i, Brush %i: areaportals only allowed in world\n"
170 				,  dmapGlobals.num_entities - 1, entityPrimitive);
171 			FreeBuildBrush();
172 			return NULL;
173 		}
174 	}
175 
176 	// keep it
177 	b = CopyBrush( buildBrush );
178 
179 	FreeBuildBrush();
180 
181 	b->entitynum = dmapGlobals.num_entities-1;
182 	b->brushnum = entityPrimitive;
183 
184 	b->original = b;
185 
186 	prim = (primitive_t *)Mem_Alloc( sizeof( *prim ) );
187 	memset( prim, 0, sizeof( *prim ) );
188 	prim->next = uEntity->primitives;
189 	uEntity->primitives = prim;
190 
191 	prim->brush = b;
192 
193 	return b;
194 }
195 
196 /*
197 ================
198 AdjustEntityForOrigin
199 ================
200 */
201 #if 0
202 static void AdjustEntityForOrigin( uEntity_t *ent ) {
203 	primitive_t	*prim;
204 	uBrush_t	*b;
205 	int			i;
206 	side_t		*s;
207 
208 	for ( prim = ent->primitives ; prim ; prim = prim->next ) {
209 		b = prim->brush;
210 		if ( !b ) {
211 			continue;
212 		}
213 		for ( i = 0; i < b->numsides; i++ ) {
214 			idPlane plane;
215 
216 			s = &b->sides[i];
217 
218 			plane = dmapGlobals.mapPlanes[s->planenum];
219 			plane[3] += plane.Normal() * ent->origin;
220 
221 			s->planenum = FindFloatPlane( plane );
222 
223 			s->texVec.v[0][3] += DotProduct( ent->origin, s->texVec.v[0] );
224 			s->texVec.v[1][3] += DotProduct( ent->origin, s->texVec.v[1] );
225 
226 			// remove any integral shift
227 			s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
228 			s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
229 		}
230 		CreateBrushWindings(b);
231 	}
232 }
233 #endif
234 
235 /*
236 =================
237 RemoveDuplicateBrushPlanes
238 
239 Returns false if the brush has a mirrored set of planes,
240 meaning it encloses no volume.
241 Also removes planes without any normal
242 =================
243 */
RemoveDuplicateBrushPlanes(uBrush_t * b)244 static bool RemoveDuplicateBrushPlanes( uBrush_t * b ) {
245 	int			i, j, k;
246 	side_t		*sides;
247 
248 	sides = b->sides;
249 
250 	for ( i = 1 ; i < b->numsides ; i++ ) {
251 
252 		// check for a degenerate plane
253 		if ( sides[i].planenum == -1) {
254 			common->Printf("Entity %i, Brush %i: degenerate plane\n"
255 				, b->entitynum, b->brushnum);
256 			// remove it
257 			for ( k = i + 1 ; k < b->numsides ; k++ ) {
258 				sides[k-1] = sides[k];
259 			}
260 			b->numsides--;
261 			i--;
262 			continue;
263 		}
264 
265 		// check for duplication and mirroring
266 		for ( j = 0 ; j < i ; j++ ) {
267 			if ( sides[i].planenum == sides[j].planenum ) {
268 				common->Printf("Entity %i, Brush %i: duplicate plane\n"
269 					, b->entitynum, b->brushnum);
270 				// remove the second duplicate
271 				for ( k = i + 1 ; k < b->numsides ; k++ ) {
272 					sides[k-1] = sides[k];
273 				}
274 				b->numsides--;
275 				i--;
276 				break;
277 			}
278 
279 			if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
280 				// mirror plane, brush is invalid
281 				common->Printf("Entity %i, Brush %i: mirrored plane\n"
282 					, b->entitynum, b->brushnum);
283 				return false;
284 			}
285 		}
286 	}
287 	return true;
288 }
289 
290 
291 /*
292 =================
293 ParseBrush
294 =================
295 */
ParseBrush(const idMapBrush * mapBrush,int primitiveNum)296 static void ParseBrush( const idMapBrush *mapBrush, int primitiveNum ) {
297 	uBrush_t	*b;
298 	side_t		*s;
299 	const idMapBrushSide	*ms;
300 	int			i;
301 	bool		fixedDegeneracies = false;
302 
303 	buildBrush->entitynum = dmapGlobals.num_entities-1;
304 	buildBrush->brushnum = entityPrimitive;
305 	buildBrush->numsides = mapBrush->GetNumSides();
306 	for ( i = 0 ; i < mapBrush->GetNumSides() ; i++ ) {
307 		s = &buildBrush->sides[i];
308 		ms = mapBrush->GetSide(i);
309 
310 		memset( s, 0, sizeof( *s ) );
311 		s->planenum = FindFloatPlane( ms->GetPlane(), &fixedDegeneracies );
312 		s->material = declManager->FindMaterial( ms->GetMaterial() );
313 		ms->GetTextureVectors( s->texVec.v );
314 		// remove any integral shift, which will help with grouping
315 		s->texVec.v[0][3] -= floor( s->texVec.v[0][3] );
316 		s->texVec.v[1][3] -= floor( s->texVec.v[1][3] );
317 	}
318 
319 	// if there are mirrored planes, the entire brush is invalid
320 	if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
321 		return;
322 	}
323 
324 	// get the content for the entire brush
325 	SetBrushContents( buildBrush );
326 
327 	b = FinishBrush();
328 	if ( !b ) {
329 		return;
330 	}
331 
332 	if ( fixedDegeneracies && dmapGlobals.verboseentities ) {
333 		common->Warning( "brush %d has degenerate plane equations", primitiveNum );
334 	}
335 }
336 
337 /*
338 ================
339 ParseSurface
340 ================
341 */
ParseSurface(const idMapPatch * patch,const idSurface * surface,const idMaterial * material)342 static void ParseSurface( const idMapPatch *patch, const idSurface *surface, const idMaterial *material ) {
343 	int				i;
344 	mapTri_t		*tri;
345 	primitive_t		*prim;
346 
347 	prim = (primitive_t *)Mem_Alloc( sizeof( *prim ) );
348 	memset( prim, 0, sizeof( *prim ) );
349 	prim->next = uEntity->primitives;
350 	uEntity->primitives = prim;
351 
352 	for ( i = 0; i < surface->GetNumIndexes(); i += 3 ) {
353 		tri = AllocTri();
354 		tri->v[2] = (*surface)[surface->GetIndexes()[i+0]];
355 		tri->v[1] = (*surface)[surface->GetIndexes()[i+2]];
356 		tri->v[0] = (*surface)[surface->GetIndexes()[i+1]];
357 		tri->material = material;
358 		tri->next = prim->tris;
359 		prim->tris = tri;
360 	}
361 
362 	// set merge groups if needed, to prevent multiple sides from being
363 	// merged into a single surface in the case of gui shaders, mirrors, and autosprites
364 	if ( material->IsDiscrete() ) {
365 		for ( tri = prim->tris ; tri ; tri = tri->next ) {
366 			tri->mergeGroup = (void *)patch;
367 		}
368 	}
369 }
370 
371 /*
372 ================
373 ParsePatch
374 ================
375 */
ParsePatch(const idMapPatch * patch,int primitiveNum)376 static void ParsePatch( const idMapPatch *patch, int primitiveNum ) {
377 	const idMaterial *mat;
378 
379 	if ( dmapGlobals.noCurves ) {
380 		return;
381 	}
382 
383 	c_numMapPatches++;
384 
385 	mat = declManager->FindMaterial( patch->GetMaterial() );
386 
387 	idSurface_Patch *cp = new idSurface_Patch( *patch );
388 
389 	if ( patch->GetExplicitlySubdivided() ) {
390 		cp->SubdivideExplicit( patch->GetHorzSubdivisions(), patch->GetVertSubdivisions(), true );
391 	} else {
392 		cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
393 	}
394 
395 	ParseSurface( patch, cp, mat );
396 
397 	delete cp;
398 }
399 
400 /*
401 ================
402 ProcessMapEntity
403 ================
404 */
ProcessMapEntity(idMapEntity * mapEnt)405 static bool	ProcessMapEntity( idMapEntity *mapEnt ) {
406 	idMapPrimitive	*prim;
407 
408 	uEntity = &dmapGlobals.uEntities[dmapGlobals.num_entities];
409 	memset( uEntity, 0, sizeof(*uEntity) );
410 	uEntity->mapEntity = mapEnt;
411 	dmapGlobals.num_entities++;
412 
413 	for ( entityPrimitive = 0; entityPrimitive < mapEnt->GetNumPrimitives(); entityPrimitive++ ) {
414 		prim = mapEnt->GetPrimitive(entityPrimitive);
415 
416 		if ( prim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
417 			ParseBrush( static_cast<idMapBrush*>(prim), entityPrimitive );
418 		}
419 		else if ( prim->GetType() == idMapPrimitive::TYPE_PATCH ) {
420 			ParsePatch( static_cast<idMapPatch*>(prim), entityPrimitive );
421 		}
422 	}
423 
424 	// never put an origin on the world, even if the editor left one there
425 	if ( dmapGlobals.num_entities != 1 ) {
426 		uEntity->mapEntity->epairs.GetVector( "origin", "", uEntity->origin );
427 	}
428 
429 	return true;
430 }
431 
432 //===================================================================
433 
434 /*
435 ==============
436 CreateMapLight
437 
438 ==============
439 */
CreateMapLight(const idMapEntity * mapEnt)440 static void CreateMapLight( const idMapEntity *mapEnt ) {
441 	mapLight_t	*light;
442 	bool	dynamic;
443 
444 	// designers can add the "noPrelight" flag to signal that
445 	// the lights will move around, so we don't want
446 	// to bother chopping up the surfaces under it or creating
447 	// shadow volumes
448 	mapEnt->epairs.GetBool( "noPrelight", "0", dynamic );
449 	if ( dynamic ) {
450 		return;
451 	}
452 
453 	light = new mapLight_t;
454 	light->name[0] = '\0';
455 	light->shadowTris = NULL;
456 
457 	// parse parms exactly as the game do
458 	// use the game's epair parsing code so
459 	// we can use the same renderLight generation
460 	gameEdit->ParseSpawnArgsToRenderLight( &mapEnt->epairs, &light->def.parms );
461 
462 	R_DeriveLightData( &light->def );
463 
464 	// get the name for naming the shadow surfaces
465 	const char	*name;
466 
467 	mapEnt->epairs.GetString( "name", "", &name );
468 
469 	idStr::Copynz( light->name, name, sizeof( light->name ) );
470 	if ( !light->name[0] ) {
471 		common->Error( "Light at (%f,%f,%f) didn't have a name",
472 			light->def.parms.origin[0], light->def.parms.origin[1], light->def.parms.origin[2] );
473 	}
474 #if 0
475 	// use the renderer code to get the bounding planes for the light
476 	// based on all the parameters
477 	R_RenderLightFrustum( light->parms, light->frustum );
478 	light->lightShader = light->parms.shader;
479 #endif
480 
481 	dmapGlobals.mapLights.Append( light );
482 
483 }
484 
485 /*
486 ==============
487 CreateMapLights
488 
489 ==============
490 */
CreateMapLights(const idMapFile * dmapFile)491 static void CreateMapLights( const idMapFile *dmapFile ) {
492 	int		i;
493 	const idMapEntity *mapEnt;
494 	const char	*value;
495 
496 	for ( i = 0 ; i < dmapFile->GetNumEntities() ; i++ ) {
497 		mapEnt = dmapFile->GetEntity(i);
498 		mapEnt->epairs.GetString( "classname", "", &value);
499 		if ( !idStr::Icmp( value, "light" ) ) {
500 			CreateMapLight( mapEnt );
501 		}
502 
503 	}
504 
505 }
506 
507 /*
508 ================
509 LoadDMapFile
510 ================
511 */
LoadDMapFile(const char * filename)512 bool LoadDMapFile( const char *filename ) {
513 	primitive_t	*prim;
514 	idBounds	mapBounds;
515 	int			brushes, triSurfs;
516 	int			i;
517 	int			size;
518 
519 	common->Printf( "--- LoadDMapFile ---\n" );
520 	common->Printf( "loading %s\n", filename );
521 
522 	// load and parse the map file into canonical form
523 	dmapGlobals.dmapFile = new idMapFile();
524 	if ( !dmapGlobals.dmapFile->Parse(filename) ) {
525 		delete dmapGlobals.dmapFile;
526 		dmapGlobals.dmapFile = NULL;
527 		common->Warning( "Couldn't load map file: '%s'", filename );
528 		return false;
529 	}
530 
531 	dmapGlobals.mapPlanes.Clear();
532 	dmapGlobals.mapPlanes.SetGranularity( 1024 );
533 
534 	// process the canonical form into utility form
535 	dmapGlobals.num_entities = 0;
536 	c_numMapPatches = 0;
537 	c_areaportals = 0;
538 
539 	size = dmapGlobals.dmapFile->GetNumEntities() * sizeof( dmapGlobals.uEntities[0] );
540 	dmapGlobals.uEntities = (uEntity_t *)Mem_Alloc( size );
541 	memset( dmapGlobals.uEntities, 0, size );
542 
543 	// allocate a very large temporary brush for building
544 	// the brushes as they are loaded
545 	buildBrush = AllocBrush( MAX_BUILD_SIDES );
546 
547 	for ( i = 0 ; i < dmapGlobals.dmapFile->GetNumEntities() ; i++ ) {
548 		ProcessMapEntity( dmapGlobals.dmapFile->GetEntity(i) );
549 	}
550 
551 	CreateMapLights( dmapGlobals.dmapFile );
552 
553 	brushes = 0;
554 	triSurfs = 0;
555 
556 	mapBounds.Clear();
557 	for ( prim = dmapGlobals.uEntities[0].primitives ; prim ; prim = prim->next ) {
558 		if ( prim->brush ) {
559 			brushes++;
560 			mapBounds.AddBounds( prim->brush->bounds );
561 		} else if ( prim->tris ) {
562 			triSurfs++;
563 		}
564 	}
565 
566 	common->Printf( "%5i total world brushes\n", brushes );
567 	common->Printf( "%5i total world triSurfs\n", triSurfs );
568 	common->Printf( "%5i patches\n", c_numMapPatches );
569 	common->Printf( "%5i entities\n", dmapGlobals.num_entities );
570 	common->Printf( "%5i planes\n", dmapGlobals.mapPlanes.Num() );
571 	common->Printf( "%5i areaportals\n", c_areaportals );
572 	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],
573 				mapBounds[1][0], mapBounds[1][1], mapBounds[1][2] );
574 
575 	return true;
576 }
577 
578 /*
579 ================
580 FreeOptimizeGroupList
581 ================
582 */
FreeOptimizeGroupList(optimizeGroup_t * groups)583 void FreeOptimizeGroupList( optimizeGroup_t *groups ) {
584 	optimizeGroup_t	*next;
585 
586 	for ( ; groups ; groups = next ) {
587 		next = groups->nextGroup;
588 		FreeTriList( groups->triList );
589 		Mem_Free( groups );
590 	}
591 }
592 
593 /*
594 ================
595 FreeDMapFile
596 ================
597 */
FreeDMapFile(void)598 void FreeDMapFile( void ) {
599 	int		i, j;
600 
601 	FreeBrush( buildBrush );
602 	buildBrush = NULL;
603 
604 	// free the entities and brushes
605 	for ( i = 0 ; i < dmapGlobals.num_entities ; i++ ) {
606 		uEntity_t	*ent;
607 		primitive_t	*prim, *nextPrim;
608 
609 		ent = &dmapGlobals.uEntities[i];
610 
611 		FreeTree( ent->tree );
612 
613 		// free primitives
614 		for ( prim = ent->primitives ; prim ; prim = nextPrim ) {
615 			nextPrim = prim->next;
616 			if ( prim->brush ) {
617 				FreeBrush( prim->brush );
618 			}
619 			if ( prim->tris ) {
620 				FreeTriList( prim->tris );
621 			}
622 			Mem_Free( prim );
623 		}
624 
625 		// free area surfaces
626 		if ( ent->areas ) {
627 			for ( j = 0 ; j < ent->numAreas ; j++ ) {
628 				uArea_t	*area;
629 
630 				area = &ent->areas[j];
631 				FreeOptimizeGroupList( area->groups );
632 
633 			}
634 			Mem_Free( ent->areas );
635 		}
636 	}
637 
638 	Mem_Free( dmapGlobals.uEntities );
639 
640 	dmapGlobals.num_entities = 0;
641 
642 	// free the map lights
643 	for ( i = 0; i < dmapGlobals.mapLights.Num(); i++ ) {
644 		R_FreeLightDefDerivedData( &dmapGlobals.mapLights[i]->def );
645 	}
646 	dmapGlobals.mapLights.DeleteContents( true );
647 }
648