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"
34 dmapGlobals_t dmapGlobals;
41 bool ProcessModel( uEntity_t *e, bool floodFill ) {
44 // build a bsp tree using all of the sides
45 // of all of the structural brushes
46 faces = MakeStructuralBspFaceList ( e->primitives );
47 e->tree = FaceBSP( faces );
49 // create portals at every leaf intersection
50 // to allow flood filling
51 MakeTreePortals( e->tree );
53 // classify the leafs as opaque or areaportal
54 FilterBrushesIntoTree( e );
56 // see if the bsp is completely enclosed
57 if ( floodFill && !dmapGlobals.noFlood ) {
58 if ( FloodEntities( e->tree ) ) {
59 // set the outside leafs to opaque
62 common->Printf ( "**********************\n" );
63 common->Warning( "******* leaked *******" );
64 common->Printf ( "**********************\n" );
66 // bail out here. If someone really wants to
67 // process a map that leaks, they should use
73 // get minimum convex hulls for each visible side
74 // this must be done before creating area portals,
75 // because the visible hull is used as the portal
78 // determine areas before clipping tris into the
79 // tree, so tris will never cross area boundaries
82 // we now have a BSP tree with solid and non-solid leafs marked with areas
83 // all primitives will now be clipped into this, throwing away
84 // fragments in the solid areas
85 PutPrimitivesInAreas( e );
87 // now build shadow volumes for the lights and split
88 // the optimize lists by the light beam trees
89 // so there won't be unneeded overdraw in the static
93 // optimizing is a superset of fixing tjunctions
94 if ( !dmapGlobals.noOptimize ) {
96 } else if ( !dmapGlobals.noTJunc ) {
97 FixEntityTjunctions( e );
100 // now fix t junctions across areas
101 FixGlobalTjunctions( e );
111 bool ProcessModels( void ) {
115 oldVerbose = dmapGlobals.verbose;
117 for ( dmapGlobals.entityNum = 0 ; dmapGlobals.entityNum < dmapGlobals.num_entities ; dmapGlobals.entityNum++ ) {
119 entity = &dmapGlobals.uEntities[dmapGlobals.entityNum];
120 if ( !entity->primitives ) {
124 common->Printf( "############### entity %i ###############\n", dmapGlobals.entityNum );
126 // if we leaked, stop without any more processing
127 if ( !ProcessModel( entity, (bool)(dmapGlobals.entityNum == 0 ) ) ) {
131 // we usually don't want to see output for submodels unless
132 // something strange is going on
133 if ( !dmapGlobals.verboseentities ) {
134 dmapGlobals.verbose = false;
138 dmapGlobals.verbose = oldVerbose;
148 void DmapHelp( void ) {
151 "Usage: dmap [options] mapfile\n"
153 "noCurves = don't process curves\n"
154 "noCM = don't create collision map\n"
155 "noAAS = don't create AAS files\n"
165 void ResetDmapGlobals( void ) {
166 dmapGlobals.mapFileBase[0] = '\0';
167 dmapGlobals.dmapFile = NULL;
168 dmapGlobals.mapPlanes.Clear();
169 dmapGlobals.num_entities = 0;
170 dmapGlobals.uEntities = NULL;
171 dmapGlobals.entityNum = 0;
172 dmapGlobals.mapLights.Clear();
173 dmapGlobals.verbose = false;
174 dmapGlobals.glview = false;
175 dmapGlobals.noOptimize = false;
176 dmapGlobals.verboseentities = false;
177 dmapGlobals.noCurves = false;
178 dmapGlobals.fullCarve = false;
179 dmapGlobals.noModelBrushes = false;
180 dmapGlobals.noTJunc = false;
181 dmapGlobals.nomerge = false;
182 dmapGlobals.noFlood = false;
183 dmapGlobals.noClipSides = false;
184 dmapGlobals.noLightCarve = false;
185 dmapGlobals.noShadow = false;
186 dmapGlobals.shadowOptLevel = SO_NONE;
187 dmapGlobals.drawBounds.Clear();
188 dmapGlobals.drawflag = false;
189 dmapGlobals.totalShadowTriangles = 0;
190 dmapGlobals.totalShadowVerts = 0;
198 void Dmap( const idCmdArgs &args ) {
209 if ( args.Argc() < 2 ) {
214 common->Printf("---- dmap ----\n");
216 dmapGlobals.fullCarve = true;
217 dmapGlobals.shadowOptLevel = SO_MERGE_SURFACES; // create shadows by merging all surfaces, but no super optimization
218 // dmapGlobals.shadowOptLevel = SO_CLIP_OCCLUDERS; // remove occluders that are completely covered
219 // dmapGlobals.shadowOptLevel = SO_SIL_OPTIMIZE;
220 // dmapGlobals.shadowOptLevel = SO_CULL_OCCLUDED;
222 dmapGlobals.noLightCarve = true;
224 for ( i = 1 ; i < args.Argc() ; i++ ) {
230 if ( s[0] == '\0' ) {
235 if ( !idStr::Icmp( s,"glview" ) ) {
236 dmapGlobals.glview = true;
237 } else if ( !idStr::Icmp( s, "v" ) ) {
238 common->Printf( "verbose = true\n" );
239 dmapGlobals.verbose = true;
240 } else if ( !idStr::Icmp( s, "draw" ) ) {
241 common->Printf( "drawflag = true\n" );
242 dmapGlobals.drawflag = true;
243 } else if ( !idStr::Icmp( s, "noFlood" ) ) {
244 common->Printf( "noFlood = true\n" );
245 dmapGlobals.noFlood = true;
246 } else if ( !idStr::Icmp( s, "noLightCarve" ) ) {
247 common->Printf( "noLightCarve = true\n" );
248 dmapGlobals.noLightCarve = true;
249 } else if ( !idStr::Icmp( s, "lightCarve" ) ) {
250 common->Printf( "noLightCarve = false\n" );
251 dmapGlobals.noLightCarve = false;
252 } else if ( !idStr::Icmp( s, "noOpt" ) ) {
253 common->Printf( "noOptimize = true\n" );
254 dmapGlobals.noOptimize = true;
255 } else if ( !idStr::Icmp( s, "verboseentities" ) ) {
256 common->Printf( "verboseentities = true\n");
257 dmapGlobals.verboseentities = true;
258 } else if ( !idStr::Icmp( s, "noCurves" ) ) {
259 common->Printf( "noCurves = true\n");
260 dmapGlobals.noCurves = true;
261 } else if ( !idStr::Icmp( s, "noModels" ) ) {
262 common->Printf( "noModels = true\n" );
263 dmapGlobals.noModelBrushes = true;
264 } else if ( !idStr::Icmp( s, "noClipSides" ) ) {
265 common->Printf( "noClipSides = true\n" );
266 dmapGlobals.noClipSides = true;
267 } else if ( !idStr::Icmp( s, "noCarve" ) ) {
268 common->Printf( "noCarve = true\n" );
269 dmapGlobals.fullCarve = false;
270 } else if ( !idStr::Icmp( s, "shadowOpt" ) ) {
271 dmapGlobals.shadowOptLevel = (shadowOptLevel_t)atoi( args.Argv( i+1 ) );
272 common->Printf( "shadowOpt = %i\n",dmapGlobals.shadowOptLevel );
274 } else if ( !idStr::Icmp( s, "noTjunc" ) ) {
275 // triangle optimization won't work properly without tjunction fixing
276 common->Printf ("noTJunc = true\n" );
277 dmapGlobals.noTJunc = true;
278 dmapGlobals.noOptimize = true;
279 common->Printf ("forcing noOptimize = true\n" );
280 } else if ( !idStr::Icmp( s, "noCM" ) ) {
282 common->Printf( "noCM = true\n" );
283 } else if ( !idStr::Icmp( s, "noAAS" ) ) {
285 common->Printf( "noAAS = true\n" );
286 } else if ( !idStr::Icmp( s, "editorOutput" ) ) {
288 com_outputMsg = true;
295 if ( i >= args.Argc() ) {
296 common->Error( "usage: dmap [options] mapfile" );
299 passedName = args.Argv(i); // may have an extension
300 passedName.BackSlashesToSlashes();
301 if ( passedName.Icmpn( "maps/", 4 ) != 0 ) {
302 passedName = "maps/" + passedName;
305 idStr stripped = passedName;
306 stripped.StripFileExtension();
307 idStr::Copynz( dmapGlobals.mapFileBase, stripped, sizeof(dmapGlobals.mapFileBase) );
310 // if this isn't a regioned map, delete the last saved region map
311 if ( passedName.Right( 4 ) != ".reg" ) {
312 sprintf( path, "%s.reg", dmapGlobals.mapFileBase );
313 fileSystem->RemoveFile( path );
319 passedName = stripped;
321 // delete any old line leak files
322 sprintf( path, "%s.lin", dmapGlobals.mapFileBase );
323 fileSystem->RemoveFile( path );
327 // start from scratch
329 start = Sys_Milliseconds();
331 if ( !LoadDMapFile( passedName ) ) {
335 if ( ProcessModels() ) {
343 common->Printf( "%i total shadow triangles\n", dmapGlobals.totalShadowTriangles );
344 common->Printf( "%i total shadow verts\n", dmapGlobals.totalShadowVerts );
346 end = Sys_Milliseconds();
347 common->Printf( "-----------------------\n" );
348 common->Printf( "%5.0f seconds for dmap\n", ( end - start ) * 0.001f );
354 // make sure the collision model manager is not used by the game
355 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "disconnect" );
357 // create the collision map
358 start = Sys_Milliseconds();
360 collisionModelManager->LoadMap( dmapGlobals.dmapFile );
361 collisionModelManager->FreeMap();
363 end = Sys_Milliseconds();
364 common->Printf( "-------------------------------------\n" );
365 common->Printf( "%5.0f seconds to create collision map\n", ( end - start ) * 0.001f );
368 if ( !noAAS && !region ) {
374 // free the common .map representation
375 delete dmapGlobals.dmapFile;
377 // clear the map plane list
378 dmapGlobals.mapPlanes.Clear();
381 if ( com_outputMsg && com_hwndMsg != NULL ) {
382 unsigned int msg = ::RegisterWindowMessage( DMAP_DONE );
383 ::PostMessage( com_hwndMsg, msg, 0, 0 );
393 void Dmap_f( const idCmdArgs &args ) {
395 common->ClearWarnings( "running dmap" );
397 // refresh the screen each time we print so it doesn't look
399 common->SetRefreshOnPrint( true );
401 common->SetRefreshOnPrint( false );
403 common->PrintWarnings();