]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/compilers/dmap/dmap.cpp
hello world
[icculus/iodoom3.git] / neo / tools / compilers / dmap / dmap.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 dmapGlobals_t   dmapGlobals;
35
36 /*
37 ============
38 ProcessModel
39 ============
40 */
41 bool ProcessModel( uEntity_t *e, bool floodFill ) {
42         bspface_t       *faces;
43
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 );
48
49         // create portals at every leaf intersection
50         // to allow flood filling
51         MakeTreePortals( e->tree );
52
53         // classify the leafs as opaque or areaportal
54         FilterBrushesIntoTree( e );
55
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
60                         FillOutside( e );
61                 } else {
62                         common->Printf ( "**********************\n" );
63                         common->Warning( "******* leaked *******" );
64                         common->Printf ( "**********************\n" );
65                         LeakFile( e->tree );
66                         // bail out here.  If someone really wants to
67                         // process a map that leaks, they should use
68                         // -noFlood
69                         return false;
70                 }
71         }
72
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
76         ClipSidesByTree( e );
77
78         // determine areas before clipping tris into the
79         // tree, so tris will never cross area boundaries
80         FloodAreas( e );
81
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 );
86
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
90         // case
91         Prelight( e );
92
93         // optimizing is a superset of fixing tjunctions
94         if ( !dmapGlobals.noOptimize ) {
95                 OptimizeEntity( e );
96         } else  if ( !dmapGlobals.noTJunc ) {
97                 FixEntityTjunctions( e );
98         }
99
100         // now fix t junctions across areas
101         FixGlobalTjunctions( e );
102
103         return true;
104 }
105
106 /*
107 ============
108 ProcessModels
109 ============
110 */
111 bool ProcessModels( void ) {
112         bool    oldVerbose;
113         uEntity_t       *entity;
114
115         oldVerbose = dmapGlobals.verbose;
116
117         for ( dmapGlobals.entityNum = 0 ; dmapGlobals.entityNum < dmapGlobals.num_entities ; dmapGlobals.entityNum++ ) {
118
119                 entity = &dmapGlobals.uEntities[dmapGlobals.entityNum];
120                 if ( !entity->primitives ) {
121                         continue;
122                 }
123
124                 common->Printf( "############### entity %i ###############\n", dmapGlobals.entityNum );
125
126                 // if we leaked, stop without any more processing
127                 if ( !ProcessModel( entity, (bool)(dmapGlobals.entityNum == 0 ) ) ) {
128                         return false;
129                 }
130
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;
135                 }
136         }
137
138         dmapGlobals.verbose = oldVerbose;
139
140         return true;
141 }
142
143 /*
144 ============
145 DmapHelp
146 ============
147 */
148 void DmapHelp( void ) {
149         common->Printf(
150                 
151         "Usage: dmap [options] mapfile\n"
152         "Options:\n"
153         "noCurves          = don't process curves\n"
154         "noCM              = don't create collision map\n"
155         "noAAS             = don't create AAS files\n"
156         
157         );
158 }
159
160 /*
161 ============
162 ResetDmapGlobals
163 ============
164 */
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;
191 }
192
193 /*
194 ============
195 Dmap
196 ============
197 */
198 void Dmap( const idCmdArgs &args ) {
199         int                     i;
200         int                     start, end;
201         char            path[1024];
202         idStr           passedName;
203         bool            leaked = false;
204         bool            noCM = false;
205         bool            noAAS = false;
206
207         ResetDmapGlobals();
208
209         if ( args.Argc() < 2 ) {
210                 DmapHelp();
211                 return;
212         }
213
214         common->Printf("---- dmap ----\n");
215
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;
221
222         dmapGlobals.noLightCarve = true;
223
224         for ( i = 1 ; i < args.Argc() ; i++ ) {
225                 const char *s;
226
227                 s = args.Argv(i);
228                 if ( s[0] == '-' ) {
229                         s++;
230                         if ( s[0] == '\0' ) {
231                                 continue;
232                         }
233                 }
234
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 );
273                         i += 1;
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" ) ) {
281                         noCM = true;
282                         common->Printf( "noCM = true\n" );
283                 } else if ( !idStr::Icmp( s, "noAAS" ) ) {
284                         noAAS = true;
285                         common->Printf( "noAAS = true\n" );
286                 } else if ( !idStr::Icmp( s, "editorOutput" ) ) {
287 #ifdef _WIN32
288                         com_outputMsg = true;
289 #endif
290                 } else {
291                         break;
292                 }
293         }
294
295         if ( i >= args.Argc() ) {
296                 common->Error( "usage: dmap [options] mapfile" );
297         }
298
299         passedName = args.Argv(i);              // may have an extension
300         passedName.BackSlashesToSlashes();
301         if ( passedName.Icmpn( "maps/", 4 ) != 0 ) {
302                 passedName = "maps/" + passedName;
303         }
304
305         idStr stripped = passedName;
306         stripped.StripFileExtension();
307         idStr::Copynz( dmapGlobals.mapFileBase, stripped, sizeof(dmapGlobals.mapFileBase) );
308
309         bool region = false;
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 );
314         } else {
315                 region = true;
316         }
317
318
319         passedName = stripped;
320
321         // delete any old line leak files
322         sprintf( path, "%s.lin", dmapGlobals.mapFileBase );
323         fileSystem->RemoveFile( path );
324
325
326         //
327         // start from scratch
328         //
329         start = Sys_Milliseconds();
330
331         if ( !LoadDMapFile( passedName ) ) {
332                 return;
333         }
334
335         if ( ProcessModels() ) {
336                 WriteOutputFile();
337         } else {
338                 leaked = true;
339         }
340
341         FreeDMapFile();
342
343         common->Printf( "%i total shadow triangles\n", dmapGlobals.totalShadowTriangles );
344         common->Printf( "%i total shadow verts\n", dmapGlobals.totalShadowVerts );
345
346         end = Sys_Milliseconds();
347         common->Printf( "-----------------------\n" );
348         common->Printf( "%5.0f seconds for dmap\n", ( end - start ) * 0.001f );
349
350         if ( !leaked ) {
351
352                 if ( !noCM ) {
353
354                         // make sure the collision model manager is not used by the game
355                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "disconnect" );
356
357                         // create the collision map
358                         start = Sys_Milliseconds();
359
360                         collisionModelManager->LoadMap( dmapGlobals.dmapFile );
361                         collisionModelManager->FreeMap();
362
363                         end = Sys_Milliseconds();
364                         common->Printf( "-------------------------------------\n" );
365                         common->Printf( "%5.0f seconds to create collision map\n", ( end - start ) * 0.001f );
366                 }
367
368                 if ( !noAAS && !region ) {
369                         // create AAS files
370                         RunAAS_f( args );
371                 }
372         }
373
374         // free the common .map representation
375         delete dmapGlobals.dmapFile;
376
377         // clear the map plane list
378         dmapGlobals.mapPlanes.Clear();
379
380 #ifdef _WIN32
381         if ( com_outputMsg && com_hwndMsg != NULL ) {
382                 unsigned int msg = ::RegisterWindowMessage( DMAP_DONE );
383                 ::PostMessage( com_hwndMsg, msg, 0, 0 );
384         }
385 #endif
386 }
387
388 /*
389 ============
390 Dmap_f
391 ============
392 */
393 void Dmap_f( const idCmdArgs &args ) {
394
395         common->ClearWarnings( "running dmap" );
396
397         // refresh the screen each time we print so it doesn't look
398         // like it is hung
399         common->SetRefreshOnPrint( true );
400         Dmap( args );
401         common->SetRefreshOnPrint( false );
402
403         common->PrintWarnings();
404 }