UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ufo2map.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program 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.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #define VERSION "1.2.6"
27 #define REVISION "1"
28 
29 /* valid -nolighting parameters */
30 #define LIGHTING_NONE 1
31 #define LIGHTING_DAY_ONLY 2
32 #define LIGHTING_NIGHT_ONLY 3
33 
34 #ifdef _WIN32
35 #include <windows.h>
36 #else
37 #include <sys/resource.h>
38 #endif
39 
40 #include "lighting.h"
41 #include "bsp.h"
42 #include "check/check.h"
43 #include "check/checkentities.h"
44 #include "check/checklib.h"
45 #include "../../shared/shared.h"
46 #include "ufo2map.h"
47 #include <SDL_main.h>
48 
50 static char mapFilename[MAX_OSPATH];
51 
54 
57 typedef struct usagePair_s {
58  const char* flags;
59  const char* desc;
60 } usagePair_t;
61 
62 static const usagePair_t usageArray[] = {
63  {"Usage: ufo2map <param1 <subparam1> <subparam2> <...>> <param2> <...> [map]", nullptr},
64 #ifdef _WIN32
65  {"Even on Windows, use / slashes in the path", nullptr},
66 #endif
67  {"\nGeneral options:",nullptr},
68  {" -h --help", "print (this) help and exit"},
69 #ifdef _WIN32
70  {" -nice <prio>","priority level [0 = HIGH, 1 = NORMAL, 2 = IDLE]"},
71 #else
72  {" -nice <prio>","priority level [unix nice level from -20 to 19 where 19 is the lowest priority]"},
73 #endif
74  {" -nofootstep","don't generate a footstep file"},
75  {" -tracefile","generate two csv files describing the floors and walls found by the trace functions"},
76  {" -debugfile (TODO)","generate a trace debug file. The client can load the file to highlight map obstructions"},
77  {" -stats --statistics","print statistics and quit. may be used with -check or -fix"},
78  {" -v --verbosity <int>","set verbosity. higher <int> gives more output"},
79  {nullptr, "if it is required, this should be the first option"},
80  {nullptr, "0 - no stdout, 1 - only check/fix messages, 2 - (compile) only mapname"},
81  {nullptr, "2 - (check/fix) mapname if findings, 4 - normal output,"},
82  {nullptr, "5 - extra output, 6 - dump (a lot extra from BSPing)"},
83  /* Do not change the -V output, you will break compile_maps.bat */
84  {" -V --version","return Version and Revision level"},
85  {" -material","generate a material (.mat) file, do not proceed to compilation"},
86  {"\nLighting options:", nullptr},
87  {" -extra","extra light samples"},
88  {" -nolighting TYPE","don't perform the lighting calculations, where TYPE is one of day, night, all"},
89  {nullptr, "default is all"},
90  {" -quant","lightquant - lightmap resolution downscale (e.g. 4 = 1 << 4) (values between 1 and 6)"},
91  {" -scale","global light scale factor"},
92  {" -saturation","saturation factor (e.g. 1.5 - default is 1.0)"},
93  {" -contrast","contrast factor (e.g. 1.05, default is 1.0)"},
94  {" -t --threads","thread amount"},
95  {"\nBinary space partitioning (BSPing) options:", nullptr},
96  {" -block <xl> <yl>",""},
97  {" -blocks <xl> <yl> <xh> <yh>",""},
98  {" -subdivide","subdivide brushes for better light effects (but higher polycount)"},
99  {" -surface","surface light scaling (float value)"},
100  {" -entity","entity light scaling (float value)"},
101  {" -fulldetail","don't treat details (and trans surfaces) as details"},
102  {" -info","print bsp file info"},
103  {" -micro <float>","warn if a brush has a volume lower than the specified float."},
104  {nullptr, "brushes are tested after CSG."},
105  {" -nobackclip","draw downward pointing faces. (so actors cannot see up through floors"},
106  {nullptr, "in first person view). default is to set SURF_NODRAW to downard faces."},
107  {" -nocsg",""},
108  {" -gamedir", "Add another game dir to the search directories"},
109  {" -nodetail","skip detail brushes"},
110  {" -nomerge","skip node face merging"},
111  {" -noprune","don't prune (or cut) nodes"},
112  {" -noshare",""},
113  {" -notjunc",""},
114  {" -nowater","skip water brushes in compilation"},
115  {" -noweld",""},
116  {" -onlyents","modify existing bsp file with entities from map file"},
117  {" -exportlightmaps","write lightmaps into tga images"},
118  {" -verboseentities","also be verbose about submodels (entities)"},
119  {"\nMapping options:", nullptr},
120  {"\n These options operate on map file only. No bsp file is created.", nullptr},
121  {" Output prefixed by an asterisk (*) indicates operations that would change the map file.", nullptr},
122  {" -check","check source map, only print information."},
123  {" -fix","same subparameters as -check, changes the source map file."},
124  {" \n subparameters for -check and -fix", nullptr},
125  {" all","performs all checks and fixes. This is the default."},
126  {" bru brushes","includes 'lvl tex mfc mbr'. Performs all checks and fixes associated with brushes."},
127  {" ent entities","performs all checks and fixes associated with entities."},
128  {" con contained","checks for brushes contained entirely within other brushes. includes coincident duplicates."},
129  {" isc intersection","report intersection between optimisable brushes from worldspawn and func_group entities"},
130  {nullptr, "this is not included in all or bru as it is not always a bad thing"},
131  {" mbr microbrush <float> ","test for brushes smaller than <float> unit^3. this is done without the csg"},
132  {nullptr, "step, unlike the bsp -micro option. default 1 unit^3."},
133  {" lvl levelflags","if no levelflags for a brush or entity are set, all of them are set"},
134  {" flv filllevelflags","ensure set levelflag bits are uninterrupted"},
135  {" ndr nodraws","assigns SURF_NODRAW to hidden faces"},
136  {" tex textures","warns when no texture or error texture is assigned."},
137  {nullptr, "ensures special textures and content/surface flags are consistent."},
138  {" mfc mixedfacecontents","ensures the contentflags are the same on each face of each brush."},
139  {" zft zfighting","intersecting brushes with a common face: prevent textures shimmering together"},
140 
141  {nullptr, nullptr}
142 };
143 
147 static void Usage (void)
148 {
149  const usagePair_t* v;
150  int maxFlagsLen = 0;
151 
152  /* run through to find the length of the longest
153  * flags string */
154  for (v = usageArray; v->flags || v->desc; v++)
155  if (v->flags && v->desc) {
156  const int len = strlen(v->flags);
157  maxFlagsLen = len > maxFlagsLen ? len : maxFlagsLen;
158  }
159 
160  for (v = usageArray; v->flags || v->desc; v++) {
161  if (v->flags && v->desc)
162  Com_Printf("%-*s: %s\n", maxFlagsLen, v->flags, v->desc);
163  else if (v->desc)
164  Com_Printf("%*s %s\n", maxFlagsLen, "", v->desc);
165  else /* must be v->flags only, a full line not describing a flag */
166  Com_Printf("%s\n",v->flags);
167  }
168 }
169 
170 void Com_Printf (const char* format, ...)
171 {
172  char out_buffer[4096];
173  va_list argptr;
174 
175  va_start(argptr, format);
176  Q_vsnprintf(out_buffer, sizeof(out_buffer), format, argptr);
177  va_end(argptr);
178 
179  printf("%s", out_buffer);
180 }
181 
189 bool AbortPrint (const verbosityLevel_t msgVerbLevel)
190 {
191  return (msgVerbLevel > config.verbosity);
192 }
193 
198 void Verb_Printf (const verbosityLevel_t msgVerbLevel, const char* format, ...)
199 {
200  if (AbortPrint(msgVerbLevel))
201  return;
202 
203  char out_buffer[4096];
204  va_list argptr;
205 
206  va_start(argptr, format);
207  Q_vsnprintf(out_buffer, sizeof(out_buffer), format, argptr);
208  va_end(argptr);
209 
210  printf("%s", out_buffer);
211 }
212 
216 static void U2M_Parameter (int argc, char** argv)
217 {
218  int i;
219 
220  for (i = 1; i < argc; i++) {
221  if (Q_streq(argv[i], "-v") || Q_streq(argv[i], "-verbosity")) {
222  /* arg to -v should be a single digit. if it is not a number
223  * atoi will return 0, and no warning will be given. so check that
224  * it looks like the arg for -v first */
225  if (strlen(argv[i + 1]) == 1)
226  config.verbosity = (verbosityLevel_t)atoi(argv[++i]);
227  Verb_Printf(VERB_LESS, "verbosity = %i\n", config.verbosity);
228  } else if (Q_streq(argv[i], "-noweld")) {
229  /* make every point unique */
230  Verb_Printf(VERB_LESS, "noweld = true\n");
231  config.noweld = true;
232  } else if (Q_streq(argv[i], "--statistics") || Q_streq(argv[i], "-stats")) {
233  Verb_Printf(VERB_LESS, "statistics mode\n");
234  config.stats = true;
235  config.performMapCheck = true;
236  } else if (Q_streq(argv[i], "-check") || Q_streq(argv[i], "-fix")) {
237  /* check for subparameters terminate loop before last arg (path) or
238  * when we hit a param (as opposed to a subparam).
239  * full parameters are prefixed with "-". */
240  const int iInitial = i;
241 
242  if (Q_streq(argv[i], "-check")) {
243  Verb_Printf(VERB_LESS, "check = true\n");
244  config.performMapCheck = true;
245  }
246  if (Q_streq(argv[i], "-fix")) {
247  Verb_Printf(VERB_LESS, "fix = true\n");
248  config.fixMap = true;
249  }
250  while (++i < (argc - 1) && argv[i][0] != '-') {
251  if (Q_streq(argv[i], "entities") || Q_streq(argv[i], "ent")) {
252  Verb_Printf(VERB_LESS, " %s entities\n", config.fixMap ? "fixing" : "checking");
253  config.chkEntities = true;
254  } else if (Q_streq(argv[i], "brushes") || Q_streq(argv[i], "bru")) {
255  Verb_Printf(VERB_LESS, " %s brushes\n", config.fixMap ? "fixing" : "checking");
256  config.chkBrushes = true;
257  } else if (Q_streq(argv[i], "contained") || Q_streq(argv[i], "con")) {
258  Verb_Printf(VERB_LESS, " %s contained brushes\n", config.fixMap ? "fixing" : "checking");
259  config.chkContained = true;
260  } else if (Q_streq(argv[i], "filllevelflags") || Q_streq(argv[i], "flv")) {
261  Verb_Printf(VERB_LESS, " %s filllevelflags\n", config.fixMap ? "fixing" : "checking");
262  config.chkFillLevelFlags = true;
263  } else if (Q_streq(argv[i], "levelflags") || Q_streq(argv[i], "lvl")) {
264  Verb_Printf(VERB_LESS, " %s levelflags\n", config.fixMap ? "fixing" : "checking");
265  config.chkLevelFlags = true;
266  } else if (Q_streq(argv[i], "textures") || Q_streq(argv[i], "tex")) {
267  Verb_Printf(VERB_LESS, " %s textures\n", config.fixMap ? "fixing" : "checking");
268  config.chkTextures = true;
269  } else if (Q_streq(argv[i], "nodraws") || Q_streq(argv[i], "ndr")) {
270  Verb_Printf(VERB_LESS, " %s nodraws\n", config.fixMap ? "fixing" : "checking");
271  config.chkNodraws = true;
272  } else if (Q_streq(argv[i], "intersection") || Q_streq(argv[i], "isc")) {
273  Verb_Printf(VERB_LESS, " %s intersection\n", config.fixMap ? "fixing" : "checking");
274  config.chkIntersection = true;
275  } else if (Q_streq(argv[i], "mixedfacecontents") || Q_streq(argv[i], "mfc")) {
276  Verb_Printf(VERB_LESS, " %s mixedfacecontents\n", config.fixMap ? "fixing" : "checking");
277  config.chkMixedFaceContents = true;
278  } else if (Q_streq(argv[i], "microbrush") || Q_streq(argv[i], "mbr")) {
279  config.chkMMicro = true;
280  if (atof(argv[i + 1]) > 0.0001) {
281  config.mapMicrovol = atof(argv[i + 1]);
282  i++;
283  }
284  Verb_Printf(VERB_LESS, " checking map for microbrushes smaller than %f unit^3\n", config.mapMicrovol);
285  } else if (Q_streq(argv[i], "zfighting") || Q_streq(argv[i], "zft")) {
286  Verb_Printf(VERB_LESS, " %s for z-fighting\n", config.fixMap ? "fixing" : "checking");
287  config.chkZFight = true;
288  } else if (Q_streq(argv[i], "all")) {
289  Verb_Printf(VERB_LESS, " %s all (entites brushes)\n", config.fixMap ? "fixing" : "checking");
290  config.chkAll = true;
291  } else {
292  Verb_Printf(VERB_LESS, " WARNING: %s subparameter not understood:%s try --help for more info\n", config.fixMap ? "fix" : "check", argv[i]);
293  }
294  }
295  i--;
296  /* if no subparams set, assume all */
297  if (i == iInitial) {
298  Verb_Printf(VERB_LESS, " no %s subparameters set, assuming all\n", config.fixMap ? "fix" : "check");
299  config.chkAll = true;
300  }
301  } else if (Q_streq(argv[i], "-h") || Q_streq(argv[i], "--help")) {
302  Usage();
303  exit(0);
304  } else if (Q_streq(argv[i], "-t") || Q_streq(argv[i], "-threads")) {
305  threadstate.numthreads = atoi(argv[++i]);
306  Verb_Printf(VERB_LESS, "threads: #%i\n", threadstate.numthreads);
307  } else if (Q_streq(argv[i], "-info")) {
308  config.info = true;
309  } else if (Q_streq(argv[i], "-nocsg")) {
310  Verb_Printf(VERB_LESS, "nocsg = true\n");
311  config.nocsg = true;
312  } else if (Q_streq(argv[i], "-gamedir")) {
313  Q_strncpyz(config.gamedir, argv[i + 1], sizeof(config.gamedir));
314  // just in case, convert any OS-path seperators to UFO-path separaters
315  FS_NormPath(config.gamedir);
316  Verb_Printf(VERB_LESS, "additional gamedir = %s\n", config.gamedir);
317  i++;
318  } else if (Q_streq(argv[i], "-noshare")) {
319  Verb_Printf(VERB_LESS, "noshare = true\n");
320  config.noshare = true;
321  } else if (Q_streq(argv[i], "-notjunc")) {
322  Verb_Printf(VERB_LESS, "notjunc = true\n");
323  config.notjunc = true;
324  } else if (Q_streq(argv[i], "-nowater")) {
325  Verb_Printf(VERB_LESS, "nowater = true\n");
326  config.nowater = true;
327  } else if (Q_streq(argv[i], "-nice")) {
328 #if defined _WIN32
329  HANDLE proc = GetCurrentProcess();
330  config.nice = atoi(argv[++i]);
331  Verb_Printf(VERB_LESS, "nice = %i\n", config.nice);
332  switch (config.nice) {
333  case 0:
334  SetPriorityClass(proc, HIGH_PRIORITY_CLASS);
335  Verb_Printf(VERB_LESS, "Priority changed to HIGH\n");
336  break;
337  case 1:
338  SetPriorityClass(proc, NORMAL_PRIORITY_CLASS);
339  Verb_Printf(VERB_LESS, "Priority changed to NORMAL\n");
340  break;
341  default:
342  SetPriorityClass(proc, IDLE_PRIORITY_CLASS);
343  Verb_Printf(VERB_LESS, "Priority changed to IDLE\n");
344  break;
345  }
346  CloseHandle(proc);
347 #else
348  config.nice = atoi(argv[++i]);
349  Verb_Printf(VERB_LESS, "nice = %i\n", config.nice);
350  if (setpriority(PRIO_PROCESS, 0, config.nice))
351  Verb_Printf(VERB_LESS, "failed to set nice level of %i\n", config.nice);
352 #endif
353  } else if (Q_streq(argv[i], "-noprune")) {
354  Verb_Printf(VERB_LESS, "noprune = true\n");
355  config.noprune = true;
356  } else if (Q_streq(argv[i],"-nofootstep")) {
357  config.generateFootstepFile = false;
358  Verb_Printf(VERB_LESS, "generateFootstepFile = false\n");
359  } else if (Q_streq(argv[i],"-tracefile")) {
360  config.generateTraceFile = true;
361  Verb_Printf(VERB_NORMAL, "generateTraceFile = true\n");
362  } else if (Q_streq(argv[i],"-debugtrace")) {
363  config.generateDebugTrace = true;
364  Verb_Printf(VERB_NORMAL, "generateDebugTrace = true\n");
365  } else if (Q_streq(argv[i],"-material")) {
366  config.generateMaterialFile = true;
367  Verb_Printf(VERB_LESS, "generateMaterialFile = true\n");
368  } else if (Q_streq(argv[i], "-nomerge")) {
369  Verb_Printf(VERB_LESS, "nomerge = true\n");
370  config.nomerge = true;
371  } else if (Q_streq(argv[i], "-nosubdiv")) {
372  Verb_Printf(VERB_LESS, "nosubdiv = true\n");
373  config.nosubdiv = true;
374  } else if (Q_streq(argv[i], "-nodetail")) {
375  Verb_Printf(VERB_LESS, "nodetail = true\n");
376  config.nodetail = true;
377  } else if (Q_streq(argv[i], "-fulldetail")) {
378  Verb_Printf(VERB_LESS, "fulldetail = true\n");
379  config.fulldetail = true;
380  } else if (Q_streq(argv[i], "-onlyents")) {
381  Verb_Printf(VERB_LESS, "onlyents = true\n");
382  config.onlyents = true;
383  } else if (Q_streq(argv[i], "-exportlightmaps")) {
384  Verb_Printf(VERB_LESS, "exportlightmaps = true\n");
385  config.exportLightmaps = true;
386  } else if (Q_streq(argv[i], "-micro")) {
387  config.microvolume = atof(argv[i + 1]);
388  Verb_Printf(VERB_LESS, "microvolume = %f\n", config.microvolume);
389  i++;
390  } else if (Q_streq(argv[i], "-verboseentities")) {
391  Verb_Printf(VERB_LESS, "verboseentities = true\n");
392  config.verboseentities = true;
393  } else if (Q_streq(argv[i], "-subdivide")) {
394  config.subdivideSize = atof(argv[i + 1]);
395  Verb_Printf(VERB_LESS, "subdivide_size = %f\n", config.subdivideSize);
396  i++;
397  } else if (Q_streq(argv[i], "-block")) {
398  config.block_xl = config.block_xh = atoi(argv[i + 1]);
399  config.block_yl = config.block_yh = atoi(argv[i + 2]);
400  Verb_Printf(VERB_LESS, "block: %i,%i\n", config.block_xl, config.block_yl);
401  i += 2;
402  } else if (Q_streq(argv[i], "-blocks")) {
403  config.block_xl = atoi(argv[i + 1]);
404  config.block_yl = atoi(argv[i + 2]);
405  config.block_xh = atoi(argv[i + 3]);
406  config.block_yh = atoi(argv[i + 4]);
407  Verb_Printf(VERB_LESS, "blocks: %i,%i to %i,%i\n",
408  config.block_xl, config.block_yl, config.block_xh, config.block_yh);
409  i += 4;
410  } else if (Q_streq(argv[i], "-nobackclip")) {
411  Verb_Printf(VERB_LESS, "nobackclip = true\n");
412  config.nobackclip = true;
413  } else if (Q_streq(argv[i], "-extra")) {
414  config.extrasamples = true;
415  Verb_Printf(VERB_LESS, "extrasamples = true\n");
416  } else if (Q_streq(argv[i], "-soft")) {
417  config.extrasamples = true;
418  config.soft = true;
419  Verb_Printf(VERB_LESS, "extrasamples = true\n");
420  Verb_Printf(VERB_LESS, "soft = true\n");
421  } else if (Q_streq(argv[i], "-quant")) {
422  config.lightquant = (byte)atoi(argv[i + 1]);
423  if (config.lightquant < 1 || config.lightquant > 6) {
424  config.lightquant = 4;
425  Verb_Printf(VERB_LESS, "lightquant must be between 1 and 6\n");
426  }
427  i++;
428  } else if (Q_streq(argv[i], "-scale")) {
429  config.brightness = atof(argv[i + 1]);
430  i++;
431  } else if (Q_streq(argv[i], "-saturation")) {
432  config.saturation = atof(argv[i + 1]);
433  Verb_Printf(VERB_LESS, "saturation at %f\n", config.saturation);
434  i++;
435  } else if (Q_streq(argv[i], "-contrast")) {
436  config.contrast = atof(argv[i + 1]);
437  Verb_Printf(VERB_LESS, "contrast at %f\n", config.contrast);
438  i++;
439  } else if (Q_streq(argv[i], "-surface")) {
440  config.surface_scale *= atof(argv[i + 1]);
441  Verb_Printf(VERB_LESS, "surface light scaling at %f\n", config.surface_scale);
442  i++;
443  } else if (Q_streq(argv[i], "-entity")) {
444  config.entity_scale *= atof(argv[i + 1]);
445  Verb_Printf(VERB_LESS, "entity light scaling at %f\n", config.entity_scale);
446  i++;
447  } else if (Q_streq(argv[i], "-nolighting")) {
448  if (argc > i + 1) {
449  if (Q_streq(argv[i + 1], "day")) {
450  Verb_Printf(VERB_LESS, "nolighting = day\n");
451  config.nolighting = LIGHTING_NIGHT_ONLY;
452  i++;
453  } else if (Q_streq(argv[i + 1], "night")) {
454  Verb_Printf(VERB_LESS, "nolighting = night\n");
455  config.nolighting = LIGHTING_DAY_ONLY;
456  i++;
457  } else {
458  Verb_Printf(VERB_LESS, "nolighting = none\n");
459  config.nolighting = LIGHTING_NONE;
460  }
461  } else {
462  Sys_Error("invalid parameter count");
463  }
464  } else if (Q_streq(argv[i], "-V") || Q_streq(argv[i], "--version")) {
465  Verb_Printf(VERB_LESS, "version:" VERSION " revision:" REVISION "\n");
466  exit(0);
467  } else if (i < (argc - 1)) {
468  /* Last param is the map path, every other param should have been caught by now. */
469  Verb_Printf(VERB_LESS, "*** parameter not understood: %s try --help for more info\n", argv[i]);
470  }
471  }
472 
473  if (config.fixMap && config.performMapCheck) {
474  Sys_Error("do not specify both -fix and -check");
475  }
476 
477  /* if any check or fix option is active then skip footsteps and materials */
478  if (config.performMapCheck || config.fixMap) {
479  config.generateFootstepFile = false;
480  config.generateMaterialFile = false;
481  }
482 }
483 
487 static void U2M_SetDefaultConfigValues (void)
488 {
489  config.verbosity = VERB_NORMAL;
490 
491  config.subdivideSize = 1024.0f; /* bsp subdiv */
492  config.block_xl = -8;
493  config.block_xh = 7;
494  config.block_yl = -8;
495  config.block_yh = 7;
496  config.microvolume = 1.0f;
497  config.mapMicrovol = 1.0f; /* this value is up for debate blondandy */
498 
499  /* lightmap night values */
500  VectorSet(config.sun_ambient_color[LIGHTMAP_NIGHT], 0.16, 0.16, 0.17);
501  config.sun_intensity[LIGHTMAP_NIGHT] = 15;
502  Vector2Set(config.sun_angles[LIGHTMAP_NIGHT], -80, 220);
503  VectorSet(config.sun_color[LIGHTMAP_NIGHT], 0.25, 0.25, 0.35);
504  ColorNormalize(config.sun_color[LIGHTMAP_NIGHT], config.sun_color[LIGHTMAP_NIGHT]);
505  AngleVectors(config.sun_angles[LIGHTMAP_NIGHT], config.sun_normal[LIGHTMAP_NIGHT], nullptr, nullptr);
506 
507  /* lightmap day values */
508  VectorSet(config.sun_ambient_color[LIGHTMAP_DAY], 0.26, 0.26, 0.26);
509  config.sun_intensity[LIGHTMAP_DAY] = 280;
510  Vector2Set(config.sun_angles[LIGHTMAP_DAY], -75, 100);
511  VectorSet(config.sun_color[LIGHTMAP_DAY], 0.90, 0.75, 0.65);
512  ColorNormalize(config.sun_color[LIGHTMAP_DAY], config.sun_color[LIGHTMAP_DAY]);
513  AngleVectors(config.sun_angles[LIGHTMAP_DAY], config.sun_normal[LIGHTMAP_DAY], nullptr, nullptr);
514 
515  config.saturation = 1.0f;
516  config.contrast = 1.0f;
517  config.brightness = 1.0;
518  config.lightquant = 4;
519  config.surface_scale = 0.4f;
520  config.entity_scale = 1.0f;
521 
522  config.generateFootstepFile = true;
523 
524  config.generateTraceFile = false;
525  config.generateDebugTrace = false;
526 }
527 
532 void PrintMapName (void)
533 {
534  const char* mode = nullptr;
535 
536  if (config.performMapCheck) {
537  mode = "[check]";
538  } else if (config.fixMap) {
539  mode = "[fix]";
540  } else {
541  mode = "[compile]";
542  }
543  Com_Printf("%s %s\n", mode, mapFilename);
544 }
545 
546 
547 int main (int argc, char** argv)
548 {
549  char normMapFile[MAX_OSPATH];
550  char bspFilename[MAX_OSPATH];
551  double begin, start, end;
552  long size = 0;
553 
554  OBJZERO(config);
555  /* init thread state */
557 
559 
560  U2M_Parameter(argc, argv);
561 
562  Verb_Printf(VERB_NORMAL, "---- ufo2map " VERSION " ----\n");
563 
564  if (argc < 2) {
565  Usage();
566  Sys_Error("At least provide 1 argument: the map filename.");
567  }
568 
569  com_genericPool = Mem_CreatePool("ufo2map");
570  com_fileSysPool = Mem_CreatePool("ufo2map filesys");
571 
572  Swap_Init();
573  Mem_Init();
574 
575  start = time(nullptr);
576 
577  // copy the map filename
578  Q_strncpyz(normMapFile, argv[argc-1], sizeof(normMapFile));
579  FS_NormPath(normMapFile);
580  Verb_Printf(VERB_NORMAL, "path: '%s'\n", normMapFile);
581 
582  FS_InitFilesystem(false);
583  if (config.gamedir[0] != '\0') {
584  FS_AddGameDirectory(config.gamedir, true);
585  }
586  // get the filename and remove the file extension for further use
587  Com_StripExtension(normMapFile, mapFilename, sizeof(mapFilename));
588  if (config.gamedir[0] != '\0'){
589  /*
590  in situations were you design a map, you usually want to keep these files outside the main game installation;
591  so if -gamedir is used and the map-file specified starts with the gamedir, make the mapfile relative to
592  gamedir so the FS-functions will find it
593 
594  Note: we have a case issue here on windows where you can differ in case between the path in --gamedir
595  and the path to the map-file.
596  */
597  const char *p = Q_strstart(mapFilename, config.gamedir);
598  if (p != NULL) {
599  // yes, the file specified starts with the gamedir path
600  // drop it so it becomes relative to the gamedir
601  Q_strreplace(mapFilename, config.gamedir, "", mapFilename, sizeof(mapFilename));
602  // Q_strreplace(mapFilename, config.gamedir, "", mapFilenameRel, sizeof(mapFilenameRel));
603  // Q_strncpyz(mapFilename, mapFilenameRel, sizeof(mapFilename));
604  }
605  }
606  // create seperate filenames for the .map and .bsp filess
607  strncpy(baseFilename, mapFilename, sizeof(baseFilename) - 1);
608  strncpy(bspFilename, mapFilename, sizeof(bspFilename) - 1);
609  Com_DefaultExtension(mapFilename, sizeof(mapFilename), ".map");
610  Com_DefaultExtension(bspFilename, sizeof(bspFilename), ".bsp");
611 
612  if (config.info) {
613  LoadBSPFile(bspFilename);
615  Mem_Shutdown();
616  return 0;
617  }
618 
619  Verb_Printf(VERB_NORMAL, "...map: '%s'\n", mapFilename);
620  if (!(config.performMapCheck || config.fixMap))
621  Verb_Printf(VERB_NORMAL, "...bsp: '%s'\n", bspFilename);
622 
623  if (config.verbosity == VERB_MAPNAME && !(config.performMapCheck || config.fixMap))
624  PrintMapName();
625 
626  /* if onlyents just grab the entities and resave */
627  if (config.onlyents) {
628  LoadBSPFile(bspFilename);
629  num_entities = 0; /* use the map source entities */
630 
632  SetModelNumbers();
633 
634  UnparseEntities();
635 
636  size = WriteBSPFile(bspFilename);
637  } else if (config.exportLightmaps) {
638  LoadBSPFile(bspFilename);
639  ExportLightmaps(bspFilename);
640  } else if (config.performMapCheck || config.fixMap) {
642  /* level flags must be fixed before mixed face contents, or they swamp the
643  * console with output, as levelflags are contentflags */
644  if (config.chkLevelFlags || config.chkBrushes || config.chkAll)
645  CheckLevelFlags();
646  if (config.chkFillLevelFlags || config.chkBrushes || config.chkAll)
648  /* this must be before mfc check, as otherwise mfc warnings are given
649  * which are auto-fixed based on textures */
650  if (config.chkTextures || config.chkBrushes || config.chkAll)
652  /* mixed face contents check may remove contentflags. this should be done
653  * before tex based on flags check, as tex may replace tex on the basis
654  * of contentflags.*/
655  if (config.chkMixedFaceContents || config.chkBrushes || config.chkAll)
657  if (config.chkTextures || config.chkBrushes || config.chkAll)
659  if (config.chkMMicro || config.chkBrushes || config.chkAll)
660  CheckMapMicro();
661  if (config.chkContained || config.chkBrushes || config.chkAll)
663  if (config.chkBrushes || config.chkAll)
664  CheckBrushes();
665  if (config.chkNodraws || config.chkAll)
666  CheckNodraws();
667  if (config.chkZFight || config.chkAll || config.chkBrushes)
668  CheckZFighting();
669  if (config.chkEntities || config.chkAll)
670  CheckEntities();
671  /* not included in bru or all by design */
672  if (config.chkIntersection)
674 
675  if (config.stats)
676  Check_Stats();
677 
678  if (config.fixMap) {
679  /* update dentdata */
680  UnparseEntities();
682  }
683 
684  /* the check stuff includes entitiesdef.h, which does not use mem.h.
685  * this manual free is required */
686  Check_Free();
687 
688  Mem_Shutdown();
689 
690  return 0;
691  } else if (config.generateMaterialFile) {
692  /* start from scratch */
694  Mem_Shutdown();
695  return 0;
696  } else {
697  /* start from scratch */
699 
700  CheckNodraws();
701  Check_Free();
702 
703  SetModelNumbers();
704 
705  ProcessModels(bspFilename);
706  }
707 
708  end = time(nullptr);
709  Verb_Printf(VERB_LESS, "%5.0f seconds elapsed\n", end - start);
710  begin = start;
711 
712  if (!config.exportLightmaps && !config.onlyents && config.nolighting != LIGHTING_NONE) {
713  Verb_Printf(VERB_LESS, "----- Lighting ----\n");
714 
716 
717  if (config.nolighting != LIGHTING_DAY_ONLY) {
718  /* compile night version */
719  start = time(nullptr);
720  LightWorld();
721  end = time(nullptr);
722  Verb_Printf(VERB_LESS, "%5.0f seconds elapsed\n", end - start);
723  }
724 
725  if (config.nolighting != LIGHTING_NIGHT_ONLY) {
726  /* compile day version */
727  config.compile_for_day = 1;
728  start = time(nullptr);
729  LightWorld();
730  end = time(nullptr);
731  Verb_Printf(VERB_LESS, "%5.0f seconds elapsed\n", end - start);
732  }
733 
734  Verb_Printf(VERB_LESS, "writing %s\n", bspFilename);
735  size = WriteBSPFile(bspFilename);
736  } else if (!config.exportLightmaps) {
737  /* build per-vertex normals for phong shading */
739  size = WriteBSPFile(bspFilename);
740  end = time(nullptr);
741  }
742 
743  Verb_Printf(VERB_LESS, "sum: %5.0f seconds elapsed - %.1g MB (%li bytes)\n\n", end - begin, (float)size / (1024.0f * 1024.0f), size);
744 
745  Mem_Shutdown();
746 
747  return 0;
748 }
void CheckZFighting(void)
check all brushes for overlapping shared faces
Definition: check.cpp:843
void BuildVertexNormals(void)
Calculate per-vertex (instead of per-plane) normal vectors. This is done by finding all of the faces ...
Definition: lightmap.cpp:673
Performs check on a loaded mapfile, and makes changes that can be saved back to the source map...
static void U2M_Parameter(int argc, char **argv)
Check for bsping, lighting and checking/fixing command line parameters.
Definition: ufo2map.cpp:216
Performs check on a loaded mapfile, and makes changes that can be saved back to the source map...
void PrintBSPFileSizes(void)
Dumps info about current file.
Definition: bspfile.cpp:364
static void U2M_SetDefaultConfigValues(void)
Set default values.
Definition: ufo2map.cpp:487
void FS_AddGameDirectory(const char *dir, bool write)
Adds the directory to the head of the search path.
Definition: files.cpp:495
#define LIGHTMAP_DAY
Definition: defines.h:364
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition: shared.cpp:535
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
#define VectorSet(v, x, y, z)
Definition: vector.h:59
memPool_t * com_genericPool
Definition: ufo2map.cpp:52
void LoadMapFile(const char *filename)
Definition: map.cpp:1197
void Mem_Shutdown(void)
Definition: mem.cpp:603
void ProcessModels(const char *filename)
Definition: bsp.cpp:106
vec_t ColorNormalize(const vec3_t in, vec3_t out)
Definition: mathlib.cpp:190
void CheckNodraws(void)
check for faces which can safely be set to SURF_NODRAW because they are pressed against the faces of ...
Definition: check.cpp:984
static char mapFilename[MAX_OSPATH]
Definition: ufo2map.cpp:50
void Swap_Init(void)
Definition: byte.cpp:31
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
void CheckMixedFaceContents(void)
contentflags should be the same on each face of a brush. print warnings if they are not...
Definition: check.cpp:1647
static const usagePair_t usageArray[]
Definition: ufo2map.cpp:62
static void Usage(void)
print usage information.
Definition: ufo2map.cpp:147
#define MAX_OSPATH
Definition: filesys.h:44
void Check_BrushIntersection(void)
reports intersection between optimisable map brushes
Definition: check.cpp:589
char baseFilename[MAX_OSPATH]
Definition: ufo2map.cpp:55
verbosityLevel_t
verbosity levels for use in calls to Verb_Printf and on the command line -v ...
Definition: shared.h:40
void CheckFillLevelFlags(void)
ensures set levelflags are in one contiguous block
Definition: check.cpp:1364
void CheckMapMicro(void)
report brushes from the map below 1 unit^3
Definition: check.cpp:1293
#define LIGHTMAP_NIGHT
Definition: defines.h:363
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Create the rotation matrix in order to rotate something.
Definition: mathlib.cpp:631
void FS_NormPath(char *path)
Convert operating systems path separators to ufo virtual filesystem separators (/) ...
Definition: files.cpp:83
void SetModelNumbers(void)
Set the model numbers for SOLID_BSP or SOLID_TRIGGER entities like func_door or func_breakable.
Definition: writebsp.cpp:217
GLsizei size
Definition: r_gl.h:152
#define OBJZERO(obj)
Definition: shared.h:178
#define LIGHTING_NONE
Definition: ufo2map.cpp:30
void CheckTexturesBasedOnFlags(void)
check that sides have textures and that where content/surface flags are set the texture is correct...
Definition: check.cpp:1555
void LightWorld(void)
Build the lightmap out of light entities and surface lights (patches)
Definition: lighting.cpp:34
#define Vector2Set(v, x, y)
Definition: vector.h:61
dMapTile_t * LoadBSPFile(const char *filename)
Definition: bspfile.cpp:231
void Com_Printf(const char *format,...)
Definition: ufo2map.cpp:170
void WriteMapFile(const char *filename)
Definition: map.cpp:1055
void CalcTextureReflectivity(void)
Calculates the texture color that is used for light emitting surfaces.
Definition: patches.cpp:41
threadstate_t threadstate
Definition: threads.cpp:32
void FS_InitFilesystem(bool writeToHomeDir)
Definition: files.cpp:888
#define Mem_CreatePool(name)
Definition: mem.h:32
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
#define LIGHTING_NIGHT_ONLY
Definition: ufo2map.cpp:32
void CheckLevelFlags(void)
sets all levelflags, if none are set.
Definition: check.cpp:1385
memPool_t * com_fileSysPool
Definition: ufo2map.cpp:53
void PrintMapName(void)
print name in concise form for lower verbosity levels. verbosity check done before calling this funct...
Definition: ufo2map.cpp:532
#define REVISION
Definition: ufo2map.cpp:27
int main(int argc, char **argv)
Definition: ufo2map.cpp:547
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
const char * UnparseEntities(void)
Generates the curTile->entdata string from all the entities.
Definition: bspfile.cpp:515
void CheckBrushes(void)
Definition: check.cpp:1708
const char * flags
Definition: ufo2map.cpp:58
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition: shared.cpp:297
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
void Mem_Init(void)
Definition: mem.cpp:588
void Check_Free(void)
free the mapbrush_t::nearBrushes, compositeSides and entitiesdef.h stuff.
Definition: checklib.cpp:153
#define LIGHTING_DAY_ONLY
Definition: ufo2map.cpp:31
bool AbortPrint(const verbosityLevel_t msgVerbLevel)
return nonzero if printing should be aborted based on the command line verbosity level and the import...
Definition: ufo2map.cpp:189
const char int mode
Definition: ioapi.h:41
void Check_Stats(void)
print map stats on -stats
long WriteBSPFile(const char *filename)
Swaps the bsp file in place, so it should not be referenced again.
Definition: bspfile.cpp:316
void CheckEntities(void)
Perform an entity check.
bool Q_strreplace(const char *source, const char *pattern, const char *replace, char *dest, size_t destsize)
Replaces the first occurence of the given pattern in the source string with the given replace string...
Definition: shared.cpp:596
void Verb_Printf(const verbosityLevel_t msgVerbLevel, const char *format,...)
decides wether to proceed with output based on verbosity level
Definition: ufo2map.cpp:198
mapConfig_t config
Definition: ufo2map.cpp:49
#define VERSION
Definition: ufo2map.cpp:26
#define Q_streq(a, b)
Definition: shared.h:136
struct usagePair_s usagePair_t
void Check_ContainedBrushes(void)
find duplicated brushes and brushes contained inside brushes
Definition: check.cpp:912
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
int num_entities
Definition: bspfile.cpp:394
void CheckFlagsBasedOnTextures(void)
sets content flags based on textures
Definition: check.cpp:1532
const char * desc
Definition: ufo2map.cpp:59
void format(__printf__, 1, 2)))
void ExportLightmaps(const char *bspFileName)
Export the day and night lightmap and direction data for the given map.
Definition: lightmap.cpp:963
void struct mapConfig_s mapConfig_t