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