1 /*
2
3 R A D I O S I T Y -aka- R A D
4
5 Code based on original code from Valve Software,
6 Modified by Sean "Zoner" Cavanaugh (seanc@gearboxsoftware.com) with permission.
7 Modified by Tony "Merl" Moore (merlinis@bigpond.net.au) [AJM]
8
9 */
10
11 #ifdef SYSTEM_WIN32
12 #define WIN32_LEAN_AND_MEAN
13 #include <windows.h>
14 #endif
15
16 #include <vector>
17 #include <string>
18
19 #include "qrad.h"
20 #include "cmdlib.h"
21
22 /*
23 * NOTES
24 * -----
25 * every surface must be divided into at least two g_patches each axis
26 */
27
28 typedef enum
29 {
30 eMethodVismatrix,
31 eMethodSparseVismatrix,
32 eMethodNoVismatrix
33 }
34 eVisMethods;
35
36 eVisMethods g_method = eMethodVismatrix;
37
38 vec_t g_fade = DEFAULT_FADE;
39 int g_falloff = DEFAULT_FALLOFF;
40
41 patch_t* g_face_patches[MAX_MAP_FACES];
42 entity_t* g_face_entity[MAX_MAP_FACES];
43 eModelLightmodes g_face_lightmode[MAX_MAP_FACES];
44 patch_t g_patches[MAX_PATCHES];
45 unsigned g_num_patches;
46
47 bool g_warned_direct = false;
48
49 #ifdef ZHLT_TEXLIGHT
50 static vec3_t emitlight[MAX_PATCHES][MAXLIGHTMAPS]; //LRC
51 static vec3_t addlight[MAX_PATCHES][MAXLIGHTMAPS]; //LRC
52 #else
53 static vec3_t emitlight[MAX_PATCHES];
54 static vec3_t addlight[MAX_PATCHES];
55 #endif
56
57 vec3_t g_face_offset[MAX_MAP_FACES]; // for rotating bmodels
58
59 vec_t g_direct_scale = DEFAULT_DLIGHT_SCALE;
60
61 unsigned g_numbounce = DEFAULT_BOUNCE; // 3; /* Originally this was 8 */
62 bool g_bounce_dynamic = DEFAULT_BOUNCE_DYNAMIC; //false
63
64 static bool g_dumppatches = DEFAULT_DUMPPATCHES;
65
66 vec3_t g_ambient = { DEFAULT_AMBIENT_RED, DEFAULT_AMBIENT_GREEN, DEFAULT_AMBIENT_BLUE };
67 float g_maxlight = DEFAULT_MAXLIGHT; // 196 /* Originally this was 196 */
68
69 float g_lightscale = DEFAULT_LIGHTSCALE;
70 float g_dlight_threshold = DEFAULT_DLIGHT_THRESHOLD; // was DIRECT_LIGHT constant
71
72 char g_source[_MAX_PATH] = "";
73
74 char g_vismatfile[_MAX_PATH] = "";
75 bool g_incremental = DEFAULT_INCREMENTAL;
76 #ifndef HLRAD_WHOME
77 float g_qgamma = DEFAULT_GAMMA;
78 #endif
79 float g_indirect_sun = DEFAULT_INDIRECT_SUN;
80 bool g_extra = DEFAULT_EXTRA;
81 bool g_texscale = DEFAULT_TEXSCALE;
82
83 float g_smoothing_threshold;
84 float g_smoothing_value = DEFAULT_SMOOTHING_VALUE;
85
86 bool g_circus = DEFAULT_CIRCUS;
87 bool g_allow_opaques = DEFAULT_ALLOW_OPAQUES;
88
89 // --------------------------------------------------------------------------
90 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
91 #ifdef HLRAD_WHOME
92 vec3_t g_colour_qgamma = { DEFAULT_COLOUR_GAMMA_RED, DEFAULT_COLOUR_GAMMA_GREEN, DEFAULT_COLOUR_GAMMA_BLUE };
93 vec3_t g_colour_lightscale = { DEFAULT_COLOUR_LIGHTSCALE_RED, DEFAULT_COLOUR_LIGHTSCALE_GREEN, DEFAULT_COLOUR_LIGHTSCALE_BLUE };
94 vec3_t g_colour_jitter_hack = { DEFAULT_COLOUR_JITTER_HACK_RED, DEFAULT_COLOUR_JITTER_HACK_GREEN, DEFAULT_COLOUR_JITTER_HACK_BLUE };
95 vec3_t g_jitter_hack = { DEFAULT_JITTER_HACK_RED, DEFAULT_JITTER_HACK_GREEN, DEFAULT_JITTER_HACK_BLUE };
96 bool g_diffuse_hack = DEFAULT_DIFFUSE_HACK;
97 bool g_spotlight_hack = DEFAULT_SPOTLIGHT_HACK;
98 vec3_t g_softlight_hack = { DEFAULT_SOFTLIGHT_HACK_RED, DEFAULT_SOFTLIGHT_HACK_GREEN, DEFAULT_SOFTLIGHT_HACK_BLUE };
99 float g_softlight_hack_distance = DEFAULT_SOFTLIGHT_HACK_DISTANCE;
100 #endif
101 // --------------------------------------------------------------------------
102
103 #ifdef HLRAD_HULLU
104 bool g_customshadow_with_bouncelight = DEFAULT_CUSTOMSHADOW_WITH_BOUNCELIGHT;
105 bool g_rgb_transfers = DEFAULT_RGB_TRANSFERS;
106 #endif
107
108 // Cosine of smoothing angle(in radians)
109 float g_coring = DEFAULT_CORING; // Light threshold to force to blackness(minimizes lightmaps)
110 bool g_chart = DEFAULT_CHART;
111 bool g_estimate = DEFAULT_ESTIMATE;
112 bool g_info = DEFAULT_INFO;
113
114 #ifdef ZHLT_PROGRESSFILE // AJM
115 char* g_progressfile = DEFAULT_PROGRESSFILE; // "-progressfile path"
116 #endif
117
118 // Patch creation and subdivision criteria
119 bool g_subdivide = DEFAULT_SUBDIVIDE;
120 vec_t g_chop = DEFAULT_CHOP;
121 vec_t g_texchop = DEFAULT_TEXCHOP;
122
123 // Opaque faces
124 opaqueList_t* g_opaque_face_list = NULL;
125 unsigned g_opaque_face_count = 0;
126 unsigned g_max_opaque_face_count = 0; // Current array maximum (used for reallocs)
127
128 // Misc
129 int leafparents[MAX_MAP_LEAFS];
130 int nodeparents[MAX_MAP_NODES];
131
132 #ifdef ZHLT_INFO_COMPILE_PARAMETERS
133 // =====================================================================================
134 // GetParamsFromEnt
135 // this function is called from parseentity when it encounters the
136 // info_compile_parameters entity. each tool should have its own version of this
137 // to handle its own specific settings.
138 // =====================================================================================
GetParamsFromEnt(entity_t * mapent)139 void GetParamsFromEnt(entity_t* mapent)
140 {
141 int iTmp;
142 float flTmp;
143 char szTmp[256];
144 const char* pszTmp;
145
146 Log("\nCompile Settings detected from info_compile_parameters entity\n");
147
148 // lightdata(string) : "Lighting Data Memory" : "8192"
149 iTmp = IntForKey(mapent, "lightdata") * 1024;
150 if (iTmp > g_max_map_miptex)
151 {
152 g_max_map_lightdata = iTmp;
153 }
154 sprintf_s(szTmp, "%i", g_max_map_lightdata);
155 Log("%30s [ %-9s ]\n", "Lighting Data Memory", szTmp);
156
157 // verbose(choices) : "Verbose compile messages" : 0 = [ 0 : "Off" 1 : "On" ]
158 iTmp = IntForKey(mapent, "verbose");
159 if (iTmp == 1)
160 {
161 g_verbose = true;
162 }
163 else if (iTmp == 0)
164 {
165 g_verbose = false;
166 }
167 Log("%30s [ %-9s ]\n", "Compile Option", "setting");
168 Log("%30s [ %-9s ]\n", "Verbose Compile Messages", g_verbose ? "on" : "off");
169
170 // estimate(choices) :"Estimate Compile Times?" : 0 = [ 0: "Yes" 1: "No" ]
171 if (IntForKey(mapent, "estimate"))
172 {
173 g_estimate = true;
174 }
175 else
176 {
177 g_estimate = false;
178 }
179 Log("%30s [ %-9s ]\n", "Estimate Compile Times", g_estimate ? "on" : "off");
180
181 // priority(choices) : "Priority Level" : 0 = [ 0 : "Normal" 1 : "High" -1 : "Low" ]
182 if (!strcmp(ValueForKey(mapent, "priority"), "1"))
183 {
184 g_threadpriority = eThreadPriorityHigh;
185 Log("%30s [ %-9s ]\n", "Thread Priority", "high");
186 }
187 else if (!strcmp(ValueForKey(mapent, "priority"), "-1"))
188 {
189 g_threadpriority = eThreadPriorityLow;
190 Log("%30s [ %-9s ]\n", "Thread Priority", "low");
191 }
192
193 // bounce(integer) : "Number of radiosity bounces" : 0
194 iTmp = IntForKey(mapent, "bounce");
195 if (iTmp)
196 {
197 g_numbounce = abs(iTmp);
198 Log("%30s [ %-9s ]\n", "Number of radiosity bounces", ValueForKey(mapent, "bounce"));
199 }
200
201 if(IntForKey(mapent,"nodynbounce"))
202 {
203 g_bounce_dynamic = false;
204 }
205 else
206 {
207 g_bounce_dynamic = true;
208 }
209 Log("%30s [ %-9s ]\n", "Bounce dynamic lights", g_bounce_dynamic ? "on" : "off");
210
211
212 #ifdef HLRAD_HULLU
213 iTmp = IntForKey(mapent, "customshadowwithbounce");
214 if (iTmp)
215 {
216 g_customshadow_with_bouncelight = true;
217 Log("%30s [ %-9s ]\n", "Custom Shadow with Bounce Light", ValueForKey(mapent, "customshadowwithbounce"));
218 }
219 iTmp = IntForKey(mapent, "rgbtransfers");
220 if (iTmp)
221 {
222 g_rgb_transfers = true;
223 Log("%30s [ %-9s ]\n", "RGB Transfers", ValueForKey(mapent, "rgbtransfers"));
224 }
225 #endif
226
227 // ambient(string) : "Ambient world light (0.0 to 1.0, R G B)" : "0 0 0"
228 //vec3_t g_ambient = { DEFAULT_AMBIENT_RED, DEFAULT_AMBIENT_GREEN, DEFAULT_AMBIENT_BLUE };
229 pszTmp = ValueForKey(mapent, "ambient");
230 if (pszTmp)
231 {
232 float red = 0, green = 0, blue = 0;
233 if (sscanf_s(pszTmp, "%f %f %f", &red, &green, &blue))
234 {
235 if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1)
236 {
237 Error("info_compile_parameters: Ambient World Light (ambient) all 3 values must be within the range of 0.0 to 1.0\n"
238 "Parsed values:\n"
239 " red [ %1.3f ] %s\n"
240 " green [ %1.3f ] %s\n"
241 " blue [ %1.3f ] %s\n"
242 , red, (red < 0 || red > 1) ? "OUT OF RANGE" : ""
243 , green, (green < 0 || green > 1) ? "OUT OF RANGE" : ""
244 , blue, (blue < 0 || blue > 1) ? "OUT OF RANGE" : "" );
245 }
246
247 if (red == 0 && green == 0 && blue == 0)
248 {} // dont bother setting null values
249 else
250 {
251 g_ambient[0] = red * 128;
252 g_ambient[1] = green * 128;
253 g_ambient[2] = blue * 128;
254 Log("%30s [ %1.3f %1.3f %1.3f ]\n", "Ambient world light (R G B)", red, green, blue);
255 }
256 }
257 else
258 {
259 Error("info_compile_parameters: Ambient World Light (ambient) has unrecognised value\n"
260 "This keyvalue accepts 3 numeric values from 0.000 to 1.000, use \"0 0 0\" if in doubt");
261 }
262 }
263
264 // smooth(integer) : "Smoothing threshold (in degrees)" : 0
265 flTmp = FloatForKey(mapent, "smooth");
266 if (flTmp)
267 {
268 g_smoothing_threshold = flTmp;
269 Log("%30s [ %-9s ]\n", "Smoothing threshold", ValueForKey(mapent, "smooth"));
270 }
271
272 // dscale(integer) : "Direct Lighting Scale" : 1
273 flTmp = FloatForKey(mapent, "dscale");
274 if (flTmp)
275 {
276 g_direct_scale = flTmp;
277 Log("%30s [ %-9s ]\n", "Direct Lighting Scale", ValueForKey(mapent, "dscale"));
278 }
279
280 // chop(integer) : "Chop Size" : 64
281 iTmp = IntForKey(mapent, "chop");
282 if (iTmp)
283 {
284 g_chop = iTmp;
285 Log("%30s [ %-9s ]\n", "Chop Size", ValueForKey(mapent, "chop"));
286 }
287
288 // texchop(integer) : "Texture Light Chop Size" : 32
289 flTmp = FloatForKey(mapent, "texchop");
290 if (flTmp)
291 {
292 g_texchop = flTmp;
293 Log("%30s [ %-9s ]\n", "Texture Light Chop Size", ValueForKey(mapent, "texchop"));
294 }
295
296 /*
297 hlrad(choices) : "HLRAD" : 0 =
298 [
299 0 : "Off"
300 1 : "Normal"
301 2 : "Extra"
302 ]
303 */
304 iTmp = IntForKey(mapent, "hlrad");
305 if (iTmp == 0)
306 {
307 Fatal(assume_TOOL_CANCEL,
308 "%s flag was not checked in info_compile_parameters entity, execution of %s cancelled", g_Program, g_Program);
309 CheckFatal();
310 }
311 else if (iTmp == 1)
312 {
313 g_extra = false;
314 }
315 else if (iTmp == 2)
316 {
317 g_extra = true;
318 }
319 Log("%30s [ %-9s ]\n", "Extra RAD", g_extra ? "on" : "off");
320
321 /*
322 sparse(choices) : "Vismatrix Method" : 2 =
323 [
324 0 : "No Vismatrix"
325 1 : "Sparse Vismatrix"
326 2 : "Normal"
327 ]
328 */
329 iTmp = IntForKey(mapent, "sparse");
330 if (iTmp == 1)
331 {
332 g_method = eMethodSparseVismatrix;
333 }
334 else if (iTmp == 0)
335 {
336 g_method = eMethodNoVismatrix;
337 }
338 else if (iTmp == 2)
339 {
340 g_method = eMethodVismatrix;
341 }
342 Log("%30s [ %-9s ]\n", "Sparse Vismatrix", g_method == eMethodSparseVismatrix ? "on" : "off");
343 Log("%30s [ %-9s ]\n", "NoVismatrix", g_method == eMethodNoVismatrix ? "on" : "off");
344
345 /*
346 circus(choices) : "Circus RAD lighting" : 0 =
347 [
348 0 : "Off"
349 1 : "On"
350 ]
351 */
352 iTmp = IntForKey(mapent, "circus");
353 if (iTmp == 0)
354 {
355 g_circus = false;
356 }
357 else if (iTmp == 1)
358 {
359 g_circus = true;
360 }
361
362 Log("%30s [ %-9s ]\n", "Circus Lighting Mode", g_circus ? "on" : "off");
363
364 ////////////////////
365 Log("\n");
366 }
367 #endif
368
369 // =====================================================================================
370 // Extract File stuff (ExtractFile | ExtractFilePath | ExtractFileBase)
371 //
372 // With VS 2005 - and the 64 bit build, i had to pull 3 classes over from
373 // cmdlib.cpp even with the proper includes to get rid of the lnk2001 error
374 //
375 // amckern - amckern@yahoo.com
376 // =====================================================================================
377
378 #define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
379
ExtractFileBase(const char * const path,char * dest)380 void ExtractFileBase(const char* const path, char* dest)
381 {
382 hlassert (path != dest);
383
384 const char* src;
385
386 src = path + strlen(path) - 1;
387
388 //
389 // back up until a \ or the start
390 //
391 while (src != path && !PATHSEPARATOR(*(src - 1)))
392 src--;
393
394 while (*src && *src != '.')
395 {
396 *dest++ = *src++;
397 }
398 *dest = 0;
399 }
400
ExtractFilePath(const char * const path,char * dest)401 void ExtractFilePath(const char* const path, char* dest)
402 {
403 hlassert (path != dest);
404
405 const char* src;
406
407 src = path + strlen(path) - 1;
408
409 //
410 // back up until a \ or the start
411 //
412 while (src != path && !PATHSEPARATOR(*(src - 1)))
413 src--;
414
415 memcpy(dest, path, src - path);
416 dest[src - path] = 0;
417 }
418
ExtractFile(const char * const path,char * dest)419 void ExtractFile(const char* const path, char* dest)
420 {
421 hlassert (path != dest);
422
423 const char* src;
424
425 src = path + strlen(path) - 1;
426
427 while (src != path && !PATHSEPARATOR(*(src - 1)))
428 src--;
429
430 while (*src)
431 {
432 *dest++ = *src++;
433 }
434 *dest = 0;
435 }
436
437 // =====================================================================================
438 // MakeParents
439 // blah
440 // =====================================================================================
MakeParents(const int nodenum,const int parent)441 static void MakeParents(const int nodenum, const int parent)
442 {
443 int i;
444 int j;
445 dnode_t* node;
446
447 nodeparents[nodenum] = parent;
448 node = g_dnodes + nodenum;
449
450 for (i = 0; i < 2; i++)
451 {
452 j = node->children[i];
453 if (j < 0)
454 {
455 leafparents[-j - 1] = nodenum;
456 }
457 else
458 {
459 MakeParents(j, nodenum);
460 }
461 }
462 }
463
464 // =====================================================================================
465 //
466 // TEXTURE LIGHT VALUES
467 //
468 // =====================================================================================
469
470 // misc
471 typedef struct
472 {
473 std::string name;
474 vec3_t value;
475 const char* filename;
476 }
477 texlight_t;
478
479 static std::vector< texlight_t > s_texlights;
480 typedef std::vector< texlight_t >::iterator texlight_i;
481
482 // =====================================================================================
483 // ReadLightFile
484 // =====================================================================================
ReadLightFile(const char * const filename)485 static void ReadLightFile(const char* const filename)
486 {
487 FILE* f;
488 char scan[MAXTOKEN];
489 short argCnt;
490 unsigned int file_texlights = 0;
491
492 f = fopen(filename, "r");
493 if (!f)
494 {
495 Warning("Could not open texlight file %s", filename);
496 return;
497 }
498 else
499 {
500 Log("[Reading texlights from '%s']\n", filename);
501 }
502
503 while (fgets(scan, sizeof(scan), f))
504 {
505 char* comment;
506 char szTexlight[_MAX_PATH];
507 vec_t r, g, b, i = 1;
508
509 comment = strstr(scan, "//");
510 if (comment)
511 {
512 // Newline and Null terminate the string early if there is a c++ style single line comment
513 comment[0] = '\n';
514 comment[1] = 0;
515 }
516
517 argCnt = sscanf/*_s*/(scan, "%s %f %f %f %f", szTexlight, &r, &g, &b, &i);
518
519 if (argCnt == 2)
520 {
521 // With 1+1 args, the R,G,B values are all equal to the first value
522 g = b = r;
523 }
524 else if (argCnt == 5)
525 {
526 // With 1+4 args, the R,G,B values are "scaled" by the fourth numeric value i;
527 r *= i / 255.0;
528 g *= i / 255.0;
529 b *= i / 255.0;
530 }
531 else if (argCnt != 4)
532 {
533 if (strlen(scan) > 4)
534 {
535 Warning("ignoring bad texlight '%s' in %s", scan, filename);
536 }
537 continue;
538 }
539
540 texlight_i it;
541 for (it = s_texlights.begin(); it != s_texlights.end(); it++)
542 {
543 if (strcmp(it->name.c_str(), szTexlight) == 0)
544 {
545 if (strcmp(it->filename, filename) == 0)
546 {
547 Warning("Duplication of texlight '%s' in file '%s'!", it->name.c_str(), it->filename);
548 }
549 else if (it->value[0] != r || it->value[1] != g || it->value[2] != b)
550 {
551 Warning("Overriding '%s' from '%s' with '%s'!", it->name.c_str(), it->filename, filename);
552 }
553 else
554 {
555 Warning("Redundant '%s' def in '%s' AND '%s'!", it->name.c_str(), it->filename, filename);
556 }
557 s_texlights.erase(it);
558 break;
559 }
560 }
561
562 texlight_t texlight;
563 texlight.name = szTexlight;
564 texlight.value[0] = r;
565 texlight.value[1] = g;
566 texlight.value[2] = b;
567 texlight.filename = filename;
568 file_texlights++;
569 s_texlights.push_back(texlight);
570 }
571 Log("[%u texlights parsed from '%s']\n\n", file_texlights, filename);
572 }
573
574 // =====================================================================================
575 // LightForTexture
576 // =====================================================================================
LightForTexture(const char * const name,vec3_t result)577 static void LightForTexture(const char* const name, vec3_t result)
578 {
579 texlight_i it;
580 for (it = s_texlights.begin(); it != s_texlights.end(); it++)
581 {
582 if (!strcasecmp(name, it->name.c_str()))
583 {
584 VectorCopy(it->value, result);
585 return;
586 }
587 }
588 VectorClear(result);
589 }
590
591
592 // =====================================================================================
593 //
594 // MAKE FACES
595 //
596 // =====================================================================================
597
598 // =====================================================================================
599 // BaseLightForFace
600 // =====================================================================================
BaseLightForFace(const dface_t * const f,vec3_t light)601 static void BaseLightForFace(const dface_t* const f, vec3_t light)
602 {
603 texinfo_t* tx;
604 miptex_t* mt;
605 int ofs;
606
607 //
608 // check for light emited by texture
609 //
610 tx = &g_texinfo[f->texinfo];
611
612 ofs = ((dmiptexlump_t*)g_dtexdata)->dataofs[tx->miptex];
613 mt = (miptex_t*)((byte*) g_dtexdata + ofs);
614
615 LightForTexture(mt->name, light);
616 }
617
618 // =====================================================================================
619 // IsSpecial
620 // =====================================================================================
IsSpecial(const dface_t * const f)621 static bool IsSpecial(const dface_t* const f)
622 {
623 return g_texinfo[f->texinfo].flags & TEX_SPECIAL;
624 }
625
626 // =====================================================================================
627 // PlacePatchInside
628 // =====================================================================================
PlacePatchInside(patch_t * patch)629 static bool PlacePatchInside(patch_t* patch)
630 {
631 const dplane_t* plane;
632 const vec_t* face_offset = g_face_offset[patch->faceNumber];
633
634 plane = getPlaneFromFaceNumber(patch->faceNumber);
635
636 if (!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.01) &&
637 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.1) &&
638 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.5) &&
639 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.01) &&
640 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.1))
641 {
642 // Try offsetting it by the plane normal (1 unit away) and try again
643
644 VectorAdd(plane->normal, patch->origin, patch->origin); // Original offset-into-world method
645 if (PointInLeaf(patch->origin) == g_dleafs)
646 {
647 if (!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.01) &&
648 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.1) &&
649 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.5) &&
650 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.01) &&
651 !HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.1))
652 {
653 patch->flags = (ePatchFlags)(patch->flags | ePatchFlagOutside);
654 Developer(DEVELOPER_LEVEL_MESSAGE, "Patch @ (%4.3f %4.3f %4.3f) outside world\n",
655 patch->origin[0], patch->origin[1], patch->origin[2]);
656 return false;
657 }
658 }
659 }
660
661 return true;
662 }
663
664
665 // =====================================================================================
666 //
667 // SUBDIVIDE PATCHES
668 //
669 // =====================================================================================
670
671 // misc
672 #define MAX_SUBDIVIDE 16384
673 static Winding* windingArray[MAX_SUBDIVIDE];
674 static unsigned g_numwindings = 0;
675
676 // =====================================================================================
677 // AddWindingToArray
678 // =====================================================================================
AddWindingToArray(Winding * winding)679 static void AddWindingToArray(Winding* winding)
680 {
681 unsigned x;
682
683 Winding** wA = windingArray;
684
685 for (x = 0; x < g_numwindings; x++, wA++)
686 {
687 if (*wA == winding)
688 {
689 return;
690 }
691 }
692
693 windingArray[g_numwindings++] = winding;
694 }
695
CreateStrips_r(Winding * winding,const vec3_t plane_normal,const vec_t plane_dist,vec_t step)696 static void CreateStrips_r(Winding* winding, const vec3_t plane_normal, const vec_t plane_dist, vec_t step)
697 {
698 Winding* A;
699 Winding* B;
700 vec_t areaA;
701 vec_t areaB;
702
703 winding->Clip(plane_normal, plane_dist + step, &A, &B);
704
705 if (A && B)
706 {
707 areaA = A->getArea();
708 areaB = B->getArea();
709 if ((areaA > 1.0) && (areaB > 1.0))
710 {
711 delete winding;
712 CreateStrips_r(A, plane_normal, plane_dist + step, step);
713 CreateStrips_r(B, plane_normal, plane_dist + step, step);
714 return;
715 }
716 }
717 else
718 { // Try the other direction
719 if (A)
720 {
721 delete A;
722 }
723 if (B)
724 {
725 delete B;
726 }
727
728 winding->Clip(plane_normal, plane_dist - step, &A, &B);
729
730 if (A && B)
731 {
732 areaA = A->getArea();
733 areaB = B->getArea();
734 if ((areaA > 1.0) && (areaB > 1.0))
735 {
736 delete winding;
737 CreateStrips_r(A, plane_normal, plane_dist - step, step);
738 CreateStrips_r(B, plane_normal, plane_dist - step, step);
739 return;
740 }
741 }
742 }
743
744 // Last recursion, save it into the list
745 if (A)
746 {
747 delete A;
748 }
749 if (B)
750 {
751 delete B;
752 }
753
754 AddWindingToArray(winding);
755 hlassume(g_numwindings < MAX_SUBDIVIDE, assume_GENERIC);
756 }
757
758 // =====================================================================================
759 // CreateStrips
760 // =====================================================================================
CreateStrips(Winding * winding,const dplane_t * plane,vec_t step)761 static bool CreateStrips(Winding* winding, const dplane_t* plane, vec_t step)
762 {
763 Winding* A;
764 Winding* B;
765 vec_t areaA;
766 vec_t areaB;
767
768 winding->Clip(plane->normal, plane->dist, &A, &B);
769
770 if (A && B)
771 {
772 areaA = A->getArea();
773 areaB = B->getArea();
774 if ((areaA > 1.0) && (areaB > 1.0))
775 {
776 CreateStrips_r(A, (vec_t*)plane->normal, plane->dist, step);
777 CreateStrips_r(B, (vec_t*)plane->normal, plane->dist, step);
778 return true;
779 }
780 }
781
782 if (A)
783 {
784 delete A;
785 }
786 if (B)
787 {
788 delete B;
789 }
790
791 AddWindingToArray(winding);
792 hlassume(g_numwindings < MAX_SUBDIVIDE, assume_GENERIC);
793 return false;
794 }
795
796 // =====================================================================================
797 // cutWindingWithGrid
798 // Caller must free this returned value at some point
799 // =====================================================================================
cutWindingWithGrid(patch_t * patch,const dplane_t * const plA,const dplane_t * const plB)800 static void cutWindingWithGrid(patch_t* patch, const dplane_t* const plA, const dplane_t* const plB)
801 {
802 Winding** winding;
803 unsigned int count;
804 unsigned int x;
805
806 g_numwindings = 0;
807 if (CreateStrips(patch->winding, plA, patch->chop))
808 {
809 delete patch->winding;
810 patch->winding = NULL; // Invalidated by CreateStrips routine
811 }
812 count = g_numwindings;
813
814 for (x = 0, winding = windingArray; x < count; x++, winding++)
815 {
816 if (CreateStrips(*winding, plB, patch->chop))
817 {
818 delete *winding;
819 *winding = NULL;
820 }
821 }
822 }
823
824 // =====================================================================================
825 // getGridPlanes
826 // From patch, determine perpindicular grid planes to subdivide with (returned in planeA and planeB)
827 // assume S and T is perpindicular (they SHOULD be in worldcraft 3.3 but aren't always . . .)
828 // =====================================================================================
getGridPlanes(const patch_t * const p,dplane_t * const pl)829 static void getGridPlanes(const patch_t* const p, dplane_t* const pl)
830 {
831 const patch_t* patch = p;
832 dplane_t* planes = pl;
833 const dface_t* f = g_dfaces + patch->faceNumber;
834 texinfo_t* tx = &g_texinfo[f->texinfo];
835 dplane_t* plane = planes;
836 const dplane_t* faceplane = getPlaneFromFaceNumber(patch->faceNumber);
837 int x;
838
839 for (x = 0; x < 2; x++, plane++)
840 {
841 vec3_t a, b, c;
842 vec3_t delta1, delta2;
843
844 VectorCopy(patch->origin, a);
845 VectorAdd(patch->origin, faceplane->normal, b);
846 VectorAdd(patch->origin, tx->vecs[x], c);
847
848 VectorSubtract(b, a, delta1);
849 VectorSubtract(c, a, delta2);
850
851 CrossProduct(delta1, delta2, plane->normal);
852 VectorNormalize(plane->normal);
853 plane->dist = DotProduct(plane->normal, patch->origin);
854 }
855 }
856
857 // =====================================================================================
858 // SubdividePatch
859 // =====================================================================================
SubdividePatch(patch_t * patch)860 static void SubdividePatch(patch_t* patch)
861 {
862 dplane_t planes[2];
863 dplane_t* plA = &planes[0];
864 dplane_t* plB = &planes[1];
865 Winding** winding;
866 unsigned x;
867 patch_t* new_patch;
868
869 memset(windingArray, 0, sizeof(windingArray));
870 g_numwindings = 0;
871
872 getGridPlanes(patch, planes);
873 cutWindingWithGrid(patch, plA, plB);
874
875 x = 0;
876 patch->next = NULL;
877 winding = windingArray;
878 while (*winding == NULL)
879 {
880 winding++;
881 x++;
882 }
883 patch->winding = *winding;
884 winding++;
885 x++;
886 patch->area = patch->winding->getArea();
887 patch->winding->getCenter(patch->origin);
888 PlacePatchInside(patch);
889
890 new_patch = g_patches + g_num_patches;
891 for (; x < g_numwindings; x++, winding++)
892 {
893 if (*winding)
894 {
895 memcpy(new_patch, patch, sizeof(patch_t));
896
897 new_patch->winding = *winding;
898 new_patch->area = new_patch->winding->getArea();
899 new_patch->winding->getCenter(new_patch->origin);
900 PlacePatchInside(new_patch);
901
902 new_patch++;
903 g_num_patches++;
904 hlassume(g_num_patches < MAX_PATCHES, assume_MAX_PATCHES);
905 }
906 }
907
908 // ATTENTION: We let SortPatches relink all the ->next correctly! instead of doing it here too which is somewhat complicated
909 }
910
911 // =====================================================================================
912 // MakePatchForFace
913 static float totalarea = 0;
914 // =====================================================================================
getScale(const patch_t * const patch)915 static vec_t getScale(const patch_t* const patch)
916 {
917 dface_t* f = g_dfaces + patch->faceNumber;
918 texinfo_t* tx = &g_texinfo[f->texinfo];
919
920 if (g_texscale)
921 {
922 vec_t scale[2];
923
924 scale[0] = 0.0;
925 scale[1] = 0.0;
926
927 scale[0] += tx->vecs[0][0] * tx->vecs[0][0];
928 scale[0] += tx->vecs[0][1] * tx->vecs[0][1];
929 scale[0] += tx->vecs[0][2] * tx->vecs[0][2];
930
931 scale[1] += tx->vecs[1][0] * tx->vecs[1][0];
932 scale[1] += tx->vecs[1][1] * tx->vecs[1][1];
933 scale[1] += tx->vecs[1][2] * tx->vecs[1][2];
934
935 scale[0] = sqrt(scale[0]);
936 scale[1] = sqrt(scale[1]);
937
938 return 2.0 / ((scale[0] + scale[1]));
939 }
940 else
941 {
942 return 1.0;
943 }
944 }
945
946 // =====================================================================================
947 // getChop
948 // =====================================================================================
getChop(const patch_t * const patch)949 static vec_t getChop(const patch_t* const patch)
950 {
951 vec_t rval;
952
953 if (VectorCompare(patch->baselight, vec3_origin))
954 {
955 rval = g_chop * getScale(patch);
956 }
957 else
958 {
959 rval = g_texchop * getScale(patch);
960 if (g_extra)
961 {
962 rval *= 0.5;
963 }
964 }
965
966 return rval;
967 }
968
969 // =====================================================================================
970 // MakePatchForFace
971 // =====================================================================================
972 #ifdef ZHLT_TEXLIGHT
MakePatchForFace(const int fn,Winding * w,int style)973 static void MakePatchForFace(const int fn, Winding* w, int style) //LRC
974 #else
975 static void MakePatchForFace(const int fn, Winding* w)
976 #endif
977 {
978 const dface_t* f = g_dfaces + fn;
979
980 // No g_patches at all for the sky!
981 if (!IsSpecial(f))
982 {
983 patch_t* patch;
984 vec3_t light;
985 vec3_t centroid = { 0, 0, 0 };
986
987 int numpoints = w->m_NumPoints;
988
989 if (numpoints < 3) // WTF! (Actually happens in real-world maps too)
990 {
991 Developer(DEVELOPER_LEVEL_WARNING, "Face %d only has %d points on winding\n", fn, numpoints);
992 return;
993 }
994 if (numpoints > MAX_POINTS_ON_WINDING)
995 {
996 Error("numpoints %d > MAX_POINTS_ON_WINDING", numpoints);
997 return;
998 }
999
1000 patch = &g_patches[g_num_patches];
1001 hlassume(g_num_patches < MAX_PATCHES, assume_MAX_PATCHES);
1002 memset(patch, 0, sizeof(patch_t));
1003
1004 patch->winding = w;
1005
1006 patch->area = patch->winding->getArea();
1007 patch->winding->getCenter(patch->origin);
1008 patch->faceNumber = fn;
1009
1010 totalarea += patch->area;
1011
1012 PlacePatchInside(patch);
1013
1014 BaseLightForFace(f, light);
1015 #ifdef ZHLT_TEXLIGHT
1016 //LRC VectorCopy(light, patch->totallight);
1017 #else
1018 VectorCopy(light, patch->totallight);
1019 #endif
1020 VectorCopy(light, patch->baselight);
1021
1022 #ifdef ZHLT_TEXLIGHT
1023 //LRC
1024 int i;
1025 patch->totalstyle[0] = 0;
1026 for (i = 1; i < MAXLIGHTMAPS; i++)
1027 {
1028 patch->totalstyle[i] = 255;
1029 }
1030 if (style)
1031 {
1032 patch->emitstyle = patch->totalstyle[1] = style;
1033 }
1034 //LRC (ends)
1035 #endif
1036
1037 patch->scale = getScale(patch);
1038 patch->chop = getChop(patch);
1039
1040 g_face_patches[fn] = patch;
1041 g_num_patches++;
1042
1043 // Per-face data
1044 {
1045 int j;
1046
1047 // Centroid of face for nudging samples in direct lighting pass
1048 for (j = 0; j < f->numedges; j++)
1049 {
1050 int edge = g_dsurfedges[f->firstedge + j];
1051
1052 if (edge > 0)
1053 {
1054 VectorAdd(g_dvertexes[g_dedges[edge].v[0]].point, centroid, centroid);
1055 VectorAdd(g_dvertexes[g_dedges[edge].v[1]].point, centroid, centroid);
1056 }
1057 else
1058 {
1059 VectorAdd(g_dvertexes[g_dedges[-edge].v[1]].point, centroid, centroid);
1060 VectorAdd(g_dvertexes[g_dedges[-edge].v[0]].point, centroid, centroid);
1061 }
1062 }
1063
1064 // Fixup centroid for anything with an altered origin (rotating models/turrets mostly)
1065 // Save them for moving direct lighting points towards the face center
1066 VectorScale(centroid, 1.0 / (f->numedges * 2), centroid);
1067 VectorAdd(centroid, g_face_offset[fn], g_face_centroids[fn]);
1068 }
1069
1070 {
1071 vec3_t mins;
1072 vec3_t maxs;
1073
1074 patch->winding->getBounds(mins, maxs);
1075
1076 if (g_subdivide)
1077 {
1078 vec_t amt;
1079 vec_t length;
1080 vec3_t delta;
1081
1082 VectorSubtract(maxs, mins, delta);
1083 length = VectorLength(delta);
1084 if (VectorCompare(patch->baselight, vec3_origin))
1085 {
1086 amt = g_chop;
1087 }
1088 else
1089 {
1090 amt = g_texchop;
1091 }
1092
1093 if (length > amt)
1094 {
1095 if (patch->area < 1.0)
1096 {
1097 Developer(DEVELOPER_LEVEL_WARNING,
1098 "Patch at (%4.3f %4.3f %4.3f) (face %d) tiny area (%4.3f) not subdividing \n",
1099 patch->origin[0], patch->origin[1], patch->origin[2], patch->faceNumber, patch->area);
1100 }
1101 else
1102 {
1103 SubdividePatch(patch);
1104 }
1105 }
1106 }
1107 }
1108 }
1109 }
1110
1111 // =====================================================================================
1112 // AddFaceToOpaqueList
1113 // =====================================================================================
1114 #ifdef HLRAD_HULLU
AddFaceToOpaqueList(const unsigned facenum,const Winding * const winding,const vec3_t & transparency_scale,const bool transparency)1115 static void AddFaceToOpaqueList(const unsigned facenum, const Winding* const winding, const vec3_t &transparency_scale, const bool transparency)
1116 #else
1117 static void AddFaceToOpaqueList(const unsigned facenum, const Winding* const winding)
1118 #endif
1119 {
1120 if (g_opaque_face_count == g_max_opaque_face_count)
1121 {
1122 g_max_opaque_face_count += OPAQUE_ARRAY_GROWTH_SIZE;
1123 g_opaque_face_list = (opaqueList_t*)realloc(g_opaque_face_list, sizeof(opaqueList_t) * g_max_opaque_face_count);
1124 }
1125
1126 {
1127 opaqueList_t* opaque = &g_opaque_face_list[g_opaque_face_count];
1128
1129 g_opaque_face_count++;
1130
1131 #ifdef HLRAD_HULLU
1132 VectorCopy(transparency_scale, opaque->transparency_scale);
1133 opaque->transparency = transparency;
1134 #endif
1135 opaque->facenum = facenum;
1136 getAdjustedPlaneFromFaceNumber(facenum, &opaque->plane);
1137 opaque->winding = new Winding(*winding);
1138
1139 //build bounding box
1140 opaque->winding->getBounds(opaque->mins,opaque->maxs);
1141 }
1142 }
1143
1144 // =====================================================================================
1145 // FreeOpaqueFaceList
1146 // =====================================================================================
FreeOpaqueFaceList()1147 static void FreeOpaqueFaceList()
1148 {
1149 unsigned x;
1150 opaqueList_t* opaque = g_opaque_face_list;
1151
1152 for (x = 0; x < g_opaque_face_count; x++, opaque++)
1153 {
1154 delete opaque->winding;
1155 opaque->winding = NULL;
1156 }
1157 free(g_opaque_face_list);
1158
1159 g_opaque_face_list = NULL;
1160 g_opaque_face_count = 0;
1161 g_max_opaque_face_count = 0;
1162 }
1163
1164 // =====================================================================================
1165 // MakePatches
1166 // =====================================================================================
MakePatches()1167 static void MakePatches()
1168 {
1169 int i;
1170 int j;
1171 unsigned int k;
1172 dface_t* f;
1173 int fn;
1174 Winding* w;
1175 dmodel_t* mod;
1176 vec3_t origin;
1177 entity_t* ent;
1178 const char* s;
1179 vec3_t light_origin;
1180 vec3_t model_center;
1181 bool b_light_origin;
1182 bool b_model_center;
1183 eModelLightmodes lightmode;
1184
1185 #ifdef ZHLT_TEXLIGHT
1186 int style; //LRC
1187 #endif
1188
1189 #ifdef HLRAD_HULLU
1190 vec3_t d_transparency;
1191 bool b_transparency;
1192 #endif
1193
1194 Log("%i faces\n", g_numfaces);
1195
1196 Log("Create Patches : ");
1197
1198 for (i = 0; i < g_nummodels; i++)
1199 {
1200 b_light_origin = false;
1201 b_model_center = false;
1202 lightmode = eModelLightmodeNull;
1203
1204 #ifdef HLRAD_OPACITY // AJM
1205 float l_opacity = 0.0f; // decimal percentage
1206 #endif
1207
1208 mod = g_dmodels + i;
1209 ent = EntityForModel(i);
1210 VectorCopy(vec3_origin, origin);
1211
1212 if (*(s = ValueForKey(ent, "zhlt_lightflags")))
1213 {
1214 lightmode = (eModelLightmodes)atoi(s);
1215 }
1216
1217 // models with origin brushes need to be offset into their in-use position
1218 if (*(s = ValueForKey(ent, "origin")))
1219 {
1220 double v1, v2, v3;
1221
1222 if (sscanf_s(s, "%lf %lf %lf", &v1, &v2, &v3) == 3)
1223 {
1224 origin[0] = v1;
1225 origin[1] = v2;
1226 origin[2] = v3;
1227 }
1228
1229 }
1230
1231 // Allow models to be lit in an alternate location (pt1)
1232 if (*(s = ValueForKey(ent, "light_origin")))
1233 {
1234 entity_t* e = FindTargetEntity(s);
1235
1236 if (e)
1237 {
1238 if (*(s = ValueForKey(e, "origin")))
1239 {
1240 double v1, v2, v3;
1241
1242 if (sscanf_s(s, "%lf %lf %lf", &v1, &v2, &v3) == 3)
1243 {
1244 light_origin[0] = v1;
1245 light_origin[1] = v2;
1246 light_origin[2] = v3;
1247
1248 b_light_origin = true;
1249 }
1250 }
1251 }
1252 }
1253
1254 // Allow models to be lit in an alternate location (pt2)
1255 if (*(s = ValueForKey(ent, "model_center")))
1256 {
1257 double v1, v2, v3;
1258
1259 if (sscanf_s(s, "%lf %lf %lf", &v1, &v2, &v3) == 3)
1260 {
1261 model_center[0] = v1;
1262 model_center[1] = v2;
1263 model_center[2] = v3;
1264
1265 b_model_center = true;
1266 }
1267 }
1268
1269 #ifdef HLRAD_HULLU
1270 // Check for colored transparency/custom shadows
1271 VectorFill(d_transparency, 1.0);
1272 b_transparency = false;
1273
1274 if (*(s = ValueForKey(ent, "zhlt_customshadow")))
1275 {
1276 double r1 = 1.0, g1 = 1.0, b1 = 1.0, tmp = 1.0;
1277 if (sscanf_s(s, "%lf %lf %lf", &r1, &g1, &b1) == 3) //RGB version
1278 {
1279 if(r1<0.0) r1 = 0.0;
1280 if(g1<0.0) g1 = 0.0;
1281 if(b1<0.0) b1 = 0.0;
1282
1283 d_transparency[0] = r1;
1284 d_transparency[1] = g1;
1285 d_transparency[2] = b1;
1286 b_transparency = true;
1287 }
1288 else if (sscanf_s(s, "%lf", &tmp) == 1) //Greyscale version
1289 {
1290 if(tmp<0.0) tmp = 0.0;
1291
1292 VectorFill(d_transparency, tmp);
1293 b_transparency = true;
1294 }
1295 }
1296 #endif
1297 // Allow models to be lit in an alternate location (pt3)
1298 if (b_light_origin && b_model_center)
1299 {
1300 VectorSubtract(light_origin, model_center, origin);
1301 }
1302
1303 #ifdef ZHLT_TEXLIGHT
1304 //LRC:
1305 /* ummmmm..... something is very, very wrong here. */
1306 if (*(s = ValueForKey(ent, "style")))
1307 {
1308 style = atoi(s);
1309 if (style < 0)
1310 style = -style;
1311 }
1312 else
1313 {
1314 style = 0;
1315 }
1316 //LRC (ends)
1317
1318 #endif
1319
1320 for (j = 0; j < mod->numfaces; j++)
1321 {
1322 fn = mod->firstface + j;
1323 g_face_entity[fn] = ent;
1324 VectorCopy(origin, g_face_offset[fn]);
1325 g_face_lightmode[fn] = lightmode;
1326 f = g_dfaces + fn;
1327 w = new Winding(*f);
1328 for (k = 0; k < w->m_NumPoints; k++)
1329 {
1330 VectorAdd(w->m_Points[k], origin, w->m_Points[k]);
1331 }
1332 if (g_allow_opaques)
1333 {
1334 if (lightmode & eModelLightmodeOpaque)
1335 {
1336 #ifdef HLRAD_HULLU
1337 AddFaceToOpaqueList(fn, w, d_transparency, b_transparency);
1338 #else
1339 AddFaceToOpaqueList(fn, w);
1340 #endif
1341 }
1342 }
1343 #ifdef ZHLT_TEXLIGHT
1344 MakePatchForFace(fn, w, style); //LRC
1345 #else
1346 MakePatchForFace(fn, w);
1347 #endif
1348 }
1349 }
1350
1351 Log("%i base patches\n", g_num_patches);
1352 Log("%i opaque faces\n", g_opaque_face_count);
1353 Log("%i square feet [%.2f square inches]\n", (int)(totalarea / 144), totalarea);
1354 }
1355
1356 // =====================================================================================
1357 // patch_sorter
1358 // =====================================================================================
patch_sorter(const void * p1,const void * p2)1359 static int CDECL patch_sorter(const void* p1, const void* p2)
1360 {
1361 patch_t* patch1 = (patch_t*)p1;
1362 patch_t* patch2 = (patch_t*)p2;
1363
1364 if (patch1->faceNumber < patch2->faceNumber)
1365 {
1366 return -1;
1367 }
1368 else if (patch1->faceNumber > patch2->faceNumber)
1369 {
1370 return 1;
1371 }
1372 else
1373 {
1374 return 0;
1375 }
1376 }
1377
1378 // =====================================================================================
1379 // patch_sorter
1380 // This sorts the patches by facenumber, which makes their runs compress even better
1381 // =====================================================================================
SortPatches()1382 static void SortPatches()
1383 {
1384 qsort((void*)g_patches, (size_t) g_num_patches, sizeof(patch_t), patch_sorter);
1385
1386 // Fixup g_face_patches & Fixup patch->next
1387 memset(g_face_patches, 0, sizeof(g_face_patches));
1388 {
1389 unsigned x;
1390 patch_t* patch = g_patches + 1;
1391 patch_t* prev = g_patches;
1392
1393 g_face_patches[0] = g_patches;
1394
1395 for (x = 1; x < g_num_patches; x++, patch++)
1396 {
1397 if (patch->faceNumber != prev->faceNumber)
1398 {
1399 prev->next = NULL;
1400 g_face_patches[patch->faceNumber] = patch;
1401 }
1402 else
1403 {
1404 prev->next = patch;
1405 }
1406 prev = patch;
1407 }
1408 }
1409 }
1410
1411 // =====================================================================================
1412 // FreePatches
1413 // =====================================================================================
FreePatches()1414 static void FreePatches()
1415 {
1416 unsigned x;
1417 patch_t* patch = g_patches;
1418
1419 // AJM EX
1420 //Log("patches: %i of %i (%2.2lf percent)\n", g_num_patches, MAX_PATCHES, (double)((double)g_num_patches / (double)MAX_PATCHES));
1421
1422 for (x = 0; x < g_num_patches; x++, patch++)
1423 {
1424 delete patch->winding;
1425 }
1426 memset(g_patches, 0, sizeof(patch_t) * g_num_patches);
1427 }
1428
1429 //=====================================================================
1430
1431 // =====================================================================================
1432 // WriteWorld
1433 // =====================================================================================
WriteWorld(const char * const name)1434 static void WriteWorld(const char* const name)
1435 {
1436 unsigned i;
1437 unsigned j;
1438 FILE* out;
1439 patch_t* patch;
1440 Winding* w;
1441
1442 out = fopen(name, "w");
1443
1444 if (!out)
1445 Error("Couldn't open %s", name);
1446
1447 for (j = 0, patch = g_patches; j < g_num_patches; j++, patch++)
1448 {
1449 w = patch->winding;
1450 Log("%i\n", w->m_NumPoints);
1451 for (i = 0; i < w->m_NumPoints; i++)
1452 {
1453 #ifdef ZHLT_TEXLIGHT
1454 Log("%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
1455 w->m_Points[i][0],
1456 w->m_Points[i][1],
1457 w->m_Points[i][2], patch->totallight[0][0] / 256, patch->totallight[0][1] / 256, patch->totallight[0][2] / 256); //LRC
1458 #else
1459 Log("%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
1460 w->m_Points[i][0],
1461 w->m_Points[i][1],
1462 w->m_Points[i][2], patch->totallight[0] / 256, patch->totallight[1] / 256, patch->totallight[2] / 256);
1463 #endif
1464 }
1465 Log("\n");
1466 }
1467
1468 fclose(out);
1469 }
1470
1471 // =====================================================================================
1472 // CollectLight
1473 // =====================================================================================
CollectLight()1474 static void CollectLight()
1475 {
1476 #ifdef ZHLT_TEXLIGHT
1477 unsigned j; //LRC
1478 #endif
1479 unsigned i;
1480 patch_t* patch;
1481
1482 for (i = 0, patch = g_patches; i < g_num_patches; i++, patch++)
1483 {
1484 #ifdef ZHLT_TEXLIGHT
1485 //LRC
1486 for (j = 0; j < MAXLIGHTMAPS && patch->totalstyle[j] != 255; j++)
1487 {
1488 VectorAdd(patch->totallight[j], addlight[i][j], patch->totallight[j]);
1489 VectorScale(addlight[i][j], TRANSFER_SCALE, emitlight[i][j]);
1490 VectorClear(addlight[i][j]);
1491 }
1492 #else
1493 VectorAdd(patch->totallight, addlight[i], patch->totallight);
1494 VectorScale(addlight[i], TRANSFER_SCALE, emitlight[i]);
1495 VectorClear(addlight[i]);
1496 #endif
1497 }
1498 }
1499
1500 // =====================================================================================
1501 // GatherLight
1502 // Get light from other g_patches
1503 // Run multi-threaded
1504 // =====================================================================================
1505 #ifdef SYSTEM_WIN32
1506 #pragma warning(push)
1507 #pragma warning(disable: 4100) // unreferenced formal parameter
1508 #endif
GatherLight(intptr_t threadnum)1509 static void GatherLight(intptr_t threadnum)
1510 {
1511 int j;
1512 patch_t* patch;
1513
1514 #ifdef ZHLT_TEXLIGHT
1515 unsigned k,m; //LRC
1516 //LRC vec3_t sum;
1517 #else
1518 unsigned k;
1519 vec3_t sum;
1520 #endif
1521
1522 unsigned iIndex;
1523 transfer_data_t* tData;
1524 transfer_index_t* tIndex;
1525
1526 while (1)
1527 {
1528 j = GetThreadWork();
1529 if (j == -1)
1530 {
1531 break;
1532 }
1533
1534 patch = &g_patches[j];
1535
1536 tData = patch->tData;
1537 tIndex = patch->tIndex;
1538 iIndex = patch->iIndex;
1539
1540 #ifdef ZHLT_TEXLIGHT
1541 //LRC
1542 for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
1543 {
1544 VectorClear(addlight[j][m]);
1545 }
1546 #else
1547 VectorClear(sum);
1548 #endif
1549
1550 for (k = 0; k < iIndex; k++, tIndex++)
1551 {
1552 unsigned l;
1553 unsigned size = (tIndex->size + 1);
1554 unsigned patchnum = tIndex->index;
1555
1556 for (l = 0; l < size; l++, tData++, patchnum++)
1557 {
1558 vec3_t v;
1559 #ifdef ZHLT_TEXLIGHT
1560 //LRC:
1561 patch_t* emitpatch = &g_patches[patchnum];
1562 unsigned emitstyle;
1563
1564 // for each style on the emitting patch
1565 for (emitstyle = 0; emitstyle < MAXLIGHTMAPS && emitpatch->totalstyle[emitstyle] != 255; emitstyle++)
1566 {
1567 //if dynamic bounce has been turned off, we ignore dynamic lightstyles
1568 if(!g_bounce_dynamic && emitstyle != 0)
1569 { break; }
1570
1571 // find the matching style on this (destination) patch
1572 for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
1573 {
1574 if (patch->totalstyle[m] == emitpatch->totalstyle[emitstyle])
1575 {
1576 break;
1577 }
1578 }
1579
1580 if (m == MAXLIGHTMAPS)
1581 {
1582 if(!g_warned_direct || g_verbose)
1583 {
1584 Warning("Too many light styles on a face(%f,%f,%f)",patch->origin[0],patch->origin[1],patch->origin[2]);
1585 g_warned_direct = true;
1586 }
1587 }
1588 else
1589 {
1590 if (patch->totalstyle[m] == 255)
1591 {
1592 patch->totalstyle[m] = emitpatch->totalstyle[emitstyle];
1593 }
1594 VectorScale(emitlight[patchnum][emitstyle], (*tData), v);
1595 if (isPointFinite(v))
1596 {
1597 VectorAdd(addlight[j][m], v, addlight[j][m]);
1598 }
1599 else
1600 {
1601 Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
1602 v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
1603 }
1604 }
1605 }
1606 #else
1607 VectorScale(emitlight[patchnum], (*tData), v);
1608 if (isPointFinite(v))
1609 {
1610 VectorAdd(sum, v, sum);
1611 }
1612 else
1613 {
1614 Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
1615 v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
1616 }
1617 #endif
1618 }
1619 }
1620
1621 #ifdef ZHLT_TEXLIGHT
1622 //LRC VectorCopy(sum, addlight[j]);
1623 #else
1624 VectorCopy(sum, addlight[j]);
1625 #endif
1626 }
1627 }
1628
1629 // RGB Transfer version
1630 #ifdef HLRAD_HULLU
GatherRGBLight(intptr_t threadnum)1631 static void GatherRGBLight(intptr_t threadnum)
1632 {
1633 int j;
1634 patch_t* patch;
1635
1636 #ifdef ZHLT_TEXLIGHT
1637 unsigned k,m; //LRC
1638 //LRC vec3_t sum;
1639 #else
1640 unsigned k;
1641 vec3_t sum;
1642 #endif
1643
1644 unsigned iIndex;
1645 rgb_transfer_data_t* tRGBData;
1646 transfer_index_t* tIndex;
1647
1648 while (1)
1649 {
1650 j = GetThreadWork();
1651 if (j == -1)
1652 {
1653 break;
1654 }
1655
1656 patch = &g_patches[j];
1657
1658 tRGBData = patch->tRGBData;
1659 tIndex = patch->tIndex;
1660 iIndex = patch->iIndex;
1661
1662 #ifdef ZHLT_TEXLIGHT
1663 //LRC
1664 for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
1665 {
1666 VectorClear(addlight[j][m]);
1667 }
1668 #else
1669 VectorClear(sum);
1670 #endif
1671
1672 for (k = 0; k < iIndex; k++, tIndex++)
1673 {
1674 unsigned l;
1675 unsigned size = (tIndex->size + 1);
1676 unsigned patchnum = tIndex->index;
1677
1678 for (l = 0; l < size; l++, tRGBData++, patchnum++)
1679 {
1680 vec3_t v;
1681 #ifdef ZHLT_TEXLIGHT
1682 //LRC:
1683 patch_t* emitpatch = &g_patches[patchnum];
1684 unsigned emitstyle;
1685
1686 // for each style on the emitting patch
1687 for (emitstyle = 0; emitstyle < MAXLIGHTMAPS && emitpatch->totalstyle[emitstyle] != 255; emitstyle++)
1688 {
1689 //if dynamic bounce has been turned off, we ignore nonzero lightstyles
1690 if(!g_bounce_dynamic && emitstyle != 0)
1691 { break; }
1692
1693 // find the matching style on this (destination) patch
1694 for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
1695 {
1696 if (patch->totalstyle[m] == emitpatch->totalstyle[emitstyle])
1697 {
1698 break;
1699 }
1700 }
1701
1702 if (m == MAXLIGHTMAPS)
1703 {
1704 if(!g_warned_direct || g_verbose)
1705 {
1706 Warning("Too many light styles on a face(%f,%f,%f)",patch->origin[0],patch->origin[1],patch->origin[2]);
1707 g_warned_direct = true;
1708 }
1709 }
1710 else
1711 {
1712 if (patch->totalstyle[m] == 255)
1713 {
1714 patch->totalstyle[m] = emitpatch->totalstyle[emitstyle];
1715 // Log("Granting new style %d to patch at idx %d\n", patch->totalstyle[m], m);
1716 }
1717 VectorMultiply(emitlight[patchnum][emitstyle], (*tRGBData), v);
1718 if (isPointFinite(v))
1719 {
1720 VectorAdd(addlight[j][m], v, addlight[j][m]);
1721 }
1722 else
1723 {
1724 Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
1725 v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
1726 }
1727 }
1728 }
1729 //LRC (ends)
1730 #else
1731 VectorMultiply(emitlight[patchnum], (*tRGBData), v);
1732 if (isPointFinite(v))
1733 {
1734 VectorAdd(sum, v, sum);
1735 }
1736 else
1737 {
1738 Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
1739 v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
1740 }
1741 #endif
1742 }
1743 }
1744
1745 #ifdef ZHLT_TEXLIGHT
1746 //LRC VectorCopy(sum, addlight[j]);
1747 #else
1748 VectorCopy(sum, addlight[j]);
1749 #endif
1750 }
1751 }
1752 #endif
1753
1754 #ifdef SYSTEM_WIN32
1755 #pragma warning(pop)
1756 #endif
1757
1758 // =====================================================================================
1759 // BounceLight
1760 // =====================================================================================
BounceLight()1761 static void BounceLight()
1762 {
1763 unsigned i;
1764 char name[64];
1765
1766 #ifdef ZHLT_TEXLIGHT
1767 unsigned j; //LRC
1768 #endif
1769
1770 for (i = 0; i < g_num_patches; i++)
1771 {
1772 #ifdef ZHLT_TEXLIGHT
1773 //LRC
1774 for (j = 0; j < MAXLIGHTMAPS && g_patches[i].totalstyle[j] != 255; j++)
1775 {
1776 VectorScale(g_patches[i].totallight[j], TRANSFER_SCALE, emitlight[i][j]);
1777 }
1778 #else
1779 VectorScale(g_patches[i].totallight, TRANSFER_SCALE, emitlight[i]);
1780 #endif
1781 }
1782
1783 for (i = 0; i < g_numbounce; i++)
1784 {
1785 printf("Bounce %u ", i + 1);
1786 #ifdef HLRAD_HULLU
1787 if(g_rgb_transfers)
1788 {
1789 NamedRunThreadsOn(g_num_patches, g_estimate, GatherRGBLight);
1790 }
1791 else
1792 {
1793 NamedRunThreadsOn(g_num_patches, g_estimate, GatherLight);
1794 }
1795 #else
1796 NamedRunThreadsOn(g_num_patches, g_estimate, GatherLight);
1797 #endif
1798 CollectLight();
1799
1800 if (g_dumppatches)
1801 {
1802 sprintf_s(name, "bounce%u.txt", i);
1803 WriteWorld(name);
1804 }
1805 }
1806 }
1807
1808 // =====================================================================================
1809 // CheckMaxPatches
1810 // =====================================================================================
CheckMaxPatches()1811 static void CheckMaxPatches()
1812 {
1813 switch (g_method)
1814 {
1815 case eMethodVismatrix:
1816 hlassume(g_num_patches < MAX_VISMATRIX_PATCHES, assume_MAX_PATCHES);
1817 break;
1818 case eMethodSparseVismatrix:
1819 hlassume(g_num_patches < MAX_SPARSE_VISMATRIX_PATCHES, assume_MAX_PATCHES);
1820 break;
1821 case eMethodNoVismatrix:
1822 hlassume(g_num_patches < MAX_PATCHES, assume_MAX_PATCHES);
1823 break;
1824 }
1825 }
1826
1827 // =====================================================================================
1828 // MakeScalesStub
1829 // =====================================================================================
MakeScalesStub()1830 static void MakeScalesStub()
1831 {
1832 switch (g_method)
1833 {
1834 case eMethodVismatrix:
1835 MakeScalesVismatrix();
1836 break;
1837 case eMethodSparseVismatrix:
1838 MakeScalesSparseVismatrix();
1839 break;
1840 case eMethodNoVismatrix:
1841 MakeScalesNoVismatrix();
1842 break;
1843 }
1844 }
1845
1846 // =====================================================================================
1847 // FreeTransfers
1848 // =====================================================================================
FreeTransfers()1849 static void FreeTransfers()
1850 {
1851 unsigned x;
1852 patch_t* patch = g_patches;
1853
1854 for (x = 0; x < g_num_patches; x++, patch++)
1855 {
1856 if (patch->tData)
1857 {
1858 FreeBlock(patch->tData);
1859 patch->tData = NULL;
1860 }
1861 #ifdef HLRAD_HULLU
1862 if (patch->tRGBData)
1863 {
1864 FreeBlock(patch->tRGBData);
1865 patch->tRGBData = NULL;
1866 }
1867 #endif
1868 if (patch->tIndex)
1869 {
1870 FreeBlock(patch->tIndex);
1871 patch->tIndex = NULL;
1872 }
1873 }
1874 }
1875
1876 // =====================================================================================
1877 // RadWorld
1878 // =====================================================================================
RadWorld()1879 static void RadWorld()
1880 {
1881 unsigned i;
1882 #ifdef ZHLT_TEXLIGHT
1883 unsigned j;
1884 #endif
1885
1886 MakeBackplanes();
1887 MakeParents(0, -1);
1888 MakeTnodes(&g_dmodels[0]);
1889
1890 // turn each face into a single patch
1891 MakePatches();
1892 CheckMaxPatches(); // Check here for exceeding max patches, to prevent a lot of work from occuring before an error occurs
1893 SortPatches(); // Makes the runs in the Transfer Compression really good
1894 PairEdges();
1895
1896 // create directlights out of g_patches and lights
1897 CreateDirectLights();
1898
1899 Log("\n");
1900
1901 // build initial facelights
1902 NamedRunThreadsOnIndividual(g_numfaces, g_estimate, BuildFacelights);
1903
1904 // free up the direct lights now that we have facelights
1905 DeleteDirectLights();
1906
1907 if (g_numbounce > 0)
1908 {
1909 // build transfer lists
1910 MakeScalesStub();
1911
1912 // spread light around
1913 BounceLight();
1914
1915 for (i = 0; i < g_num_patches; i++)
1916 {
1917 #ifdef ZHLT_TEXLIGHT// AJM
1918 for (j = 0; j < MAXLIGHTMAPS && g_patches[i].totalstyle[j] != 255; j++)
1919 {
1920 VectorSubtract(g_patches[i].totallight[j], g_patches[i].directlight[j], g_patches[i].totallight[j]);
1921 }
1922 #else
1923 VectorSubtract(g_patches[i].totallight, g_patches[i].directlight, g_patches[i].totallight);
1924 #endif
1925 }
1926 }
1927
1928 FreeTransfers();
1929
1930 // blend bounced light into direct light and save
1931 PrecompLightmapOffsets();
1932
1933 NamedRunThreadsOnIndividual(g_numfaces, g_estimate, FinalLightFace);
1934 }
1935
1936 // =====================================================================================
1937 // Usage
1938 // =====================================================================================
Usage()1939 static void Usage()
1940 {
1941 Banner();
1942
1943 Log("\n-= %s Options =-\n\n", g_Program);
1944 Log(" -sparse : Enable low memory vismatrix algorithm\n");
1945 Log(" -nomatrix : Disable usage of vismatrix entirely\n\n");
1946 Log(" -extra : Improve lighting quality by doing 9 point oversampling\n");
1947 Log(" -bounce # : Set number of radiosity bounces\n");
1948 Log(" -ambient r g b : Set ambient world light (0.0 to 1.0, r g b)\n");
1949 Log(" -maxlight # : Set maximum light intensity value\n");
1950 Log(" -circus : Enable 'circus' mode for locating unlit lightmaps\n");
1951 Log(" -nopaque : Disable the opaque zhlt_lightflags for this compile\n\n");
1952 Log(" -smooth # : Set smoothing threshold for blending (in degrees)\n");
1953 Log(" -chop # : Set radiosity patch size for normal textures\n");
1954 Log(" -texchop # : Set radiosity patch size for texture light faces\n\n");
1955 Log(" -notexscale # : Do not scale radiosity patches with texture scale\n");
1956 Log(" -coring # : Set lighting threshold before blackness\n");
1957 Log(" -dlight # : Set direct lighting threshold\n");
1958 Log(" -nolerp : Disable radiosity interpolation, nearest point instead\n\n");
1959 Log(" -fade # : Set global fade (larger values = shorter lights)\n");
1960 Log(" -falloff # : Set global falloff mode (1 = inv linear, 2 = inv square)\n");
1961 Log(" -scale # : Set global light scaling value\n");
1962 Log(" -gamma # : Set global gamma value\n\n");
1963 Log(" -sky # : Set ambient sunlight contribution in the shade outside\n");
1964 Log(" -lights file : Manually specify a lights.rad file to use\n");
1965 Log(" -noskyfix : Disable light_environment being global\n");
1966 Log(" -incremental : Use or create an incremental transfer list file\n\n");
1967 Log(" -dump : Dumps light patches to a file for hlrad debugging info\n\n");
1968 Log(" -texdata # : Alter maximum texture memory limit (in kb)\n");
1969 Log(" -lightdata # : Alter maximum lighting memory limit (in kb)\n");
1970 Log(" -chart : display bsp statitics\n");
1971 Log(" -low | -high : run program an altered priority level\n");
1972 Log(" -nolog : Do not generate the compile logfiles\n");
1973 Log(" -threads # : manually specify the number of threads to run\n");
1974 #ifdef SYSTEM_WIN32
1975 Log(" -estimate : display estimated time during compile\n");
1976 #endif
1977 #ifdef ZHLT_PROGRESSFILE // AJM
1978 Log(" -progressfile path : specify the path to a file for progress estimate output\n");
1979 #endif
1980 #ifdef SYSTEM_POSIX
1981 Log(" -noestimate : Do not display continuous compile time estimates\n");
1982 #endif
1983 Log(" -verbose : compile with verbose messages\n");
1984 Log(" -noinfo : Do not show tool configuration information\n");
1985 Log(" -dev # : compile with developer message\n\n");
1986
1987 // ------------------------------------------------------------------------
1988 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
1989 #ifdef HLRAD_WHOME
1990
1991 // AJM: we dont need this extra crap
1992 //Log("-= Unofficial features added by Adam Foster (afoster@compsoc.man.ac.uk) =-\n\n");
1993 Log(" -colourgamma r g b : Sets different gamma values for r, g, b\n" );
1994 Log(" -colourscale r g b : Sets different lightscale values for r, g ,b\n" );
1995 Log(" -colourjitter r g b : Adds noise, independent colours, for dithering\n");
1996 Log(" -jitter r g b : Adds noise, monochromatic, for dithering\n");
1997 Log(" -nodiffuse : Disables light_environment diffuse hack\n");
1998 Log(" -nospotpoints : Disables light_spot spherical point sources\n");
1999 Log(" -softlight r g b d : Scaling values for backwards-light hack\n\n");
2000 //Log("-= End of unofficial features! =-\n\n" );
2001
2002 #endif
2003 // ------------------------------------------------------------------------
2004
2005 #ifdef HLRAD_HULLU
2006 Log(" -customshadowwithbounce : Enables custom shadows with bounce light\n");
2007 Log(" -rgbtransfers : Enables RGB Transfers (for custom shadows)\n\n");
2008 #endif
2009
2010 Log(" mapfile : The mapfile to compile\n\n");
2011
2012 exit(1);
2013 }
2014
2015 // =====================================================================================
2016 // Settings
2017 // =====================================================================================
Settings()2018 static void Settings()
2019 {
2020 char* tmp;
2021 char buf1[1024];
2022 char buf2[1024];
2023
2024 if (!g_info)
2025 {
2026 return;
2027 }
2028
2029 Log("\n-= Current %s Settings =-\n", g_Program);
2030 Log("Name | Setting | Default\n"
2031 "--------------------|---------------------|-------------------------\n");
2032
2033 // ZHLT Common Settings
2034 if (DEFAULT_NUMTHREADS == -1)
2035 {
2036 Log("threads [ %17d ] [ Varies ]\n", g_numthreads);
2037 }
2038 else
2039 {
2040 Log("threads [ %17d ] [ %17d ]\n", g_numthreads, DEFAULT_NUMTHREADS);
2041 }
2042
2043 Log("verbose [ %17s ] [ %17s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off");
2044 Log("log [ %17s ] [ %17s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off");
2045 Log("developer [ %17d ] [ %17d ]\n", g_developer, DEFAULT_DEVELOPER);
2046 Log("chart [ %17s ] [ %17s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
2047 Log("estimate [ %17s ] [ %17s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off");
2048 Log("max texture memory [ %17d ] [ %17d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
2049 Log("max lighting memory [ %17d ] [ %17d ]\n", g_max_map_lightdata, DEFAULT_MAX_MAP_LIGHTDATA);
2050
2051 switch (g_threadpriority)
2052 {
2053 case eThreadPriorityNormal:
2054 default:
2055 tmp = "Normal";
2056 break;
2057 case eThreadPriorityLow:
2058 tmp = "Low";
2059 break;
2060 case eThreadPriorityHigh:
2061 tmp = "High";
2062 break;
2063 }
2064 Log("priority [ %17s ] [ %17s ]\n", tmp, "Normal");
2065 Log("\n");
2066
2067 // HLRAD Specific Settings
2068 switch (g_method)
2069 {
2070 default:
2071 tmp = "Unknown";
2072 break;
2073 case eMethodVismatrix:
2074 tmp = "Original";
2075 break;
2076 case eMethodSparseVismatrix:
2077 tmp = "Sparse";
2078 break;
2079 case eMethodNoVismatrix:
2080 tmp = "NoMatrix";
2081 break;
2082 }
2083
2084 Log("vismatrix algorithm [ %17s ] [ %17s ]\n", tmp, "Original");
2085 Log("oversampling (-extra)[ %17s ] [ %17s ]\n", g_extra ? "on" : "off", DEFAULT_EXTRA ? "on" : "off");
2086 Log("bounces [ %17d ] [ %17d ]\n", g_numbounce, DEFAULT_BOUNCE);
2087 Log("bounce dynamic light [ %17s ] [ %17s ]\n", g_bounce_dynamic ? "on" : "off", DEFAULT_BOUNCE_DYNAMIC ? "on" : "off");
2088
2089 safe_snprintf(buf1, sizeof(buf1), "%1.3f %1.3f %1.3f", g_ambient[0], g_ambient[1], g_ambient[2]);
2090 safe_snprintf(buf2, sizeof(buf2), "%1.3f %1.3f %1.3f", DEFAULT_AMBIENT_RED, DEFAULT_AMBIENT_GREEN, DEFAULT_AMBIENT_BLUE);
2091 Log("ambient light [ %17s ] [ %17s ]\n", buf1, buf2);
2092 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_maxlight);
2093 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_MAXLIGHT);
2094 Log("maximum light [ %17s ] [ %17s ]\n", buf1, buf2);
2095 Log("circus mode [ %17s ] [ %17s ]\n", g_circus ? "on" : "off", DEFAULT_CIRCUS ? "on" : "off");
2096
2097 Log("\n");
2098
2099 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_smoothing_value);
2100 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_SMOOTHING_VALUE);
2101 Log("smoothing threshold [ %17s ] [ %17s ]\n", buf1, buf2);
2102 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_dlight_threshold);
2103 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_DLIGHT_THRESHOLD);
2104 Log("direct threshold [ %17s ] [ %17s ]\n", buf1, buf2);
2105 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_direct_scale);
2106 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_DLIGHT_SCALE);
2107 Log("direct light scale [ %17s ] [ %17s ]\n", buf1, buf2);
2108 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_coring);
2109 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_CORING);
2110 Log("coring threshold [ %17s ] [ %17s ]\n", buf1, buf2);
2111 Log("patch interpolation [ %17s ] [ %17s ]\n", g_lerp_enabled ? "on" : "off", DEFAULT_LERP_ENABLED ? "on" : "off");
2112
2113 Log("\n");
2114
2115 Log("texscale [ %17s ] [ %17s ]\n", g_texscale ? "on" : "off", DEFAULT_TEXSCALE ? "on" : "off");
2116 Log("patch subdividing [ %17s ] [ %17s ]\n", g_subdivide ? "on" : "off", DEFAULT_SUBDIVIDE ? "on" : "off");
2117 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_chop);
2118 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_CHOP);
2119 Log("chop value [ %17s ] [ %17s ]\n", buf1, buf2);
2120 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_texchop);
2121 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TEXCHOP);
2122 Log("texchop value [ %17s ] [ %17s ]\n", buf1, buf2);
2123 Log("\n");
2124
2125 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_fade);
2126 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_FADE);
2127 Log("global fade [ %17s ] [ %17s ]\n", buf1, buf2);
2128 Log("global falloff [ %17d ] [ %17d ]\n", g_falloff, DEFAULT_FALLOFF);
2129
2130 // ------------------------------------------------------------------------
2131 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
2132 // replaces the old stuff for displaying current values for gamma and lightscale
2133 #ifdef HLRAD_WHOME
2134 safe_snprintf(buf1, sizeof(buf1), "%1.3f %1.3f %1.3f", g_colour_lightscale[0], g_colour_lightscale[1], g_colour_lightscale[2]);
2135 safe_snprintf(buf2, sizeof(buf2), "%1.3f %1.3f %1.3f", DEFAULT_COLOUR_LIGHTSCALE_RED, DEFAULT_COLOUR_LIGHTSCALE_GREEN, DEFAULT_COLOUR_LIGHTSCALE_BLUE);
2136 Log("global light scale [ %17s ] [ %17s ]\n", buf1, buf2);
2137
2138 safe_snprintf(buf1, sizeof(buf1), "%1.3f %1.3f %1.3f", g_colour_qgamma[0], g_colour_qgamma[1], g_colour_qgamma[2]);
2139 safe_snprintf(buf2, sizeof(buf2), "%1.3f %1.3f %1.3f", DEFAULT_COLOUR_GAMMA_RED, DEFAULT_COLOUR_GAMMA_GREEN, DEFAULT_COLOUR_GAMMA_BLUE);
2140 Log("global gamma [ %17s ] [ %17s ]\n", buf1, buf2);
2141 #endif
2142 // ------------------------------------------------------------------------
2143
2144 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_lightscale);
2145 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_LIGHTSCALE);
2146 Log("global light scale [ %17s ] [ %17s ]\n", buf1, buf2);
2147
2148 #ifndef HLRAD_WHOME
2149 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_qgamma);
2150 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_GAMMA);
2151 Log("global gamma amount [ %17s ] [ %17s ]\n", buf1, buf2);
2152 #endif
2153
2154 safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_indirect_sun);
2155 safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_INDIRECT_SUN);
2156 Log("global sky diffusion [ %17s ] [ %17s ]\n", buf1, buf2);
2157
2158 Log("\n");
2159 Log("opaque entities [ %17s ] [ %17s ]\n", g_allow_opaques ? "on" : "off", DEFAULT_ALLOW_OPAQUES ? "on" : "off");
2160 Log("sky lighting fix [ %17s ] [ %17s ]\n", g_sky_lighting_fix ? "on" : "off", DEFAULT_SKY_LIGHTING_FIX ? "on" : "off");
2161 Log("incremental [ %17s ] [ %17s ]\n", g_incremental ? "on" : "off", DEFAULT_INCREMENTAL ? "on" : "off");
2162 Log("dump [ %17s ] [ %17s ]\n", g_dumppatches ? "on" : "off", DEFAULT_DUMPPATCHES ? "on" : "off");
2163
2164 // ------------------------------------------------------------------------
2165 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
2166 // displays information on all the brand-new features :)
2167 #ifdef HLRAD_WHOME
2168
2169 Log("\n");
2170 safe_snprintf(buf1, sizeof(buf1), "%3.1f %3.1f %3.1f", g_colour_jitter_hack[0], g_colour_jitter_hack[1], g_colour_jitter_hack[2]);
2171 safe_snprintf(buf2, sizeof(buf2), "%3.1f %3.1f %3.1f", DEFAULT_COLOUR_JITTER_HACK_RED, DEFAULT_COLOUR_JITTER_HACK_GREEN, DEFAULT_COLOUR_JITTER_HACK_BLUE);
2172 Log("colour jitter [ %17s ] [ %17s ]\n", buf1, buf2);
2173 safe_snprintf(buf1, sizeof(buf1), "%3.1f %3.1f %3.1f", g_jitter_hack[0], g_jitter_hack[1], g_jitter_hack[2]);
2174 safe_snprintf(buf2, sizeof(buf2), "%3.1f %3.1f %3.1f", DEFAULT_JITTER_HACK_RED, DEFAULT_JITTER_HACK_GREEN, DEFAULT_JITTER_HACK_BLUE);
2175 Log("monochromatic jitter [ %17s ] [ %17s ]\n", buf1, buf2);
2176
2177 safe_snprintf(buf1, sizeof(buf1), "%2.1f %2.1f %2.1f %2.1f", g_softlight_hack[0], g_softlight_hack[1], g_softlight_hack[2], g_softlight_hack_distance);
2178 safe_snprintf(buf2, sizeof(buf2), "%2.1f %2.1f %2.1f %2.1f", DEFAULT_SOFTLIGHT_HACK_RED, DEFAULT_SOFTLIGHT_HACK_GREEN, DEFAULT_SOFTLIGHT_HACK_BLUE, DEFAULT_SOFTLIGHT_HACK_DISTANCE);
2179 Log("softlight hack [ %17s ] [ %17s ]\n", buf1, buf2);
2180
2181 Log("diffuse hack [ %17s ] [ %17s ]\n", g_diffuse_hack ? "on" : "off", DEFAULT_DIFFUSE_HACK ? "on" : "off");
2182 Log("spotlight points [ %17s ] [ %17s ]\n", g_spotlight_hack ? "on" : "off", DEFAULT_SPOTLIGHT_HACK ? "on" : "off");
2183
2184 #endif
2185 // ------------------------------------------------------------------------
2186
2187 #ifdef HLRAD_HULLU
2188 Log("\n");
2189 Log("custom shadows with bounce light\n"
2190 " [ %17s ] [ %17s ]\n", g_customshadow_with_bouncelight ? "on" : "off", DEFAULT_CUSTOMSHADOW_WITH_BOUNCELIGHT ? "on" : "off");
2191 Log("rgb transfers [ %17s ] [ %17s ]\n", g_rgb_transfers ? "on" : "off", DEFAULT_RGB_TRANSFERS ? "on" : "off");
2192 #endif
2193 Log("\n\n");
2194 }
2195
2196 #ifdef HLRAD_INFO_TEXLIGHTS
2197 // AJM: added in
2198 // =====================================================================================
2199 // ReadInfoTexlights
2200 // try and parse texlight info from the info_texlights entity
2201 // =====================================================================================
ReadInfoTexlights()2202 void ReadInfoTexlights()
2203 {
2204 int k;
2205 int values;
2206 int numtexlights = 0;
2207 float r, g, b, i;
2208 entity_t* mapent;
2209 epair_t* ep;
2210 texlight_t texlight;
2211
2212 for (k = 0; k < g_numentities; k++)
2213 {
2214 mapent = &g_entities[k];
2215
2216 if (strcmp(ValueForKey(mapent, "classname"), "info_texlights"))
2217 continue;
2218
2219 Log("[Reading texlights from info_texlights map entity]\n");
2220
2221 for (ep = mapent->epairs; ep; ep = ep->next)
2222 {
2223 if ( !strcmp(ep->key, "classname")
2224 || !strcmp(ep->key, "origin")
2225 )
2226 continue; // we dont care about these keyvalues
2227
2228 values = sscanf_s(ep->value, "%f %f %f %f", &r, &g, &b, &i);
2229
2230 if (values == 1)
2231 {
2232 g = b = r;
2233 }
2234 else if (values == 4) // use brightness value.
2235 {
2236 r *= i / 255.0;
2237 g *= i / 255.0;
2238 b *= i / 255.0;
2239 }
2240 else if (values != 3)
2241 {
2242 Warning("ignoring bad texlight '%s' in info_texlights entity", ep->key);
2243 continue;
2244 }
2245
2246 texlight.name = ep->key;
2247 texlight.value[0] = r;
2248 texlight.value[1] = g;
2249 texlight.value[2] = b;
2250 texlight.filename = "info_texlights";
2251 s_texlights.push_back(texlight);
2252 numtexlights++;
2253 }
2254
2255 Log("[%i texlights parsed from info_texlights map entity]\n\n", numtexlights);
2256 }
2257 }
2258 #endif
2259
2260 const char* lights_rad = "lights.rad";
2261 const char* ext_rad = ".rad";
2262
2263 // =====================================================================================
2264 // LoadRadFiles
2265 // =====================================================================================
LoadRadFiles(const char * const mapname,const char * const user_rad,const char * argv0)2266 void LoadRadFiles(const char* const mapname, const char* const user_rad, const char* argv0)
2267 {
2268 char global_lights[_MAX_PATH];
2269 char mapname_lights[_MAX_PATH];
2270
2271 char mapfile[_MAX_PATH];
2272 char mapdir[_MAX_PATH];
2273 char appdir[_MAX_PATH];
2274
2275 // Get application directory (only an approximation on posix systems)
2276 // try looking in the directory we were run from
2277 {
2278 char tmp[_MAX_PATH];
2279 memset(tmp, 0, sizeof(tmp));
2280 #ifdef SYSTEM_WIN32
2281 GetModuleFileName(NULL, tmp, _MAX_PATH);
2282 #else
2283 safe_strncpy(tmp, argv0, _MAX_PATH);
2284 #endif
2285 ExtractFilePath(tmp, appdir);
2286 }
2287
2288 // Get map directory
2289 ExtractFilePath(mapname, mapdir);
2290 ExtractFileBase(mapname, mapfile);
2291
2292 // Look for lights.rad in mapdir
2293 safe_strncpy(global_lights, mapdir, _MAX_PATH);
2294 safe_strncat(global_lights, lights_rad, _MAX_PATH);
2295 if (q_exists(global_lights))
2296 {
2297 ReadLightFile(global_lights);
2298 }
2299 else
2300 {
2301 // Look for lights.rad in appdir
2302 safe_strncpy(global_lights, appdir, _MAX_PATH);
2303 safe_strncat(global_lights, lights_rad, _MAX_PATH);
2304 if (q_exists(global_lights))
2305 {
2306 ReadLightFile(global_lights);
2307 }
2308 else
2309 {
2310 // Look for lights.rad in current working directory
2311 safe_strncpy(global_lights, lights_rad, _MAX_PATH);
2312 if (q_exists(global_lights))
2313 {
2314 ReadLightFile(global_lights);
2315 }
2316 }
2317 }
2318
2319 // Look for mapname.rad in mapdir
2320 safe_strncpy(mapname_lights, mapdir, _MAX_PATH);
2321 safe_strncat(mapname_lights, mapfile, _MAX_PATH);
2322 DefaultExtension(mapname_lights, ext_rad);
2323 if (q_exists(mapname_lights))
2324 {
2325 ReadLightFile(mapname_lights);
2326 }
2327
2328
2329 if (user_rad)
2330 {
2331 char user_lights[_MAX_PATH];
2332 char userfile[_MAX_PATH];
2333
2334 ExtractFile(user_rad, userfile);
2335
2336 // Look for user.rad from command line (raw)
2337 safe_strncpy(user_lights, user_rad, _MAX_PATH);
2338 if (q_exists(user_lights))
2339 {
2340 ReadLightFile(user_lights);
2341 }
2342 else
2343 {
2344 // Try again with .rad enforced as extension
2345 DefaultExtension(user_lights, ext_rad);
2346 if (q_exists(user_lights))
2347 {
2348 ReadLightFile(user_lights);
2349 }
2350 else
2351 {
2352 // Look for user.rad in mapdir
2353 safe_strncpy(user_lights, mapdir, _MAX_PATH);
2354 safe_strncat(user_lights, userfile, _MAX_PATH);
2355 DefaultExtension(user_lights, ext_rad);
2356 if (q_exists(user_lights))
2357 {
2358 ReadLightFile(user_lights);
2359 }
2360 else
2361 {
2362 // Look for user.rad in appdir
2363 safe_strncpy(user_lights, appdir, _MAX_PATH);
2364 safe_strncat(user_lights, userfile, _MAX_PATH);
2365 DefaultExtension(user_lights, ext_rad);
2366 if (q_exists(user_lights))
2367 {
2368 ReadLightFile(user_lights);
2369 }
2370 else
2371 {
2372 // Look for user.rad in current working directory
2373 safe_strncpy(user_lights, userfile, _MAX_PATH);
2374 DefaultExtension(user_lights, ext_rad);
2375 if (q_exists(user_lights))
2376 {
2377 ReadLightFile(user_lights);
2378 }
2379 }
2380 }
2381 }
2382 }
2383 }
2384
2385 #ifdef HLRAD_INFO_TEXLIGHTS
2386 ReadInfoTexlights(); // AJM
2387 #endif
2388 }
2389
2390 // =====================================================================================
2391 // main
2392 // =====================================================================================
main(const int argc,char ** argv)2393 int main(const int argc, char** argv)
2394 {
2395 int i;
2396 double start, end;
2397 const char* mapname_from_arg = NULL;
2398 const char* user_lights = NULL;
2399
2400 g_Program = "hlrad";
2401
2402 if (argc == 1)
2403 Usage();
2404
2405 for (i = 1; i < argc; i++)
2406 {
2407 if (!strcasecmp(argv[i], "-dump"))
2408 {
2409 g_dumppatches = true;
2410 }
2411 else if (!strcasecmp(argv[i], "-bounce"))
2412 {
2413 if (i < argc)
2414 {
2415 g_numbounce = atoi(argv[++i]);
2416 if (g_numbounce > 1000)
2417 {
2418 Log("Unexpectedly large value (>1000) for '-bounce'\n");
2419 Usage();
2420 }
2421 }
2422 else
2423 {
2424 Usage();
2425 }
2426 }
2427 else if (!strcasecmp(argv[i], "-dev"))
2428 {
2429 if (i < argc)
2430 {
2431 g_developer = (developer_level_t)atoi(argv[++i]);
2432 }
2433 else
2434 {
2435 Usage();
2436 }
2437 }
2438 else if (!strcasecmp(argv[i], "-verbose"))
2439 {
2440 g_verbose = true;
2441 }
2442 else if (!strcasecmp(argv[i], "-noinfo"))
2443 {
2444 g_info = false;
2445 }
2446 else if (!strcasecmp(argv[i], "-threads"))
2447 {
2448 if (i < argc)
2449 {
2450 g_numthreads = atoi(argv[++i]);
2451 if (g_numthreads < 1)
2452 {
2453 Log("Expected value of at least 1 for '-threads'\n");
2454 Usage();
2455 }
2456 }
2457 else
2458 {
2459 Usage();
2460 }
2461 }
2462 #ifdef SYSTEM_WIN32
2463 else if (!strcasecmp(argv[i], "-estimate"))
2464 {
2465 g_estimate = true;
2466 }
2467 #endif
2468 #ifdef SYSTEM_POSIX
2469 else if (!strcasecmp(argv[i], "-noestimate"))
2470 {
2471 g_estimate = false;
2472 }
2473 #endif
2474 #ifdef ZHLT_NETVIS
2475 else if (!strcasecmp(argv[i], "-client"))
2476 {
2477 if (i < argc)
2478 {
2479 g_clientid = atoi(argv[++i]);
2480 }
2481 else
2482 {
2483 Usage();
2484 }
2485 }
2486 #endif
2487 else if (!strcasecmp(argv[i], "-nolerp"))
2488 {
2489 g_lerp_enabled = false;
2490 }
2491 else if (!strcasecmp(argv[i], "-chop"))
2492 {
2493 if (i < argc)
2494 {
2495 g_chop = atof(argv[++i]);
2496 if (g_chop < 1)
2497 {
2498 Log("expected value greater than 1 for '-chop'\n");
2499 Usage();
2500 }
2501 if (g_chop < 32)
2502 {
2503 Log("Warning: Chop values below 32 are not recommended.");
2504 }
2505 }
2506 else
2507 {
2508 Usage();
2509 }
2510 }
2511 else if (!strcasecmp(argv[i], "-texchop"))
2512 {
2513 if (i < argc)
2514 {
2515 g_texchop = atof(argv[++i]);
2516 if (g_texchop < 1)
2517 {
2518 Log("expected value greater than 1 for '-texchop'\n");
2519 Usage();
2520 }
2521 if (g_texchop < 32)
2522 {
2523 Log("Warning: texchop values below 16 are not recommended.");
2524 }
2525 }
2526 else
2527 {
2528 Usage();
2529 }
2530 }
2531 else if (!strcasecmp(argv[i], "-nodynbounce"))
2532 {
2533 g_bounce_dynamic = false;
2534 }
2535 else if (!strcasecmp(argv[i], "-notexscale"))
2536 {
2537 g_texscale = false;
2538 }
2539 else if (!strcasecmp(argv[i], "-nosubdivide"))
2540 {
2541 if (i < argc)
2542 {
2543 g_subdivide = false;
2544 }
2545 else
2546 {
2547 Usage();
2548 }
2549 }
2550 else if (!strcasecmp(argv[i], "-scale"))
2551 {
2552 if (i < argc)
2553 {
2554 // ------------------------------------------------------------------------
2555 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
2556 // Munge monochrome lightscale into colour one
2557 #ifdef HLRAD_WHOME
2558 i++;
2559 g_colour_lightscale[0] = (float)atof(argv[i]);
2560 g_colour_lightscale[1] = (float)atof(argv[i]);
2561 g_colour_lightscale[2] = (float)atof(argv[i]);
2562 #else
2563 g_lightscale = (float)atof(argv[++i]);
2564 #endif
2565 // ------------------------------------------------------------------------
2566 }
2567 else
2568 {
2569 Usage();
2570 }
2571 }
2572 else if (!strcasecmp(argv[i], "-falloff"))
2573 {
2574 if (i < argc)
2575 {
2576 g_falloff = (int)atoi(argv[++i]);
2577 if ((g_falloff != 1) && (g_falloff != 2))
2578 {
2579 Log("-falloff must be 1 or 2\n");
2580 Usage();
2581 }
2582 }
2583 else
2584 {
2585 Usage();
2586 }
2587 }
2588 else if (!strcasecmp(argv[i], "-fade"))
2589 {
2590 if (i < argc)
2591 {
2592 g_fade = (float)atof(argv[++i]);
2593 if (g_fade < 0.0)
2594 {
2595 Log("-fade must be a positive number\n");
2596 Usage();
2597 }
2598 }
2599 else
2600 {
2601 Usage();
2602 }
2603 }
2604 else if (!strcasecmp(argv[i], "-ambient"))
2605 {
2606 if (i + 3 < argc)
2607 {
2608 g_ambient[0] = (float)atof(argv[++i]) * 128;
2609 g_ambient[1] = (float)atof(argv[++i]) * 128;
2610 g_ambient[2] = (float)atof(argv[++i]) * 128;
2611 }
2612 else
2613 {
2614 Error("expected three color values after '-ambient'\n");
2615 }
2616 }
2617 else if (!strcasecmp(argv[i], "-maxlight"))
2618 {
2619 if (i < argc)
2620 {
2621 g_maxlight = (float)atof(argv[++i]) * 128;
2622 if (g_maxlight <= 0)
2623 {
2624 Log("expected positive value after '-maxlight'\n");
2625 Usage();
2626 }
2627 }
2628 else
2629 {
2630 Usage();
2631 }
2632 }
2633 else if (!strcasecmp(argv[i], "-lights"))
2634 {
2635 if (i < argc)
2636 {
2637 user_lights = argv[++i];
2638 }
2639 else
2640 {
2641 Usage();
2642 }
2643 }
2644 else if (!strcasecmp(argv[i], "-circus"))
2645 {
2646 g_circus = true;
2647 }
2648 else if (!strcasecmp(argv[i], "-noskyfix"))
2649 {
2650 g_sky_lighting_fix = false;
2651 }
2652 else if (!strcasecmp(argv[i], "-incremental"))
2653 {
2654 g_incremental = true;
2655 }
2656 else if (!strcasecmp(argv[i], "-chart"))
2657 {
2658 g_chart = true;
2659 }
2660 else if (!strcasecmp(argv[i], "-low"))
2661 {
2662 g_threadpriority = eThreadPriorityLow;
2663 }
2664 else if (!strcasecmp(argv[i], "-high"))
2665 {
2666 g_threadpriority = eThreadPriorityHigh;
2667 }
2668 else if (!strcasecmp(argv[i], "-nolog"))
2669 {
2670 g_log = false;
2671 }
2672 else if (!strcasecmp(argv[i], "-gamma"))
2673 {
2674 if (i < argc)
2675 {
2676 // ------------------------------------------------------------------------
2677 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
2678 // Munge values from original, monochrome gamma into colour gamma
2679 #ifdef HLRAD_WHOME
2680 i++;
2681 g_colour_qgamma[0] = (float)atof(argv[i]);
2682 g_colour_qgamma[1] = (float)atof(argv[i]);
2683 g_colour_qgamma[2] = (float)atof(argv[i]);
2684 #else
2685 g_qgamma = (float)atof(argv[++i]);
2686 #endif
2687 // ------------------------------------------------------------------------
2688 }
2689 else
2690 {
2691 Usage();
2692 }
2693 }
2694 else if (!strcasecmp(argv[i], "-dlight"))
2695 {
2696 if (i < argc)
2697 {
2698 g_dlight_threshold = (float)atof(argv[++i]);
2699 }
2700 else
2701 {
2702 Usage();
2703 }
2704 }
2705 else if (!strcasecmp(argv[i], "-extra"))
2706 {
2707 g_extra = true;
2708 }
2709 else if (!strcasecmp(argv[i], "-sky"))
2710 {
2711 if (i < argc)
2712 {
2713 g_indirect_sun = (float)atof(argv[++i]);
2714 }
2715 else
2716 {
2717 Usage();
2718 }
2719 }
2720 else if (!strcasecmp(argv[i], "-smooth"))
2721 {
2722 if (i < argc)
2723 {
2724 g_smoothing_value = atof(argv[++i]);
2725 }
2726 else
2727 {
2728 Usage();
2729 }
2730 }
2731 else if (!strcasecmp(argv[i], "-coring"))
2732 {
2733 if (i < argc)
2734 {
2735 g_coring = (float)atof(argv[++i]);
2736 }
2737 else
2738 {
2739 Usage();
2740 }
2741 }
2742 else if (!strcasecmp(argv[i], "-texdata"))
2743 {
2744 if (i < argc)
2745 {
2746 int x = atoi(argv[++i]) * 1024;
2747
2748 if (x > g_max_map_miptex)
2749 {
2750 g_max_map_miptex = x;
2751 }
2752 }
2753 else
2754 {
2755 Usage();
2756 }
2757 }
2758 else if (!strcasecmp(argv[i], "-lightdata"))
2759 {
2760 if (i < argc)
2761 {
2762 int x = atoi(argv[++i]) * 1024;
2763
2764 if (x > g_max_map_lightdata)
2765 {
2766 g_max_map_lightdata = x;
2767 }
2768 }
2769 else
2770 {
2771 Usage();
2772 }
2773 }
2774 else if (!strcasecmp(argv[i], "-sparse"))
2775 {
2776 g_method = eMethodSparseVismatrix;
2777 }
2778 else if (!strcasecmp(argv[i], "-nomatrix"))
2779 {
2780 g_method = eMethodNoVismatrix;
2781 }
2782 else if (!strcasecmp(argv[i], "-nopaque"))
2783 {
2784 g_allow_opaques = false;
2785 }
2786 else if (!strcasecmp(argv[i], "-dscale"))
2787 {
2788 if (i < argc)
2789 {
2790 g_direct_scale = (float)atof(argv[++i]);
2791 }
2792 else
2793 {
2794 Usage();
2795 }
2796 }
2797
2798 // ------------------------------------------------------------------------
2799 // Changes by Adam Foster - afoster@compsoc.man.ac.uk
2800 #ifdef HLRAD_WHOME
2801 else if (!strcasecmp(argv[i], "-colourgamma"))
2802 {
2803 if (i + 3 < argc)
2804 {
2805 g_colour_qgamma[0] = (float)atof(argv[++i]);
2806 g_colour_qgamma[1] = (float)atof(argv[++i]);
2807 g_colour_qgamma[2] = (float)atof(argv[++i]);
2808 }
2809 else
2810 {
2811 Error("expected three color values after '-colourgamma'\n");
2812 }
2813 }
2814 else if (!strcasecmp(argv[i], "-colourscale"))
2815 {
2816 if (i + 3 < argc)
2817 {
2818 g_colour_lightscale[0] = (float)atof(argv[++i]);
2819 g_colour_lightscale[1] = (float)atof(argv[++i]);
2820 g_colour_lightscale[2] = (float)atof(argv[++i]);
2821 }
2822 else
2823 {
2824 Error("expected three color values after '-colourscale'\n");
2825 }
2826 }
2827
2828 else if (!strcasecmp(argv[i], "-colourjitter"))
2829 {
2830 if (i + 3 < argc)
2831 {
2832 g_colour_jitter_hack[0] = (float)atof(argv[++i]);
2833 g_colour_jitter_hack[1] = (float)atof(argv[++i]);
2834 g_colour_jitter_hack[2] = (float)atof(argv[++i]);
2835 }
2836 else
2837 {
2838 Error("expected three color values after '-colourjitter'\n");
2839 }
2840 }
2841 else if (!strcasecmp(argv[i], "-jitter"))
2842 {
2843 if (i + 3 < argc)
2844 {
2845 g_jitter_hack[0] = (float)atof(argv[++i]);
2846 g_jitter_hack[1] = (float)atof(argv[++i]);
2847 g_jitter_hack[2] = (float)atof(argv[++i]);
2848 }
2849 else
2850 {
2851 Error("expected three color values after '-jitter'\n");
2852 }
2853 }
2854
2855 else if (!strcasecmp(argv[i], "-nodiffuse"))
2856 {
2857 g_diffuse_hack = false;
2858 }
2859 else if (!strcasecmp(argv[i], "-nospotpoints"))
2860 {
2861 g_spotlight_hack = false;
2862 }
2863 else if (!strcasecmp(argv[i], "-softlight"))
2864 {
2865 if (i + 4 < argc)
2866 {
2867 g_softlight_hack[0] = (float)atof(argv[++i]);
2868 g_softlight_hack[1] = (float)atof(argv[++i]);
2869 g_softlight_hack[2] = (float)atof(argv[++i]);
2870 g_softlight_hack_distance = (float)atof(argv[++i]);
2871 }
2872 else
2873 {
2874 Error("expected three color scalers and a distance after '-softlight'\n");
2875 }
2876 }
2877 #endif
2878 // ------------------------------------------------------------------------
2879
2880 #ifdef HLRAD_HULLU
2881 else if (!strcasecmp(argv[i], "-customshadowwithbounce"))
2882 {
2883 g_customshadow_with_bouncelight = true;
2884 }
2885 else if (!strcasecmp(argv[i], "-rgbtransfers"))
2886 {
2887 g_rgb_transfers = true;
2888 }
2889 #endif
2890
2891 #ifdef ZHLT_PROGRESSFILE // AJM
2892 else if (!strcasecmp(argv[i], "-progressfile"))
2893 {
2894 if (i < argc)
2895 {
2896 g_progressfile = argv[++i];
2897 }
2898 else
2899 {
2900 Log("Error: -progressfile: expected path to progress file following parameter\n");
2901 Usage();
2902 }
2903 }
2904 #endif
2905
2906 #ifdef HLRAD_FASTMATH
2907 else if (!strcasecmp(argv[i], "-oldmath"))
2908 {
2909 Warning("-oldmath was introduced as a temporary workaround to a bug in HLRAD and is no longer supported.\n Please remove it from your command line.\n");
2910 }
2911 #endif
2912 else if (argv[i][0] == '-')
2913 {
2914 Log("Unknown option \"%s\"\n", argv[i]);
2915 Usage();
2916 }
2917 else if (!mapname_from_arg)
2918 {
2919 mapname_from_arg = argv[i];
2920 }
2921 else
2922 {
2923 Log("Unknown option \"%s\"\n", argv[i]);
2924 Usage();
2925 }
2926 }
2927
2928 if (!mapname_from_arg)
2929 {
2930 Log("No mapname specified\n");
2931 Usage();
2932 }
2933
2934 g_smoothing_threshold = (float)cos(g_smoothing_value * (Q_PI / 180.0));
2935
2936 safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH);
2937 FlipSlashes(g_Mapname);
2938 StripExtension(g_Mapname);
2939 OpenLog(g_clientid);
2940 atexit(CloseLog);
2941 ThreadSetDefault();
2942 ThreadSetPriority(g_threadpriority);
2943 LogStart(argc, argv);
2944
2945 CheckForErrorLog();
2946
2947 dtexdata_init();
2948 atexit(dtexdata_free);
2949 // END INIT
2950
2951 // BEGIN RAD
2952 start = I_FloatTime();
2953
2954 // normalise maxlight
2955 if (g_maxlight > 255)
2956 g_maxlight = 255;
2957
2958 strcpy_s(g_source, mapname_from_arg);
2959 StripExtension(g_source);
2960 DefaultExtension(g_source, ".bsp");
2961 LoadBSPFile(g_source);
2962 ParseEntities();
2963 Settings();
2964 LoadRadFiles(g_Mapname, user_lights, argv[0]);
2965
2966 if (!g_visdatasize)
2967 {
2968 Warning("No vis information, direct lighting only.");
2969 g_numbounce = 0;
2970 g_ambient[0] = g_ambient[1] = g_ambient[2] = 0.1f;
2971 }
2972
2973 RadWorld();
2974
2975 FreeOpaqueFaceList();
2976 FreePatches();
2977
2978 if (g_chart)
2979 PrintBSPFileSizes();
2980
2981 WriteBSPFile(g_source);
2982
2983 end = I_FloatTime();
2984 LogTimeElapsed(end - start);
2985 // END RAD
2986
2987 return 0;
2988 }
2989