UFO: Alien Invasion
Loading...
Searching...
No Matches
ufo2map.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 1997-2001 Id Software, Inc.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, 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
51
54
56
57typedef struct usagePair_s {
58 const char* flags;
59 const char* desc;
61
62static 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
147static 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
170void 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
189bool AbortPrint (const verbosityLevel_t msgVerbLevel)
190{
191 return (msgVerbLevel > config.verbosity);
192}
193
198void 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
216static 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
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);
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
532void 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
547int 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
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);
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
633
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)
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)
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)
669 if (config.chkEntities || config.chkAll)
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 */
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
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 WriteMapFile(const char *filename)
Definition map.cpp:1055
void LoadMapFile(const char *filename)
Definition map.cpp:1197
void SetModelNumbers(void)
Set the model numbers for SOLID_BSP or SOLID_TRIGGER entities like func_door or func_breakable.
Definition writebsp.cpp:217
const char * UnparseEntities(void)
Generates the curTile->entdata string from all the entities.
Definition bspfile.cpp:515
int num_entities
Definition bspfile.cpp:394
void PrintBSPFileSizes(void)
Dumps info about current file.
Definition bspfile.cpp:364
long WriteBSPFile(const char *filename)
Swaps the bsp file in place, so it should not be referenced again.
Definition bspfile.cpp:316
dMapTile_t * LoadBSPFile(const char *filename)
Definition bspfile.cpp:231
void Swap_Init(void)
Definition byte.cpp:31
void Check_ContainedBrushes(void)
find duplicated brushes and brushes contained inside brushes
Definition check.cpp:912
void CheckFlagsBasedOnTextures(void)
sets content flags based on textures
Definition check.cpp:1532
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 CheckMixedFaceContents(void)
contentflags should be the same on each face of a brush. print warnings if they are not....
Definition check.cpp:1647
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
void Check_BrushIntersection(void)
reports intersection between optimisable map brushes
Definition check.cpp:589
void CheckLevelFlags(void)
sets all levelflags, if none are set.
Definition check.cpp:1385
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
void CheckZFighting(void)
check all brushes for overlapping shared faces
Definition check.cpp:843
void CheckBrushes(void)
Definition check.cpp:1708
Performs check on a loaded mapfile, and makes changes that can be saved back to the source map.
void Check_Stats(void)
print map stats on -stats
void CheckEntities(void)
Perform an entity check.
void Check_Free(void)
free the mapbrush_t::nearBrushes, compositeSides and entitiesdef.h stuff.
Definition checklib.cpp:153
Performs check on a loaded mapfile, and makes changes that can be saved back to the source map.
memPool_t * com_genericPool
Definition common.cpp:72
memPool_t * com_fileSysPool
Definition common.cpp:71
#define LIGHTMAP_NIGHT
Definition defines.h:363
#define LIGHTMAP_DAY
Definition defines.h:364
void FS_InitFilesystem(bool writeToHomeDir)
Definition files.cpp:890
void FS_NormPath(char *path)
Convert operating systems path separators to ufo virtual filesystem separators (/).
Definition files.cpp:83
void FS_AddGameDirectory(const char *dir, bool write)
Adds the directory to the head of the search path.
Definition files.cpp:495
#define MAX_OSPATH
Definition filesys.h:44
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
voidpf void uLong size
Definition ioapi.h:42
const char int mode
Definition ioapi.h:41
void LightWorld(void)
Build the lightmap out of light entities and surface lights (patches).
Definition lighting.cpp:34
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
void CalcTextureReflectivity(void)
Calculates the texture color that is used for light emitting surfaces.
Definition patches.cpp:41
void ExportLightmaps(const char *bspFileName)
Export the day and night lightmap and direction data for the given map.
Definition lightmap.cpp:963
vec_t ColorNormalize(const vec3_t in, vec3_t out)
Definition mathlib.cpp:190
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 Mem_Init(void)
Definition mem.cpp:506
void Mem_Shutdown(void)
Definition mem.cpp:518
#define Mem_CreatePool(name)
Definition mem.h:32
void format(__printf__, 1, 2)))
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLint i
Definition r_gl.h:113
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition shared.cpp:297
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition shared.cpp:535
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
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
const char * flags
Definition ufo2map.cpp:58
const char * desc
Definition ufo2map.cpp:59
static config_t config
Definition test_all.cpp:43
void ProcessModels(const char *filename)
Definition bsp.cpp:106
verbosityLevel_t
verbosity levels for use in calls to Verb_Printf and on the command line -v <int>
Definition shared.h:40
@ VERB_NORMAL
Definition shared.h:45
@ VERB_MAPNAME
Definition shared.h:43
@ VERB_LESS
Definition shared.h:44
char baseFilename[MAX_OSPATH]
Definition ufo2map.cpp:55
threadstate_t threadstate
Definition threads.cpp:32
static char mapFilename[MAX_OSPATH]
Definition ufo2map.cpp:50
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
#define VERSION
Definition ufo2map.cpp:26
static void U2M_SetDefaultConfigValues(void)
Set default values.
Definition ufo2map.cpp:487
#define LIGHTING_DAY_ONLY
Definition ufo2map.cpp:31
int main(int argc, char **argv)
Definition ufo2map.cpp:547
static const usagePair_t usageArray[]
Definition ufo2map.cpp:62
#define LIGHTING_NIGHT_ONLY
Definition ufo2map.cpp:32
void Verb_Printf(const verbosityLevel_t msgVerbLevel, const char *format,...)
decides wether to proceed with output based on verbosity level
Definition ufo2map.cpp:198
void PrintMapName(void)
print name in concise form for lower verbosity levels. verbosity check done before calling this funct...
Definition ufo2map.cpp:532
void Com_Printf(const char *format,...)
Definition ufo2map.cpp:170
static void Usage(void)
print usage information.
Definition ufo2map.cpp:147
#define REVISION
Definition ufo2map.cpp:27
#define LIGHTING_NONE
Definition ufo2map.cpp:30
static void U2M_Parameter(int argc, char **argv)
Check for bsping, lighting and checking/fixing command line parameters.
Definition ufo2map.cpp:216
uint8_t byte
Definition ufotypes.h:34
#define Vector2Set(v, x, y)
Definition vector.h:61
#define VectorSet(v, x, y, z)
Definition vector.h:59