support -sRGBcolor for all _color keys
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42 CreateSunLight() - ydnar
43 this creates a sun light
44 */
45
46 static void CreateSunLight( sun_t *sun )
47 {
48         int                     i;
49         float           photons, d, angle, elevation, da, de;
50         vec3_t          direction;
51         light_t         *light;
52         
53         
54         /* dummy check */
55         if( sun == NULL )
56                 return;
57         
58         /* fixup */
59         if( sun->numSamples < 1 )
60                 sun->numSamples = 1;
61         
62         /* set photons */
63         photons = sun->photons / sun->numSamples;
64         
65         /* create the right number of suns */
66         for( i = 0; i < sun->numSamples; i++ )
67         {
68                 /* calculate sun direction */
69                 if( i == 0 )
70                         VectorCopy( sun->direction, direction );
71                 else
72                 {
73                         /*
74                                 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
75                                 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
76                                 sun->direction[ 2 ] = sin( elevation );
77                                 
78                                 xz_dist   = sqrt( x*x + z*z )
79                                 latitude  = atan2( xz_dist, y ) * RADIANS
80                                 longitude = atan2( x,       z ) * RADIANS
81                         */
82                         
83                         d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
84                         angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
85                         elevation = atan2( sun->direction[ 2 ], d );
86                         
87                         /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
88                         do
89                         {
90                                 da = (Random() * 2.0f - 1.0f) * sun->deviance;
91                                 de = (Random() * 2.0f - 1.0f) * sun->deviance;
92                         }
93                         while( (da * da + de * de) > (sun->deviance * sun->deviance) );
94                         angle += da;
95                         elevation += de;
96                         
97                         /* debug code */
98                         //%     Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
99                         
100                         /* create new vector */
101                         direction[ 0 ] = cos( angle ) * cos( elevation );
102                         direction[ 1 ] = sin( angle ) * cos( elevation );
103                         direction[ 2 ] = sin( elevation );
104                 }
105                 
106                 /* create a light */
107                 numSunLights++;
108                 light = safe_malloc( sizeof( *light ) );
109                 memset( light, 0, sizeof( *light ) );
110                 light->next = lights;
111                 lights = light;
112                 
113                 /* initialize the light */
114                 light->flags = LIGHT_SUN_DEFAULT;
115                 light->type = EMIT_SUN;
116                 light->fade = 1.0f;
117                 light->falloffTolerance = falloffTolerance;
118                 light->filterRadius = sun->filterRadius / sun->numSamples;
119                 light->style = noStyles ? LS_NORMAL : sun->style;
120                 
121                 /* set the light's position out to infinity */
122                 VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin );    /* MAX_WORLD_COORD * 2.0f */
123                 
124                 /* set the facing to be the inverse of the sun direction */
125                 VectorScale( direction, -1.0, light->normal );
126                 light->dist = DotProduct( light->origin, light->normal );
127                 
128                 /* set color and photons */
129                 VectorCopy( sun->color, light->color );
130                 light->photons = photons * skyScale;
131         }
132
133         /* another sun? */
134         if( sun->next != NULL )
135                 CreateSunLight( sun->next );
136 }
137
138
139
140 /*
141 CreateSkyLights() - ydnar
142 simulates sky light with multiple suns
143 */
144
145 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius, int style )
146 {
147         int                     i, j, numSuns;
148         int                     angleSteps, elevationSteps;
149         float           angle, elevation;
150         float           angleStep, elevationStep;
151         sun_t           sun;
152         
153         
154         /* dummy check */
155         if( value <= 0.0f || iterations < 2 )
156                 return;
157         
158         /* basic sun setup */
159         VectorCopy( color, sun.color );
160         sun.deviance = 0.0f;
161         sun.filterRadius = filterRadius;
162         sun.numSamples = 1;
163         sun.style = noStyles ? LS_NORMAL : style;
164         sun.next = NULL;
165         
166         /* setup */
167         elevationSteps = iterations - 1;
168         angleSteps = elevationSteps * 4;
169         angle = 0.0f;
170         elevationStep = DEG2RAD( 90.0f / iterations );  /* skip elevation 0 */
171         angleStep = DEG2RAD( 360.0f / angleSteps );
172         
173         /* calc individual sun brightness */
174         numSuns = angleSteps * elevationSteps + 1;
175         sun.photons = value / numSuns;
176         
177         /* iterate elevation */
178         elevation = elevationStep * 0.5f;
179         angle = 0.0f;
180         for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
181         {
182                 /* iterate angle */
183                 for( j = 0; j < angleSteps; j++ )
184                 {
185                         /* create sun */
186                         sun.direction[ 0 ] = cos( angle ) * cos( elevation );
187                         sun.direction[ 1 ] = sin( angle ) * cos( elevation );
188                         sun.direction[ 2 ] = sin( elevation );
189                         CreateSunLight( &sun );
190                         
191                         /* move */
192                         angle += angleStep;
193                 }
194                         
195                 /* move */
196                 elevation += elevationStep;
197                 angle += angleStep / elevationSteps;
198         }
199         
200         /* create vertical sun */
201         VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
202         CreateSunLight( &sun );
203         
204         /* short circuit */
205         return;
206 }
207
208
209
210 /*
211 CreateEntityLights()
212 creates lights from light entities
213 */
214
215 void CreateEntityLights( void )
216 {
217         int                             i, j;
218         light_t                 *light, *light2;
219         entity_t                *e, *e2;
220         const char              *name;
221         const char              *target;
222         vec3_t                  dest;
223         const char              *_color;
224         float                   intensity, scale, deviance, filterRadius;
225         int                             spawnflags, flags, numSamples;
226         qboolean                junior;
227
228         
229         /* go throught entity list and find lights */
230         for( i = 0; i < numEntities; i++ )
231         {
232                 /* get entity */
233                 e = &entities[ i ];
234                 name = ValueForKey( e, "classname" );
235                 
236                 /* ydnar: check for lightJunior */
237                 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
238                         junior = qtrue;
239                 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
240                         junior = qfalse;
241                 else
242                         continue;
243                 
244                 /* lights with target names (and therefore styles) are only parsed from BSP */
245                 target = ValueForKey( e, "targetname" );
246                 if( target[ 0 ] != '\0' && i >= numBSPEntities )
247                         continue;
248                 
249                 /* create a light */
250                 numPointLights++;
251                 light = safe_malloc( sizeof( *light ) );
252                 memset( light, 0, sizeof( *light ) );
253                 light->next = lights;
254                 lights = light;
255                 
256                 /* handle spawnflags */
257                 spawnflags = IntForKey( e, "spawnflags" );
258                 
259                 /* ydnar: quake 3+ light behavior */
260                 if( wolfLight == qfalse )
261                 {
262                         /* set default flags */
263                         flags = LIGHT_Q3A_DEFAULT;
264                         
265                         /* linear attenuation? */
266                         if( spawnflags & 1 )
267                         {
268                                 flags |= LIGHT_ATTEN_LINEAR;
269                                 flags &= ~LIGHT_ATTEN_ANGLE;
270                         }
271                         
272                         /* no angle attenuate? */
273                         if( spawnflags & 2 )
274                                 flags &= ~LIGHT_ATTEN_ANGLE;
275                 }
276                 
277                 /* ydnar: wolf light behavior */
278                 else
279                 {
280                         /* set default flags */
281                         flags = LIGHT_WOLF_DEFAULT;
282                         
283                         /* inverse distance squared attenuation? */
284                         if( spawnflags & 1 )
285                         {
286                                 flags &= ~LIGHT_ATTEN_LINEAR;
287                                 flags |= LIGHT_ATTEN_ANGLE;
288                         }
289                         
290                         /* angle attenuate? */
291                         if( spawnflags & 2 )
292                                 flags |= LIGHT_ATTEN_ANGLE;
293                 }
294                 
295                 /* other flags (borrowed from wolf) */
296                 
297                 /* wolf dark light? */
298                 if( (spawnflags & 4) || (spawnflags & 8) )
299                         flags |= LIGHT_DARK;
300                 
301                 /* nogrid? */
302                 if( spawnflags & 16 )
303                         flags &= ~LIGHT_GRID;
304                 
305                 /* junior? */
306                 if( junior )
307                 {
308                         flags |= LIGHT_GRID;
309                         flags &= ~LIGHT_SURFACES;
310                 }
311
312                 /* vortex: unnormalized? */
313                 if (spawnflags & 32)
314                         flags |= LIGHT_UNNORMALIZED;
315
316                 /* vortex: distance atten? */
317                 if (spawnflags & 64)
318                         flags |= LIGHT_ATTEN_DISTANCE;
319
320                 /* store the flags */
321                 light->flags = flags;
322                 
323                 /* ydnar: set fade key (from wolf) */
324                 light->fade = 1.0f;
325                 if( light->flags & LIGHT_ATTEN_LINEAR )
326                 {
327                         light->fade = FloatForKey( e, "fade" );
328                         if( light->fade == 0.0f )
329                                 light->fade = 1.0f;
330                 }
331                 
332                 /* ydnar: set angle scaling (from vlight) */
333                 light->angleScale = FloatForKey( e, "_anglescale" );
334                 if( light->angleScale != 0.0f )
335                         light->flags |= LIGHT_ATTEN_ANGLE;
336                 
337                 /* set origin */
338                 GetVectorForKey( e, "origin", light->origin);
339                 light->style = IntForKey( e, "_style" );
340                 if( light->style == LS_NORMAL )
341                         light->style = IntForKey( e, "style" );
342                 if( light->style < LS_NORMAL || light->style >= LS_NONE )
343                         Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
344                 
345                 if( light->style != LS_NORMAL ) {
346                         Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
347                 }
348
349                 /* set light intensity */
350                 intensity = FloatForKey( e, "_light" );
351                 if( intensity == 0.0f )
352                         intensity = FloatForKey( e, "light" );
353                 if( intensity == 0.0f)
354                         intensity = 300.0f;
355                 
356                 /* ydnar: set light scale (sof2) */
357                 scale = FloatForKey( e, "scale" );
358                 if( scale == 0.0f )
359                         scale = 1.0f;
360                 intensity *= scale;
361                 
362                 /* ydnar: get deviance and samples */
363                 deviance = FloatForKey( e, "_deviance" );
364                 if( deviance == 0.0f )
365                         deviance = FloatForKey( e, "_deviation" );
366                 if( deviance == 0.0f )
367                         deviance = FloatForKey( e, "_jitter" );
368                 numSamples = IntForKey( e, "_samples" );
369                 if( deviance < 0.0f || numSamples < 1 )
370                 {
371                         deviance = 0.0f;
372                         numSamples = 1;
373                 }
374                 intensity /= numSamples;
375                 
376                 /* ydnar: get filter radius */
377                 filterRadius = FloatForKey( e, "_filterradius" );
378                 if( filterRadius == 0.0f )
379                         filterRadius = FloatForKey( e, "_filteradius" );
380                 if( filterRadius == 0.0f )
381                         filterRadius = FloatForKey( e, "_filter" );
382                 if( filterRadius < 0.0f )
383                         filterRadius = 0.0f;
384                 light->filterRadius = filterRadius;
385                 
386                 /* set light color */
387                 _color = ValueForKey( e, "_color" );
388                 if( _color && _color[ 0 ] )
389                 {
390                         sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
391                         if (colorsRGB)
392                         {
393                                 light->color[0] = Image_LinearFloatFromsRGBFloat(light->color[0]);
394                                 light->color[1] = Image_LinearFloatFromsRGBFloat(light->color[1]);
395                                 light->color[2] = Image_LinearFloatFromsRGBFloat(light->color[2]);
396                         }
397                         if (!(light->flags & LIGHT_UNNORMALIZED))
398                         {
399                                 ColorNormalize( light->color, light->color );
400                         }
401                 }
402                 else
403                         light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
404
405                 light->extraDist = FloatForKey( e, "_extradist" );
406                 if(light->extraDist == 0.0f)
407                         light->extraDist = extraDist;
408                 
409                 light->photons = intensity;
410
411                 light->type = EMIT_POINT;
412                 
413                 /* set falloff threshold */
414                 light->falloffTolerance = falloffTolerance / numSamples;
415                 
416                 /* lights with a target will be spotlights */
417                 target = ValueForKey( e, "target" );
418                 if( target[ 0 ] )
419                 {
420                         float           radius;
421                         float           dist;
422                         sun_t           sun;
423                         const char      *_sun;
424                         
425                         
426                         /* get target */
427                         e2 = FindTargetEntity( target );
428                         if( e2 == NULL )
429                         {
430                                 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
431                                         (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
432                                 light->photons *= pointScale;
433                         }
434                         else
435                         {
436                                 /* not a point light */
437                                 numPointLights--;
438                                 numSpotLights++;
439                                 
440                                 /* make a spotlight */
441                                 GetVectorForKey( e2, "origin", dest );
442                                 VectorSubtract( dest, light->origin, light->normal );
443                                 dist = VectorNormalize( light->normal, light->normal );
444                                 radius = FloatForKey( e, "radius" );
445                                 if( !radius )
446                                         radius = 64;
447                                 if( !dist )
448                                         dist = 64;
449                                 light->radiusByDist = (radius + 16) / dist;
450                                 light->type = EMIT_SPOT;
451                                 
452                                 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
453                                 light->flags &= ~LIGHT_ATTEN_LINEAR;
454                                 light->flags |= LIGHT_ATTEN_ANGLE;
455                                 light->fade = 1.0f;
456                                 
457                                 /* ydnar: is this a sun? */
458                                 _sun = ValueForKey( e, "_sun" );
459                                 if( _sun[ 0 ] == '1' )
460                                 {
461                                         /* not a spot light */
462                                         numSpotLights--;
463                                         
464                                         /* unlink this light */
465                                         lights = light->next;
466                                         
467                                         /* make a sun */
468                                         VectorScale( light->normal, -1.0f, sun.direction );
469                                         VectorCopy( light->color, sun.color );
470                                         sun.photons = intensity;
471                                         sun.deviance = deviance / 180.0f * Q_PI;
472                                         sun.numSamples = numSamples;
473                                         sun.style = noStyles ? LS_NORMAL : light->style;
474                                         sun.next = NULL;
475                                         
476                                         /* make a sun light */
477                                         CreateSunLight( &sun );
478                                         
479                                         /* free original light */
480                                         free( light );
481                                         light = NULL;
482                                         
483                                         /* skip the rest of this love story */
484                                         continue;
485                                 }
486                                 else
487                                 {
488                                         light->photons *= spotScale;
489                                 }
490                         }
491                 }
492                 else
493                         light->photons *= pointScale;
494                 
495                 /* jitter the light */
496                 for( j = 1; j < numSamples; j++ )
497                 {
498                         /* create a light */
499                         light2 = safe_malloc( sizeof( *light ) );
500                         memcpy( light2, light, sizeof( *light ) );
501                         light2->next = lights;
502                         lights = light2;
503                         
504                         /* add to counts */
505                         if( light->type == EMIT_SPOT )
506                                 numSpotLights++;
507                         else
508                                 numPointLights++;
509                         
510                         /* jitter it */
511                         light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
512                         light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
513                         light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
514                 }
515         }
516 }
517
518
519
520 /*
521 CreateSurfaceLights() - ydnar
522 this hijacks the radiosity code to generate surface lights for first pass
523 */
524
525 #define APPROX_BOUNCE   1.0f
526
527 void CreateSurfaceLights( void )
528 {
529         int                                     i;
530         bspDrawSurface_t        *ds;
531         surfaceInfo_t           *info;
532         shaderInfo_t            *si;
533         light_t                         *light;
534         float                           subdivide;
535         vec3_t                          origin;
536         clipWork_t                      cw;
537         const char                      *nss;
538         
539         
540         /* get sun shader supressor */
541         nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
542         
543         /* walk the list of surfaces */
544         for( i = 0; i < numBSPDrawSurfaces; i++ )
545         {
546                 /* get surface and other bits */
547                 ds = &bspDrawSurfaces[ i ];
548                 info = &surfaceInfos[ i ];
549                 si = info->si;
550                 
551                 /* sunlight? */
552                 if( si->sun != NULL && nss[ 0 ] != '1' )
553                 {
554                         Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
555                         CreateSunLight( si->sun );
556                         si->sun = NULL; /* FIXME: leak! */
557                 }
558                 
559                 /* sky light? */
560                 if( si->skyLightValue > 0.0f )
561                 {
562                         Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
563                         CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
564                         si->skyLightValue = 0.0f;       /* FIXME: hack! */
565                 }
566                 
567                 /* try to early out */
568                 if( si->value <= 0 )
569                         continue;
570                 
571                 /* autosprite shaders become point lights */
572                 if( si->autosprite )
573                 {
574                         /* create an average xyz */
575                         VectorAdd( info->mins, info->maxs, origin );
576                         VectorScale( origin, 0.5f, origin );
577                         
578                         /* create a light */
579                         light = safe_malloc( sizeof( *light ) );
580                         memset( light, 0, sizeof( *light ) );
581                         light->next = lights;
582                         lights = light;
583                         
584                         /* set it up */
585                         light->flags = LIGHT_Q3A_DEFAULT;
586                         light->type = EMIT_POINT;
587                         light->photons = si->value * pointScale;
588                         light->fade = 1.0f;
589                         light->si = si;
590                         VectorCopy( origin, light->origin );
591                         VectorCopy( si->color, light->color );
592                         light->falloffTolerance = falloffTolerance;
593                         light->style = si->lightStyle;
594                         
595                         /* add to point light count and continue */
596                         numPointLights++;
597                         continue;
598                 }
599                 
600                 /* get subdivision amount */
601                 if( si->lightSubdivide > 0 )
602                         subdivide = si->lightSubdivide;
603                 else
604                         subdivide = defaultLightSubdivide;
605                 
606                 /* switch on type */
607                 switch( ds->surfaceType )
608                 {
609                         case MST_PLANAR:
610                         case MST_TRIANGLE_SOUP:
611                                 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
612                                 break;
613                         
614                         case MST_PATCH:
615                                 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
616                                 break;
617                         
618                         default:
619                                 break;
620                 }
621         }
622 }
623
624
625
626 /*
627 SetEntityOrigins()
628 find the offset values for inline models
629 */
630
631 void SetEntityOrigins( void )
632 {
633         int                                     i, j, k, f;
634         entity_t                        *e;
635         vec3_t                          origin;
636         const char                      *key;
637         int                                     modelnum;
638         bspModel_t                      *dm;
639         bspDrawSurface_t        *ds;
640         
641         
642         /* ydnar: copy drawverts into private storage for nefarious purposes */
643         yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
644         memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
645         
646         /* set the entity origins */
647         for( i = 0; i < numEntities; i++ )
648         {
649                 /* get entity and model */
650                 e = &entities[ i ];
651                 key = ValueForKey( e, "model" );
652                 if( key[ 0 ] != '*' )
653                         continue;
654                 modelnum = atoi( key + 1 );
655                 dm = &bspModels[ modelnum ];
656                 
657                 /* get entity origin */
658                 key = ValueForKey( e, "origin" );
659                 if( key[ 0 ] == '\0' )
660                         continue;
661                 GetVectorForKey( e, "origin", origin );
662                 
663                 /* set origin for all surfaces for this model */
664                 for( j = 0; j < dm->numBSPSurfaces; j++ )
665                 {
666                         /* get drawsurf */
667                         ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
668                         
669                         /* set its verts */
670                         for( k = 0; k < ds->numVerts; k++ )
671                         {
672                                 f = ds->firstVert + k;
673                                 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
674                         }
675                 }
676         }
677 }
678
679
680
681 /*
682 PointToPolygonFormFactor()
683 calculates the area over a point/normal hemisphere a winding covers
684 ydnar: fixme: there has to be a faster way to calculate this
685 without the expensive per-vert sqrts and transcendental functions
686 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
687 between this and the approximation
688 */
689
690 #define ONE_OVER_2PI    0.159154942f    //% (1.0f / (2.0f * 3.141592657f))
691
692 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
693 {
694         vec3_t          triVector, triNormal;
695         int                     i, j;
696         vec3_t          dirs[ MAX_POINTS_ON_WINDING ];
697         float           total;
698         float           dot, angle, facing;
699         
700         
701         /* this is expensive */
702         for( i = 0; i < w->numpoints; i++ )
703         {
704                 VectorSubtract( w->p[ i ], point, dirs[ i ] );
705                 VectorNormalize( dirs[ i ], dirs[ i ] );
706         }
707         
708         /* duplicate first vertex to avoid mod operation */
709         VectorCopy( dirs[ 0 ], dirs[ i ] );
710         
711         /* calculcate relative area */
712         total = 0.0f;
713         for( i = 0; i < w->numpoints; i++ )
714         {
715                 /* get a triangle */
716                 j = i + 1;
717                 dot = DotProduct( dirs[ i ], dirs[ j ] );
718                 
719                 /* roundoff can cause slight creep, which gives an IND from acos */
720                 if( dot > 1.0f )
721                         dot = 1.0f;
722                 else if( dot < -1.0f )
723                         dot = -1.0f;
724                 
725                 /* get the angle */
726                 angle = acos( dot );
727                 
728                 CrossProduct( dirs[ i ], dirs[ j ], triVector );
729                 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
730                         continue;
731                 
732                 facing = DotProduct( normal, triNormal );
733                 total += facing * angle;
734                 
735                 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
736                 if( total > 6.3f || total < -6.3f )
737                         return 0.0f;
738         }
739         
740         /* now in the range of 0 to 1 over the entire incoming hemisphere */
741         //%     total /= (2.0f * 3.141592657f);
742         total *= ONE_OVER_2PI;
743         return total;
744 }
745
746
747
748 /*
749 LightContributionTosample()
750 determines the amount of light reaching a sample (luxel or vertex) from a given light
751 */
752
753 int LightContributionToSample( trace_t *trace )
754 {
755         light_t                 *light;
756         float                   angle;
757         float                   add;
758         float                   dist;
759         float                   addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
760         qboolean                angledDeluxe = qtrue;
761         float                   colorBrightness;
762         qboolean                doAddDeluxe = qtrue;
763         
764         /* get light */
765         light = trace->light;
766         
767         /* clear color */
768         trace->forceSubsampling = 0.0f; /* to make sure */
769         VectorClear( trace->color );
770         VectorClear( trace->colorNoShadow );
771         VectorClear( trace->directionContribution );
772
773         colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
774         
775         /* ydnar: early out */
776         if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
777                 return 0;
778         
779         /* do some culling checks */
780         if( light->type != EMIT_SUN )
781         {
782                 /* MrE: if the light is behind the surface */
783                 if( trace->twoSided == qfalse )
784                         if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
785                                 return 0;
786                 
787                 /* ydnar: test pvs */
788                 if( !ClusterVisible( trace->cluster, light->cluster ) )
789                         return 0;
790         }
791         
792         /* exact point to polygon form factor */
793         if( light->type == EMIT_AREA )
794         {
795                 float           factor;
796                 float           d;
797                 vec3_t          pushedOrigin;
798                 
799                 /* project sample point into light plane */
800                 d = DotProduct( trace->origin, light->normal ) - light->dist;
801                 if( d < 3.0f )
802                 {
803                         /* sample point behind plane? */
804                         if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
805                                 return 0;
806                         
807                         /* sample plane coincident? */
808                         if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
809                                 return 0;
810                 }
811                 
812                 /* nudge the point so that it is clearly forward of the light */
813                 /* so that surfaces meeting a light emitter don't get black edges */
814                 if( d > -8.0f && d < 8.0f )
815                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
816                 else
817                         VectorCopy( trace->origin, pushedOrigin );
818                 
819                 /* get direction and distance */
820                 VectorCopy( light->origin, trace->end );
821                 dist = SetupTrace( trace );
822                 if( dist >= light->envelope )
823                         return 0;
824                 
825                 /* ptpff approximation */
826                 if( faster )
827                 {
828                         /* angle attenuation */
829                         angle = DotProduct( trace->normal, trace->direction );
830                         
831                         /* twosided lighting */
832                         if( trace->twoSided && angle < 0 )
833                         {
834                                 angle = -angle;
835
836                                 /* no deluxemap contribution from "other side" light */
837                                 doAddDeluxe = qfalse;
838                         }
839                         
840                         /* attenuate */
841                         angle *= -DotProduct( light->normal, trace->direction );
842                         if( angle == 0.0f )
843                                 return 0;
844                         else if( angle < 0.0f &&
845                                 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
846                         {
847                                 angle = -angle;
848
849                                 /* no deluxemap contribution from "other side" light */
850                                 doAddDeluxe = qfalse;
851                         }
852
853                         /* clamp the distance to prevent super hot spots */
854                         dist = sqrt(dist * dist + light->extraDist * light->extraDist);
855                         if( dist < 16.0f )
856                                 dist = 16.0f;
857
858                         add = light->photons / (dist * dist) * angle;
859
860                         if( deluxemap )
861                         {
862                                 if( angledDeluxe )
863                                         addDeluxe = light->photons / (dist * dist) * angle;
864                                 else
865                                         addDeluxe = light->photons / (dist * dist);
866                         }
867                 }
868                 else
869                 {
870                         /* calculate the contribution */
871                         factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
872                         if( factor == 0.0f )
873                                 return 0;
874                         else if( factor < 0.0f )
875                         {
876                                 /* twosided lighting */
877                                 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
878                                 {
879                                         factor = -factor;
880
881                                         /* push light origin to other side of the plane */
882                                         VectorMA( light->origin, -2.0f, light->normal, trace->end );
883                                         dist = SetupTrace( trace );
884                                         if( dist >= light->envelope )
885                                                 return 0;
886
887                                         /* no deluxemap contribution from "other side" light */
888                                         doAddDeluxe = qfalse;
889                                 }
890                                 else
891                                         return 0;
892                         }
893
894                         /* also don't deluxe if the direction is on the wrong side */
895                         if(DotProduct(trace->normal, trace->direction) < 0)
896                         {
897                                 /* no deluxemap contribution from "other side" light */
898                                 doAddDeluxe = qfalse;
899                         }
900                         
901                         /* ydnar: moved to here */
902                         add = factor * light->add;
903
904                         if( deluxemap )
905                                 addDeluxe = add;
906                 }
907         }
908         
909         /* point/spot lights */
910         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
911         {
912                 /* get direction and distance */
913                 VectorCopy( light->origin, trace->end );
914                 dist = SetupTrace( trace );
915                 if( dist >= light->envelope )
916                         return 0;
917
918                 /* clamp the distance to prevent super hot spots */
919                 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
920                 if( dist < 16.0f )
921                         dist = 16.0f;
922
923                 /* angle attenuation */
924                 if( light->flags & LIGHT_ATTEN_ANGLE )
925                 {
926                         /* standard Lambert attenuation */
927                         float dot = DotProduct( trace->normal, trace->direction ); 
928
929                         /* twosided lighting */
930                         if( trace->twoSided && dot < 0 )
931                         {
932                                 dot = -dot;
933
934                                 /* no deluxemap contribution from "other side" light */
935                                 doAddDeluxe = qfalse;
936                         }
937
938                         /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
939                         if( lightAngleHL )
940                         {
941                                 if( dot > 0.001f ) // skip coplanar
942                                 {
943                                         if( dot > 1.0f ) dot = 1.0f;
944                                         dot = ( dot * 0.5f ) + 0.5f;
945                                         dot *= dot;
946                                 }
947                                 else
948                                         dot = 0;
949                         }
950
951                         angle = dot;
952                 }
953                 else
954                         angle = 1.0f;
955
956                 if( light->angleScale != 0.0f )
957                 {
958                         angle /= light->angleScale;
959                         if( angle > 1.0f )
960                                 angle = 1.0f;
961                 }
962                 
963                 /* attenuate */
964                 if( light->flags & LIGHT_ATTEN_LINEAR )
965                 {
966                         add = angle * light->photons * linearScale - (dist * light->fade);
967                         if( add < 0.0f )
968                                 add = 0.0f;
969
970                         if( deluxemap )
971                         {
972                                 if( angledDeluxe )
973                                         addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
974                                 else
975                                         addDeluxe = light->photons * linearScale - (dist * light->fade);
976
977                                 if( addDeluxe < 0.0f )
978                                         addDeluxe = 0.0f;
979                         }
980                 }
981                 else
982                 {
983                         add = (light->photons / (dist * dist)) * angle;
984                         if( add < 0.0f )
985                                 add = 0.0f;
986
987                         if( deluxemap )
988                         {
989                                 if( angledDeluxe )
990                                         addDeluxe = (light->photons / (dist * dist)) * angle;
991                                 else
992                                         addDeluxe = (light->photons / (dist * dist));
993                         }
994
995                         if( addDeluxe < 0.0f )
996                                 addDeluxe = 0.0f;
997                 }
998                 
999                 /* handle spotlights */
1000                 if( light->type == EMIT_SPOT )
1001                 {
1002                         float   distByNormal, radiusAtDist, sampleRadius;
1003                         vec3_t  pointAtDist, distToSample;
1004         
1005                         /* do cone calculation */
1006                         distByNormal = -DotProduct( trace->displacement, light->normal );
1007                         if( distByNormal < 0.0f )
1008                                 return 0;
1009                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1010                         radiusAtDist = light->radiusByDist * distByNormal;
1011                         VectorSubtract( trace->origin, pointAtDist, distToSample );
1012                         sampleRadius = VectorLength( distToSample );
1013                         
1014                         /* outside the cone */
1015                         if( sampleRadius >= radiusAtDist )
1016                                 return 0;
1017                         
1018                         /* attenuate */
1019                         if( sampleRadius > (radiusAtDist - 32.0f) )
1020                         {
1021                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1022                                 if( add < 0.0f )
1023                                         add = 0.0f;
1024
1025                                 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1026
1027                                 if( addDeluxe < 0.0f )
1028                                         addDeluxe = 0.0f;
1029                         }
1030                 }
1031         }
1032         
1033         /* ydnar: sunlight */
1034         else if( light->type == EMIT_SUN )
1035         {
1036                 /* get origin and direction */
1037                 VectorAdd( trace->origin, light->origin, trace->end );
1038                 dist = SetupTrace( trace );
1039
1040                 /* angle attenuation */
1041                 if( light->flags & LIGHT_ATTEN_ANGLE )
1042                 {
1043                         /* standard Lambert attenuation */
1044                         float dot = DotProduct( trace->normal, trace->direction ); 
1045
1046                         /* twosided lighting */
1047                         if( trace->twoSided && dot < 0 )
1048                         {
1049                                 dot = -dot;
1050
1051                                 /* no deluxemap contribution from "other side" light */
1052                                 doAddDeluxe = qfalse;
1053                         }
1054
1055                         /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1056                         if( lightAngleHL )
1057                         {
1058                                 if( dot > 0.001f ) // skip coplanar
1059                                 {
1060                                         if( dot > 1.0f ) dot = 1.0f;
1061                                         dot = ( dot * 0.5f ) + 0.5f;
1062                                         dot *= dot;
1063                                 }
1064                                 else
1065                                         dot = 0;
1066                         }
1067                         
1068                         angle = dot;
1069                 }
1070                 else
1071                         angle = 1.0f;
1072                 
1073                 /* attenuate */
1074                 add = light->photons * angle;
1075
1076                 if( deluxemap )
1077                 {
1078                         if( angledDeluxe )
1079                                 addDeluxe = light->photons * angle;
1080                         else
1081                                 addDeluxe = light->photons;
1082
1083                         if( addDeluxe < 0.0f )
1084                                 addDeluxe = 0.0f;
1085                 }
1086
1087                 if( add <= 0.0f )
1088                         return 0;
1089
1090                 /* VorteX: set noShadow color */
1091                 VectorScale(light->color, add, trace->colorNoShadow);
1092
1093                 addDeluxe *= colorBrightness;
1094
1095                 if( bouncing )
1096                 {
1097                         addDeluxe *= addDeluxeBounceScale;
1098                         if( addDeluxe < 0.00390625f )
1099                                 addDeluxe = 0.00390625f;
1100                 }
1101
1102                 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1103                 
1104                 /* setup trace */
1105                 trace->testAll = qtrue;
1106                 VectorScale( light->color, add, trace->color );
1107                 
1108                 /* trace to point */
1109                 if( trace->testOcclusion && !trace->forceSunlight )
1110                 {
1111                         /* trace */
1112                         TraceLine( trace );
1113                         trace->forceSubsampling *= add;
1114                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
1115                         {
1116                                 VectorClear( trace->color );
1117                                 VectorClear( trace->directionContribution );
1118
1119                                 return -1;
1120                         }
1121                 }
1122                 
1123                 /* return to sender */
1124                 return 1;
1125         }
1126         else
1127                 Error("Light of undefined type!");
1128
1129         /* VorteX: set noShadow color */
1130         VectorScale(light->color, add, trace->colorNoShadow);
1131         
1132         /* ydnar: changed to a variable number */
1133         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1134                 return 0;
1135
1136         addDeluxe *= colorBrightness;
1137
1138         /* hack land: scale down the radiosity contribution to light directionality.
1139         Deluxemaps fusion many light directions into one. In a rtl process all lights
1140         would contribute individually to the bump map, so several light sources together
1141         would make it more directional (example: a yellow and red lights received from
1142         opposing sides would light one side in red and the other in blue, adding
1143         the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1144         neutralize each other making it look like having no direction.
1145         Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1146         is modifying the direction applied from directional lights, making it go closer and closer
1147         to the surface normal the bigger is the amount of radiosity received.
1148         So, for preserving the directional lights contributions, we scale down the radiosity
1149         contribution. It's a hack, but there's a reason behind it */
1150         if( bouncing )
1151         {
1152                 addDeluxe *= addDeluxeBounceScale;
1153                 /* better NOT increase it beyond the original value
1154                 if( addDeluxe < 0.00390625f )
1155                         addDeluxe = 0.00390625f;
1156                 */
1157         }
1158
1159         if(doAddDeluxe)
1160         {
1161                 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1162         }
1163         
1164         /* setup trace */
1165         trace->testAll = qfalse;
1166         VectorScale( light->color, add, trace->color );
1167         
1168         /* raytrace */
1169         TraceLine( trace );
1170         trace->forceSubsampling *= add;
1171         if( trace->passSolid || trace->opaque )
1172         {
1173                 VectorClear( trace->color );
1174                 VectorClear( trace->directionContribution );
1175
1176                 return -1;
1177         }
1178         
1179         /* return to sender */
1180         return 1;
1181 }
1182
1183
1184
1185 /*
1186 LightingAtSample()
1187 determines the amount of light reaching a sample (luxel or vertex)
1188 */
1189
1190 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1191 {
1192         int                             i, lightmapNum;
1193         
1194         
1195         /* clear colors */
1196         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1197                 VectorClear( colors[ lightmapNum ] );
1198         
1199         /* ydnar: normalmap */
1200         if( normalmap )
1201         {
1202                 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1203                 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1204                 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1205                 return;
1206         }
1207         
1208         /* ydnar: don't bounce ambient all the time */
1209         if( !bouncing )
1210                 VectorCopy( ambientColor, colors[ 0 ] );
1211         
1212         /* ydnar: trace to all the list of lights pre-stored in tw */
1213         for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1214         {
1215                 /* set light */
1216                 trace->light = trace->lights[ i ];
1217                 
1218                 /* style check */
1219                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1220                 {
1221                         if( styles[ lightmapNum ] == trace->light->style ||
1222                                 styles[ lightmapNum ] == LS_NONE )
1223                                 break;
1224                 }
1225                 
1226                 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1227                 if( lightmapNum >= MAX_LIGHTMAPS )
1228                         continue;
1229                 
1230                 /* sample light */
1231                 LightContributionToSample( trace );
1232                 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1233                         continue;
1234                 
1235                 /* handle negative light */
1236                 if( trace->light->flags & LIGHT_NEGATIVE )
1237                         VectorScale( trace->color, -1.0f, trace->color );
1238                 
1239                 /* set style */
1240                 styles[ lightmapNum ] = trace->light->style;
1241                 
1242                 /* add it */
1243                 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1244                 
1245                 /* cheap mode */
1246                 if( cheap &&
1247                         colors[ 0 ][ 0 ] >= 255.0f &&
1248                         colors[ 0 ][ 1 ] >= 255.0f &&
1249                         colors[ 0 ][ 2 ] >= 255.0f )
1250                         break;
1251         }
1252 }
1253
1254
1255
1256 /*
1257 LightContributionToPoint()
1258 for a given light, how much light/color reaches a given point in space (with no facing)
1259 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1260 */
1261
1262 int LightContributionToPoint( trace_t *trace )
1263 {
1264         light_t         *light;
1265         float           add, dist;
1266         
1267         
1268         /* get light */
1269         light = trace->light;
1270         
1271         /* clear color */
1272         VectorClear( trace->color );
1273         
1274         /* ydnar: early out */
1275         if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1276                 return qfalse;
1277         
1278         /* is this a sun? */
1279         if( light->type != EMIT_SUN )
1280         {
1281                 /* sun only? */
1282                 if( sunOnly )
1283                         return qfalse;
1284                 
1285                 /* test pvs */
1286                 if( !ClusterVisible( trace->cluster, light->cluster ) )
1287                         return qfalse;
1288         }
1289         
1290         /* ydnar: check origin against light's pvs envelope */
1291         if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1292                 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1293                 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1294         {
1295                 gridBoundsCulled++;
1296                 return qfalse;
1297         }
1298         
1299         /* set light origin */
1300         if( light->type == EMIT_SUN )
1301                 VectorAdd( trace->origin, light->origin, trace->end );
1302         else
1303                 VectorCopy( light->origin, trace->end );
1304         
1305         /* set direction */
1306         dist = SetupTrace( trace );
1307         
1308         /* test envelope */
1309         if( dist > light->envelope )
1310         {
1311                 gridEnvelopeCulled++;
1312                 return qfalse;
1313         }
1314         
1315         /* ptpff approximation */
1316         if( light->type == EMIT_AREA && faster )
1317         {
1318                 /* clamp the distance to prevent super hot spots */
1319                 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1320                 if( dist < 16.0f )
1321                         dist = 16.0f;
1322
1323                 /* attenuate */
1324                 add = light->photons / (dist * dist);
1325         }
1326         
1327         /* exact point to polygon form factor */
1328         else if( light->type == EMIT_AREA )
1329         {
1330                 float           factor, d;
1331                 vec3_t          pushedOrigin;
1332                 
1333                 
1334                 /* see if the point is behind the light */
1335                 d = DotProduct( trace->origin, light->normal ) - light->dist;
1336                 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1337                         return qfalse;
1338                 
1339                 /* nudge the point so that it is clearly forward of the light */
1340                 /* so that surfaces meeting a light emiter don't get black edges */
1341                 if( d > -8.0f && d < 8.0f )
1342                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
1343                 else
1344                         VectorCopy( trace->origin, pushedOrigin );
1345                 
1346                 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1347                 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1348                 if( factor == 0.0f )
1349                         return qfalse;
1350                 else if( factor < 0.0f )
1351                 {
1352                         if( light->flags & LIGHT_TWOSIDED )
1353                                 factor = -factor;
1354                         else
1355                                 return qfalse;
1356                 }
1357                 
1358                 /* ydnar: moved to here */
1359                 add = factor * light->add;
1360         }
1361         
1362         /* point/spot lights */
1363         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1364         {
1365                 /* clamp the distance to prevent super hot spots */
1366                 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1367                 if( dist < 16.0f )
1368                         dist = 16.0f;
1369                 
1370                 /* attenuate */
1371                 if( light->flags & LIGHT_ATTEN_LINEAR )
1372                 {
1373                         add = light->photons * linearScale - (dist * light->fade);
1374                         if( add < 0.0f )
1375                                 add = 0.0f;
1376                 }
1377                 else
1378                         add = light->photons / (dist * dist);
1379                 
1380                 /* handle spotlights */
1381                 if( light->type == EMIT_SPOT )
1382                 {
1383                         float   distByNormal, radiusAtDist, sampleRadius;
1384                         vec3_t  pointAtDist, distToSample;
1385                         
1386                         
1387                         /* do cone calculation */
1388                         distByNormal = -DotProduct( trace->displacement, light->normal );
1389                         if( distByNormal < 0.0f )
1390                                 return qfalse;
1391                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1392                         radiusAtDist = light->radiusByDist * distByNormal;
1393                         VectorSubtract( trace->origin, pointAtDist, distToSample );
1394                         sampleRadius = VectorLength( distToSample );
1395                         
1396                         /* outside the cone */
1397                         if( sampleRadius >= radiusAtDist )
1398                                 return qfalse;
1399                         
1400                         /* attenuate */
1401                         if( sampleRadius > (radiusAtDist - 32.0f) )
1402                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1403                 }
1404         }
1405         
1406         /* ydnar: sunlight */
1407         else if( light->type == EMIT_SUN )
1408         {
1409                 /* attenuate */
1410                 add = light->photons;
1411                 if( add <= 0.0f )
1412                         return qfalse;
1413                 
1414                 /* setup trace */
1415                 trace->testAll = qtrue;
1416                 VectorScale( light->color, add, trace->color );
1417                 
1418                 /* trace to point */
1419                 if( trace->testOcclusion && !trace->forceSunlight )
1420                 {
1421                         /* trace */
1422                         TraceLine( trace );
1423                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
1424                         {
1425                                 VectorClear( trace->color );
1426                                 return -1;
1427                         }
1428                 }
1429                 
1430                 /* return to sender */
1431                 return qtrue;
1432         }
1433         
1434         /* unknown light type */
1435         else
1436                 return qfalse;
1437         
1438         /* ydnar: changed to a variable number */
1439         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1440                 return qfalse;
1441         
1442         /* setup trace */
1443         trace->testAll = qfalse;
1444         VectorScale( light->color, add, trace->color );
1445         
1446         /* trace */
1447         TraceLine( trace );
1448         if( trace->passSolid )
1449         {
1450                 VectorClear( trace->color );
1451                 return qfalse;
1452         }
1453         
1454         /* we have a valid sample */
1455         return qtrue;
1456 }
1457
1458
1459
1460 /*
1461 TraceGrid()
1462 grid samples are for quickly determining the lighting
1463 of dynamically placed entities in the world
1464 */
1465
1466 #define MAX_CONTRIBUTIONS       32768
1467
1468 typedef struct
1469 {
1470         vec3_t          dir;
1471         vec3_t          color;
1472         vec3_t          ambient;
1473         int                     style;
1474 }
1475 contribution_t;
1476
1477 void TraceGrid( int num )
1478 {
1479         int                                             i, j, x, y, z, mod, numCon, numStyles;
1480         float                                   d, step;
1481         vec3_t                                  baseOrigin, cheapColor, color, thisdir;
1482         rawGridPoint_t                  *gp;
1483         bspGridPoint_t                  *bgp;
1484         contribution_t                  contributions[ MAX_CONTRIBUTIONS ];
1485         trace_t                                 trace;
1486         
1487         /* get grid points */
1488         gp = &rawGridPoints[ num ];
1489         bgp = &bspGridPoints[ num ];
1490         
1491         /* get grid origin */
1492         mod = num;
1493         z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1494         mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1495         y = mod / gridBounds[ 0 ];
1496         mod -= y * gridBounds[ 0 ];
1497         x = mod;
1498         
1499         trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1500         trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1501         trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1502         
1503         /* set inhibit sphere */
1504         if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1505                 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1506         else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1507                 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1508         else
1509                 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1510         
1511         /* find point cluster */
1512         trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1513         if( trace.cluster < 0 )
1514         {
1515                 /* try to nudge the origin around to find a valid point */
1516                 VectorCopy( trace.origin, baseOrigin );
1517                 for( step = 0; (step += 0.005) <= 1.0; )
1518                 {
1519                         VectorCopy( baseOrigin, trace.origin );
1520                         trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1521                         trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1522                         trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1523                                 
1524                         /* ydnar: changed to find cluster num */
1525                         trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1526                         if( trace.cluster >= 0 )
1527                                 break;
1528                 }
1529                 
1530                 /* can't find a valid point at all */
1531                 if( step > 1.0 )
1532                         return;
1533         }
1534         
1535         /* setup trace */
1536         trace.testOcclusion = !noTrace;
1537         trace.forceSunlight = qfalse;
1538         trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1539         trace.numSurfaces = 0;
1540         trace.surfaces = NULL;
1541         trace.numLights = 0;
1542         trace.lights = NULL;
1543         
1544         /* clear */
1545         numCon = 0;
1546         VectorClear( cheapColor );
1547         
1548         /* trace to all the lights, find the major light direction, and divide the
1549            total light between that along the direction and the remaining in the ambient */
1550         for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1551         {
1552                 float           addSize;
1553                 
1554                 
1555                 /* sample light */
1556                 if( !LightContributionToPoint( &trace ) )
1557                         continue;
1558                 
1559                 /* handle negative light */
1560                 if( trace.light->flags & LIGHT_NEGATIVE )
1561                         VectorScale( trace.color, -1.0f, trace.color );
1562                 
1563                 /* add a contribution */
1564                 VectorCopy( trace.color, contributions[ numCon ].color );
1565                 VectorCopy( trace.direction, contributions[ numCon ].dir );
1566                 VectorClear( contributions[ numCon ].ambient );
1567                 contributions[ numCon ].style = trace.light->style;
1568                 numCon++;
1569                 
1570                 /* push average direction around */
1571                 addSize = VectorLength( trace.color );
1572                 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1573                 
1574                 /* stop after a while */
1575                 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1576                         break;
1577                 
1578                 /* ydnar: cheap mode */
1579                 VectorAdd( cheapColor, trace.color, cheapColor );
1580                 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1581                         break;
1582         }
1583         
1584         /////// Floodlighting for point //////////////////
1585         //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1586         if( floodlighty )
1587         {
1588                 int k;
1589                 float addSize, f;
1590                 vec3_t dir = { 0, 0, 1 };
1591                 float ambientFrac = 0.25f;
1592
1593                 trace.testOcclusion = qtrue;
1594                 trace.forceSunlight = qfalse;
1595                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1596                 trace.testAll = qtrue;
1597
1598                 for( k = 0; k < 2; k++ )
1599                 {
1600                         if( k == 0 ) // upper hemisphere
1601                         {
1602                                 trace.normal[0] = 0;
1603                                 trace.normal[1] = 0;
1604                                 trace.normal[2] = 1;
1605                         }
1606                         else //lower hemisphere
1607                         {
1608                                 trace.normal[0] = 0;
1609                                 trace.normal[1] = 0;
1610                                 trace.normal[2] = -1;
1611                         }
1612
1613                         f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1614
1615                         /* add a fraction as pure ambient, half as top-down direction */
1616                         contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1617                         contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1618                         contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1619
1620                         contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1621                         contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1622                         contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1623
1624                         contributions[ numCon ].dir[0] = dir[0];
1625                         contributions[ numCon ].dir[1] = dir[1];
1626                         contributions[ numCon ].dir[2] = dir[2];
1627
1628                         contributions[ numCon ].style = 0;
1629
1630                         /* push average direction around */
1631                         addSize = VectorLength( contributions[ numCon ].color );
1632                         VectorMA( gp->dir, addSize, dir, gp->dir );
1633
1634                         numCon++;
1635                 }
1636         }
1637         /////////////////////
1638
1639         /* normalize to get primary light direction */
1640         VectorNormalize( gp->dir, thisdir );
1641         
1642         /* now that we have identified the primary light direction,
1643            go back and separate all the light into directed and ambient */
1644
1645         numStyles = 1;
1646         for( i = 0; i < numCon; i++ )
1647         {
1648                 /* get relative directed strength */
1649                 d = DotProduct( contributions[ i ].dir, thisdir );
1650                 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1651                 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1652                 if( d < 0.0f )
1653                         d = 0.0f;
1654                 
1655                 /* find appropriate style */
1656                 for( j = 0; j < numStyles; j++ )
1657                 {
1658                         if( gp->styles[ j ] == contributions[ i ].style )
1659                                 break;
1660                 }
1661                 
1662                 /* style not found? */
1663                 if( j >= numStyles )
1664                 {
1665                         /* add a new style */
1666                         if( numStyles < MAX_LIGHTMAPS )
1667                         {
1668                                 gp->styles[ numStyles ] = contributions[ i ].style;
1669                                 bgp->styles[ numStyles ] = contributions[ i ].style;
1670                                 numStyles++;
1671                                 //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1672                         }
1673                         
1674                         /* fallback */
1675                         else
1676                                 j = 0;
1677                 }
1678                 
1679                 /* add the directed color */
1680                 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1681                 
1682                 /* ambient light will be at 1/4 the value of directed light */
1683                 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1684                 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1685 //              d = 0.25f;
1686                 /* (Hobbes: always setting it to .25 is hardly any better) */
1687                 d = 0.25f * (1.0f - d);
1688                 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1689
1690                 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1691
1692 /*
1693  * div0:
1694  * the total light average = ambient value + 0.25 * sum of all directional values
1695  * we can also get the total light average as 0.25 * the sum of all contributions
1696  *
1697  * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1698  *
1699  * THIS YIELDS:
1700  * ambient == 0.25 * sum((1 - d_i) contribution_i)
1701  *
1702  * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1703  */
1704         }
1705         
1706         
1707         /* store off sample */
1708         for( i = 0; i < MAX_LIGHTMAPS; i++ )
1709         {
1710 #if 0
1711                 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1712                 if( !bouncing )
1713                         VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1714 #endif
1715                 
1716                 /* set minimum light and copy off to bytes */
1717                 VectorCopy( gp->ambient[ i ], color );
1718                 for( j = 0; j < 3; j++ )
1719                         if( color[ j ] < minGridLight[ j ] )
1720                                 color[ j ] = minGridLight[ j ];
1721
1722                 /* vortex: apply gridscale and gridambientscale here */
1723                 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1724                 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1725         }
1726         
1727         /* debug code */
1728         #if 0
1729                 //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1730                 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1731                         num,
1732                         gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1733                         gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1734         #endif
1735         
1736         /* store direction */
1737         NormalToLatLong( thisdir, bgp->latLong );
1738 }
1739
1740
1741
1742 /*
1743 SetupGrid()
1744 calculates the size of the lightgrid and allocates memory
1745 */
1746
1747 void SetupGrid( void )
1748 {
1749         int                     i, j;
1750         vec3_t          maxs, oldGridSize;
1751         const char      *value;
1752         char            temp[ 64 ];
1753         
1754          
1755         /* don't do this if not grid lighting */
1756         if( noGridLighting )
1757                 return;
1758         
1759         /* ydnar: set grid size */
1760         value = ValueForKey( &entities[ 0 ], "gridsize" );
1761         if( value[ 0 ] != '\0' )
1762                 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1763         
1764         /* quantize it */
1765         VectorCopy( gridSize, oldGridSize );
1766         for( i = 0; i < 3; i++ )
1767                 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1768         
1769         /* ydnar: increase gridSize until grid count is smaller than max allowed */
1770         numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1771         j = 0;
1772         while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1773         {
1774                 /* get world bounds */
1775                 for( i = 0; i < 3; i++ )
1776                 {
1777                         gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1778                         maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1779                         gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1780                 }
1781         
1782                 /* set grid size */
1783                 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1784                 
1785                 /* increase grid size a bit */
1786                 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1787                         gridSize[ j++ % 3 ] += 16.0f;
1788         }
1789         
1790         /* print it */
1791         Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1792         
1793         /* different? */
1794         if( !VectorCompare( gridSize, oldGridSize ) )
1795         {
1796                 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1797                 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1798                 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1799         }
1800         
1801         /* 2nd variable. fixme: is this silly? */
1802         numBSPGridPoints = numRawGridPoints;
1803         
1804         /* allocate lightgrid */
1805         rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1806         memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1807         
1808         if( bspGridPoints != NULL )
1809                 free( bspGridPoints );
1810         bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1811         memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1812         
1813         /* clear lightgrid */
1814         for( i = 0; i < numRawGridPoints; i++ )
1815         {
1816                 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1817                 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1818                 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1819                 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1820                 {
1821                         rawGridPoints[ i ].styles[ j ] = LS_NONE;
1822                         bspGridPoints[ i ].styles[ j ] = LS_NONE;
1823                 }
1824         }
1825         
1826         /* note it */
1827         Sys_Printf( "%9d grid points\n", numRawGridPoints );
1828 }
1829
1830
1831
1832 /*
1833 LightWorld()
1834 does what it says...
1835 */
1836
1837 void LightWorld( void )
1838 {
1839         vec3_t          color;
1840         float           f;
1841         int                     b, bt;
1842         qboolean        minVertex, minGrid;
1843         const char      *value;
1844         
1845
1846         /* ydnar: smooth normals */
1847         if( shade )
1848         {
1849                 Sys_Printf( "--- SmoothNormals ---\n" );
1850                 SmoothNormals();
1851         }
1852         
1853         /* determine the number of grid points */
1854         Sys_Printf( "--- SetupGrid ---\n" );
1855         SetupGrid();
1856         
1857         /* find the optional minimum lighting values */
1858         GetVectorForKey( &entities[ 0 ], "_color", color );
1859         if (colorsRGB)
1860         {
1861                 color[0] = Image_LinearFloatFromsRGBFloat(color[0]);
1862                 color[1] = Image_LinearFloatFromsRGBFloat(color[1]);
1863                 color[2] = Image_LinearFloatFromsRGBFloat(color[2]);
1864         }
1865         if( VectorLength( color ) == 0.0f )
1866                 VectorSet( color, 1.0, 1.0, 1.0 );
1867         
1868         /* ambient */
1869         f = FloatForKey( &entities[ 0 ], "_ambient" );
1870         if( f == 0.0f )
1871                 f = FloatForKey( &entities[ 0 ], "ambient" );
1872         VectorScale( color, f, ambientColor );
1873         
1874         /* minvertexlight */
1875         minVertex = qfalse;
1876         value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1877         if( value[ 0 ] != '\0' )
1878         {
1879                 minVertex = qtrue;
1880                 f = atof( value );
1881                 VectorScale( color, f, minVertexLight );
1882         }
1883         
1884         /* mingridlight */
1885         minGrid = qfalse;
1886         value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1887         if( value[ 0 ] != '\0' )
1888         {
1889                 minGrid = qtrue;
1890                 f = atof( value );
1891                 VectorScale( color, f, minGridLight );
1892         }
1893         
1894         /* minlight */
1895         value = ValueForKey( &entities[ 0 ], "_minlight" );
1896         if( value[ 0 ] != '\0' )
1897         {
1898                 f = atof( value );
1899                 VectorScale( color, f, minLight );
1900                 if( minVertex == qfalse )
1901                         VectorScale( color, f, minVertexLight );
1902                 if( minGrid == qfalse )
1903                         VectorScale( color, f, minGridLight );
1904         }
1905         
1906         /* create world lights */
1907         Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1908         CreateEntityLights();
1909         CreateSurfaceLights();
1910         Sys_Printf( "%9d point lights\n", numPointLights );
1911         Sys_Printf( "%9d spotlights\n", numSpotLights );
1912         Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1913         Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1914         
1915         /* calculate lightgrid */
1916         if( !noGridLighting )
1917         {
1918                 /* ydnar: set up light envelopes */
1919                 SetupEnvelopes( qtrue, fastgrid );
1920                 
1921                 Sys_Printf( "--- TraceGrid ---\n" );
1922                 inGrid = qtrue;
1923                 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1924                 inGrid = qfalse;
1925                 Sys_Printf( "%d x %d x %d = %d grid\n",
1926                         gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1927                 
1928                 /* ydnar: emit statistics on light culling */
1929                 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1930                 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1931         }
1932         
1933         /* slight optimization to remove a sqrt */
1934         subdivideThreshold *= subdivideThreshold;
1935         
1936         /* map the world luxels */
1937         Sys_Printf( "--- MapRawLightmap ---\n" );
1938         RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1939         Sys_Printf( "%9d luxels\n", numLuxels );
1940         Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1941         Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1942         
1943         /* dirty them up */
1944         if( dirty )
1945         {
1946                 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1947                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1948         }
1949         
1950         /* floodlight pass */
1951         FloodlightRawLightmaps();
1952
1953         /* ydnar: set up light envelopes */
1954         SetupEnvelopes( qfalse, fast );
1955         
1956         /* light up my world */
1957         lightsPlaneCulled = 0;
1958         lightsEnvelopeCulled = 0;
1959         lightsBoundsCulled = 0;
1960         lightsClusterCulled = 0;
1961         
1962         Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1963         RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1964         Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1965         
1966         StitchSurfaceLightmaps();
1967         
1968         Sys_Printf( "--- IlluminateVertexes ---\n" );
1969         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1970         Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1971         
1972         /* ydnar: emit statistics on light culling */
1973         Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1974         Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1975         Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1976         Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1977         
1978         /* radiosity */
1979         b = 1;
1980         bt = bounce;
1981         while( bounce > 0 )
1982         {
1983                 /* store off the bsp between bounces */
1984                 StoreSurfaceLightmaps();
1985                 UnparseEntities();
1986                 Sys_Printf( "Writing %s\n", source );
1987                 WriteBSPFile( source );
1988                 
1989                 /* note it */
1990                 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1991                 
1992                 /* flag bouncing */
1993                 bouncing = qtrue;
1994                 VectorClear( ambientColor );
1995                 floodlighty = qfalse;
1996                 
1997                 /* generate diffuse lights */
1998                 RadFreeLights();
1999                 RadCreateDiffuseLights();
2000                 
2001                 /* setup light envelopes */
2002                 SetupEnvelopes( qfalse, fastbounce );
2003                 if( numLights == 0 )
2004                 {
2005                         Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
2006                         break;
2007                 }
2008                 
2009                 /* add to lightgrid */
2010                 if( bouncegrid )
2011                 {
2012                         gridEnvelopeCulled = 0;
2013                         gridBoundsCulled = 0;
2014                         
2015                         Sys_Printf( "--- BounceGrid ---\n" );
2016                         inGrid = qtrue;
2017                         RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2018                         inGrid = qfalse;
2019                         Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2020                         Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2021                 }
2022                 
2023                 /* light up my world */
2024                 lightsPlaneCulled = 0;
2025                 lightsEnvelopeCulled = 0;
2026                 lightsBoundsCulled = 0;
2027                 lightsClusterCulled = 0;
2028                 
2029                 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2030                 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2031                 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2032                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2033                 
2034                 StitchSurfaceLightmaps();
2035                 
2036                 Sys_Printf( "--- IlluminateVertexes ---\n" );
2037                 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2038                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2039                 
2040                 /* ydnar: emit statistics on light culling */
2041                 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2042                 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2043                 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2044                 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2045                 
2046                 /* interate */
2047                 bounce--;
2048                 b++;
2049         }
2050 }
2051
2052
2053
2054 /*
2055 LightMain()
2056 main routine for light processing
2057 */
2058
2059 int LightMain( int argc, char **argv )
2060 {
2061         int                     i;
2062         float           f;
2063         char            mapSource[ 1024 ];
2064         const char      *value;
2065         int lightmapMergeSize = 0;
2066         qboolean        lightSamplesInsist = qfalse;
2067         
2068         
2069         /* note it */
2070         Sys_Printf( "--- Light ---\n" );
2071         Sys_Printf( "--- ProcessGameSpecific ---\n" );
2072
2073         /* set standard game flags */
2074         wolfLight = game->wolfLight;
2075         if (wolfLight == qtrue)
2076                 Sys_Printf( " lightning model: wolf\n" );
2077         else
2078                 Sys_Printf( " lightning model: quake3\n" );
2079
2080         lmCustomSize = game->lightmapSize;
2081         Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2082
2083         lightmapGamma = game->lightmapGamma;
2084         Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2085
2086         lightmapsRGB = game->lightmapsRGB;
2087         if(lightmapsRGB)
2088                 Sys_Printf( " lightmap colorspace: sRGB\n" );
2089         else
2090                 Sys_Printf( " lightmap colorspace: linear\n" );
2091
2092         texturesRGB = game->texturesRGB;
2093         if(texturesRGB)
2094                 Sys_Printf( " texture colorspace: sRGB\n" );
2095         else
2096                 Sys_Printf( " texture colorspace: linear\n" );
2097
2098         colorsRGB = game->colorsRGB;
2099         if(colorsRGB)
2100                 Sys_Printf( " _color colorspace: sRGB\n" );
2101         else
2102                 Sys_Printf( " _color colorspace: linear\n" );
2103
2104         lightmapCompensate = game->lightmapCompensate;
2105         Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2106
2107         lightmapExposure = game->lightmapExposure;
2108         Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2109
2110         gridScale = game->gridScale;
2111         Sys_Printf( " lightgrid scale: %f\n", gridScale );
2112
2113         gridAmbientScale = game->gridAmbientScale;
2114         Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2115
2116         lightAngleHL = game->lightAngleHL;
2117         if( lightAngleHL )
2118                 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2119
2120         noStyles = game->noStyles;
2121         if (noStyles == qtrue)
2122                 Sys_Printf( " shader lightstyles hack: disabled\n" );
2123         else
2124                 Sys_Printf( " shader lightstyles hack: enabled\n" );
2125
2126         patchShadows = game->patchShadows;
2127         if (patchShadows == qtrue)
2128                 Sys_Printf( " patch shadows: enabled\n" );
2129         else
2130                 Sys_Printf( " patch shadows: disabled\n" );
2131
2132         deluxemap = game->deluxeMap;
2133         deluxemode = game->deluxeMode;
2134         if (deluxemap == qtrue)
2135         {
2136                 if (deluxemode)
2137                         Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2138                 else
2139                         Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2140         }
2141         else
2142                 Sys_Printf( " deluxemapping: disabled\n" );
2143
2144         Sys_Printf( "--- ProcessCommandLine ---\n" );
2145         
2146         /* process commandline arguments */
2147         for( i = 1; i < (argc - 1); i++ )
2148         {
2149                 /* lightsource scaling */
2150                 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2151                 {
2152                         f = atof( argv[ i + 1 ] );
2153                         pointScale *= f;
2154                         spotScale *= f;
2155                         Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2156                         Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2157                         i++;
2158                 }
2159                 
2160                 else if( !strcmp( argv[ i ], "-spherical" ) || !strcmp( argv[ i ], "-sphericalscale" ) )
2161                 {
2162                         f = atof( argv[ i + 1 ] );
2163                         pointScale *= f;
2164                         Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2165                         i++;
2166                 }
2167                 
2168                 else if( !strcmp( argv[ i ], "-spot" ) || !strcmp( argv[ i ], "-spotscale" ) )
2169                 {
2170                         f = atof( argv[ i + 1 ] );
2171                         spotScale *= f;
2172                         Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2173                         i++;
2174                 }
2175                 
2176                 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2177                 {
2178                         f = atof( argv[ i + 1 ] );
2179                         areaScale *= f;
2180                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2181                         i++;
2182                 }
2183                 
2184                 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2185                 {
2186                         f = atof( argv[ i + 1 ] );
2187                         skyScale *= f;
2188                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2189                         i++;
2190                 }
2191                 
2192                 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2193                 {
2194                         f = atof( argv[ i + 1 ] );
2195                         bounceScale *= f;
2196                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2197                         i++;
2198                 }
2199                 
2200                 else if( !strcmp( argv[ i ], "-scale" ) )
2201                 {
2202                         f = atof( argv[ i + 1 ] );
2203                         pointScale *= f;
2204                         spotScale *= f;
2205                         areaScale *= f;
2206                         skyScale *= f;
2207                         bounceScale *= f;
2208                         Sys_Printf( "All light scaled by %f\n", f );
2209                         i++;
2210                 }
2211
2212                 else if( !strcmp( argv[ i ], "-gridscale" ) )
2213                 {
2214                         f = atof( argv[ i + 1 ] );
2215                         Sys_Printf( "Grid lightning scaled by %f\n", f );
2216                         gridScale *= f;
2217                         i++;
2218                 }
2219
2220                 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2221                 {
2222                         f = atof( argv[ i + 1 ] );
2223                         Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2224                         gridAmbientScale *= f;
2225                         i++;
2226                 }
2227
2228                 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2229                 {
2230                         f = atof( argv[ i + 1 ] );
2231                         if(f > 1) f = 1;
2232                         if(f < gridAmbientDirectionality) gridAmbientDirectionality = f;
2233                         Sys_Printf( "Grid directionality is %f\n", f );
2234                         gridDirectionality = f;
2235                         i++;
2236                 }
2237
2238                 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2239                 {
2240                         f = atof( argv[ i + 1 ] );
2241                         if(f < -1) f = -1;
2242                         if(f > gridDirectionality) gridDirectionality = f;
2243                         Sys_Printf( "Grid ambient directionality is %f\n", f );
2244                         gridAmbientDirectionality = f;
2245                         i++;
2246                 }
2247                 
2248                 else if( !strcmp( argv[ i ], "-gamma" ) )
2249                 {
2250                         f = atof( argv[ i + 1 ] );
2251                         lightmapGamma = f;
2252                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2253                         i++;
2254                 }
2255                 
2256                 else if( !strcmp( argv[ i ], "-sRGBlight" ) )
2257                 {
2258                         lightmapsRGB = qtrue;
2259                         Sys_Printf( "Lighting is in sRGB\n" );
2260                 }
2261
2262                 else if( !strcmp( argv[ i ], "-nosRGBlight" ) )
2263                 {
2264                         lightmapsRGB = qfalse;
2265                         Sys_Printf( "Lighting is linear\n" );
2266                 }
2267
2268                 else if( !strcmp( argv[ i ], "-sRGBtex" ) )
2269                 {
2270                         texturesRGB = qtrue;
2271                         Sys_Printf( "Textures are in sRGB\n" );
2272                 }
2273
2274                 else if( !strcmp( argv[ i ], "-nosRGBtex" ) )
2275                 {
2276                         texturesRGB = qfalse;
2277                         Sys_Printf( "Textures are linear\n" );
2278                 }
2279
2280                 else if( !strcmp( argv[ i ], "-sRGBcolor" ) )
2281                 {
2282                         colorsRGB = qtrue;
2283                         Sys_Printf( "Colors are in sRGB\n" );
2284                 }
2285
2286                 else if( !strcmp( argv[ i ], "-nosRGBcolor" ) )
2287                 {
2288                         colorsRGB = qfalse;
2289                         Sys_Printf( "Colors are linear\n" );
2290                 }
2291
2292                 else if( !strcmp( argv[ i ], "-exposure" ) )
2293                 {
2294                         f = atof( argv[ i + 1 ] );
2295                         lightmapExposure = f;
2296                         Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2297                         i++;
2298                 }
2299
2300                 else if( !strcmp( argv[ i ], "-compensate" ) )
2301                 {
2302                         f = atof( argv[ i + 1 ] );
2303                         if( f <= 0.0f )
2304                                 f = 1.0f;
2305                         lightmapCompensate = f;
2306                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2307                         i++;
2308                 }
2309                 
2310                 /* ydnar switches */
2311                 else if( !strcmp( argv[ i ], "-bounce" ) )
2312                 {
2313                         bounce = atoi( argv[ i + 1 ] );
2314                         if( bounce < 0 )
2315                                 bounce = 0;
2316                         else if( bounce > 0 )
2317                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2318                         i++;
2319                 }
2320                 
2321                 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2322                 {
2323                         superSample = atoi( argv[ i + 1 ] );
2324                         if( superSample < 1 )
2325                                 superSample = 1;
2326                         else if( superSample > 1 )
2327                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2328                         i++;
2329                 }
2330                 
2331                 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2332                 {
2333                         lightRandomSamples = qtrue;
2334                         Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2335                 }
2336                 
2337                 else if( !strcmp( argv[ i ], "-samples" ) )
2338                 {
2339                         if(*argv[i+1] == '+')
2340                                 lightSamplesInsist = qtrue;
2341                         else
2342                                 lightSamplesInsist = qfalse;
2343                         lightSamples = atoi( argv[ i + 1 ] );
2344                         if( lightSamples < 1 )
2345                                 lightSamples = 1;
2346                         else if( lightSamples > 1 )
2347                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2348                         i++;
2349                 }
2350                 
2351                 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2352                 {
2353                         lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2354                         if( lightSamplesSearchBoxSize <= 0 )
2355                                 lightSamplesSearchBoxSize = 1;
2356                         if( lightSamplesSearchBoxSize > 4 )
2357                                 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2358                         else if( lightSamplesSearchBoxSize != 1 )
2359                                 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2360                         i++;
2361                 }
2362
2363                 else if( !strcmp( argv[ i ], "-filter" ) )
2364                 {
2365                         filter = qtrue;
2366                         Sys_Printf( "Lightmap filtering enabled\n" );
2367                 }
2368                 
2369                 else if( !strcmp( argv[ i ], "-dark" ) )
2370                 {
2371                         dark = qtrue;
2372                         Sys_Printf( "Dark lightmap seams enabled\n" );
2373                 }
2374                 
2375                 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2376                 {
2377                         shadeAngleDegrees = atof( argv[ i + 1 ] );
2378                         if( shadeAngleDegrees < 0.0f )
2379                                 shadeAngleDegrees = 0.0f;
2380                         else if( shadeAngleDegrees > 0.0f )
2381                         {
2382                                 shade = qtrue;
2383                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2384                         }
2385                         i++;
2386                 }
2387                 
2388                 else if( !strcmp( argv[ i ], "-thresh" ) )
2389                 {
2390                         subdivideThreshold = atof( argv[ i + 1 ] );
2391                         if( subdivideThreshold < 0 )
2392                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2393                         else
2394                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2395                         i++;
2396                 }
2397                 
2398                 else if( !strcmp( argv[ i ], "-approx" ) )
2399                 {
2400                         approximateTolerance = atoi( argv[ i + 1 ] );
2401                         if( approximateTolerance < 0 )
2402                                 approximateTolerance = 0;
2403                         else if( approximateTolerance > 0 )
2404                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2405                         i++;
2406                 }
2407                 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2408                 {
2409                         deluxemap = qtrue;
2410                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
2411                 }
2412                 else if( !strcmp( argv[ i ], "-deluxemode" ))
2413                 {
2414                         deluxemode = atoi( argv[ i + 1 ] );
2415                         if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2416                         {
2417                                 Sys_Printf( "Generating modelspace deluxemaps\n" );
2418                                 deluxemode = 0;
2419                         }
2420                         else 
2421                                 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2422                         i++;
2423                 }
2424                 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2425                 {
2426                         deluxemap = qfalse;
2427                         Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2428                 }
2429                 else if( !strcmp( argv[ i ], "-external" ) )
2430                 {
2431                         externalLightmaps = qtrue;
2432                         Sys_Printf( "Storing all lightmaps externally\n" );
2433                 }
2434
2435                 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2436                 {
2437                         lmCustomSize = atoi( argv[ i + 1 ] );
2438                         
2439                         /* must be a power of 2 and greater than 2 */
2440                         if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2441                         {
2442                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2443                                 lmCustomSize = game->lightmapSize;
2444                         }
2445                         i++;
2446                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2447                         
2448                         /* enable external lightmaps */
2449                         if( lmCustomSize != game->lightmapSize )
2450                         {
2451                                 externalLightmaps = qtrue;
2452                                 Sys_Printf( "Storing all lightmaps externally\n" );
2453                         }
2454                 }
2455                 
2456                 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2457                 {
2458                         lmLimitSize = atoi( argv[ i + 1 ] );
2459                         
2460                         i++;
2461                         Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2462                 }
2463                 
2464                 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2465                 {
2466                         lmCustomDir = argv[i + 1];
2467                         i++;
2468                         Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2469                         externalLightmaps = qtrue;
2470                         Sys_Printf( "Storing all lightmaps externally\n" );
2471                 }
2472                 
2473                 /* ydnar: add this to suppress warnings */
2474                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
2475                 {
2476                         Sys_Printf( "Custom info parms enabled\n" );
2477                         useCustomInfoParms = qtrue;
2478                 }
2479                 
2480                 else if( !strcmp( argv[ i ], "-wolf" ) )
2481                 {
2482                         /* -game should already be set */
2483                         wolfLight = qtrue;
2484                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2485                 }
2486                 
2487                 else if( !strcmp( argv[ i ], "-q3" ) )
2488                 {
2489                         /* -game should already be set */
2490                         wolfLight = qfalse;
2491                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2492                 }
2493
2494                 else if( !strcmp( argv[ i ], "-extradist" ) )
2495                 {
2496                         extraDist = atof( argv[ i + 1 ] );
2497                         if( extraDist < 0 )
2498                                 extraDist = 0;
2499                         i++;
2500                         Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2501                 }
2502                 
2503                 else if( !strcmp( argv[ i ], "-sunonly" ) )
2504                 {
2505                         sunOnly = qtrue;
2506                         Sys_Printf( "Only computing sunlight\n" );
2507                 }
2508                 
2509                 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2510                 {
2511                         bounceOnly = qtrue;
2512                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2513                 }
2514                 
2515                 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2516                 {
2517                         noCollapse = qtrue;
2518                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2519                 }
2520
2521                 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2522                 {
2523                         lightmapSearchBlockSize = 1;
2524                         Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2525                 }
2526                 
2527                 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2528                 {
2529                         lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2530                         ++i;
2531                         Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2532                 }
2533                 
2534                 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2535                 {
2536                         lightmapSearchBlockSize = atoi(argv[i+1]);
2537                         ++i;
2538                         Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2539                 }
2540                 
2541                 else if( !strcmp( argv[ i ], "-shade" ) )
2542                 {
2543                         shade = qtrue;
2544                         Sys_Printf( "Phong shading enabled\n" );
2545                 }
2546                 
2547                 else if( !strcmp( argv[ i ], "-bouncegrid") )
2548                 {
2549                         bouncegrid = qtrue;
2550                         if( bounce > 0 )
2551                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2552                 }
2553                 
2554                 else if( !strcmp( argv[ i ], "-smooth" ) )
2555                 {
2556                         lightSamples = EXTRA_SCALE;
2557                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2558                 }
2559                 
2560                 else if( !strcmp( argv[ i ], "-fast" ) )
2561                 {
2562                         fast = qtrue;
2563                         fastgrid = qtrue;
2564                         fastbounce = qtrue;
2565                         Sys_Printf( "Fast mode enabled\n" );
2566                 }
2567                 
2568                 else if( !strcmp( argv[ i ], "-faster" ) )
2569                 {
2570                         faster = qtrue;
2571                         fast = qtrue;
2572                         fastgrid = qtrue;
2573                         fastbounce = qtrue;
2574                         Sys_Printf( "Faster mode enabled\n" );
2575                 }
2576                 
2577                 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2578                 {
2579                         fastgrid = qtrue;
2580                         Sys_Printf( "Fast grid lighting enabled\n" );
2581                 }
2582                 
2583                 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2584                 {
2585                         fastbounce = qtrue;
2586                         Sys_Printf( "Fast bounce mode enabled\n" );
2587                 }
2588                 
2589                 else if( !strcmp( argv[ i ], "-cheap" ) )
2590                 {
2591                         cheap = qtrue;
2592                         cheapgrid = qtrue;
2593                         Sys_Printf( "Cheap mode enabled\n" );
2594                 }
2595
2596                 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2597                 {
2598                         cheapgrid = qtrue;
2599                         Sys_Printf( "Cheap grid mode enabled\n" );
2600                 }
2601                 
2602                 else if( !strcmp( argv[ i ], "-normalmap" ) )
2603                 {
2604                         normalmap = qtrue;
2605                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2606                 }
2607                 
2608                 else if( !strcmp( argv[ i ], "-trisoup" ) )
2609                 {
2610                         trisoup = qtrue;
2611                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2612                 }
2613                 
2614                 else if( !strcmp( argv[ i ], "-debug" ) )
2615                 {
2616                         debug = qtrue;
2617                         Sys_Printf( "Lightmap debugging enabled\n" );
2618                 }
2619                 
2620                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2621                 {
2622                         debugSurfaces = qtrue;
2623                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2624                 }
2625                 
2626                 else if( !strcmp( argv[ i ], "-debugunused" ) )
2627                 {
2628                         debugUnused = qtrue;
2629                         Sys_Printf( "Unused luxel debugging enabled\n" );
2630                 }
2631
2632                 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2633                 {
2634                         debugAxis = qtrue;
2635                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2636                 }
2637                 
2638                 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2639                 {
2640                         debugCluster = qtrue;
2641                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2642                 }
2643                 
2644                 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2645                 {
2646                         debugOrigin = qtrue;
2647                         Sys_Printf( "Luxel origin debugging enabled\n" );
2648                 }
2649                 
2650                 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2651                 {
2652                         deluxemap = qtrue;
2653                         debugDeluxemap = qtrue;
2654                         Sys_Printf( "Deluxemap debugging enabled\n" );
2655                 }
2656                 
2657                 else if( !strcmp( argv[ i ], "-export" ) )
2658                 {
2659                         exportLightmaps = qtrue;
2660                         Sys_Printf( "Exporting lightmaps\n" );
2661                 }
2662                 
2663                 else if( !strcmp(argv[ i ], "-notrace" )) 
2664                 {
2665                         noTrace = qtrue;
2666                         Sys_Printf( "Shadow occlusion disabled\n" );
2667                 }
2668                 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2669                 {
2670                         patchShadows = qtrue;
2671                         Sys_Printf( "Patch shadow casting enabled\n" );
2672                 }
2673                 else if( !strcmp( argv[ i ], "-extra" ) )
2674                 {
2675                         superSample = EXTRA_SCALE;              /* ydnar */
2676                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2677                 }
2678                 else if( !strcmp( argv[ i ], "-extrawide" ) )
2679                 {
2680                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2681                         filter = qtrue;                                 /* ydnar */
2682                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2683                 }
2684                 else if( !strcmp( argv[ i ], "-samplesize" ) )
2685                 {
2686                         sampleSize = atoi( argv[ i + 1 ] );
2687                         if( sampleSize < 1 )
2688                                 sampleSize = 1;
2689                         i++;
2690                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2691                 }
2692                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2693                 {
2694                         minSampleSize = atoi( argv[ i + 1 ] );
2695                         if( minSampleSize < 1 )
2696                                 minSampleSize = 1;
2697                         i++;
2698                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2699                 }
2700                 else if( !strcmp( argv[ i ],  "-samplescale" ) )
2701                 {
2702                         sampleScale = atoi( argv[ i + 1 ] );
2703                         i++;
2704                         Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2705                 }
2706                 else if( !strcmp( argv[ i ], "-novertex" ) )
2707                 {
2708                         noVertexLighting = qtrue;
2709                         Sys_Printf( "Disabling vertex lighting\n" );
2710                 }
2711                 else if( !strcmp( argv[ i ], "-nogrid" ) )
2712                 {
2713                         noGridLighting = qtrue;
2714                         Sys_Printf( "Disabling grid lighting\n" );
2715                 }
2716                 else if( !strcmp( argv[ i ], "-border" ) )
2717                 {
2718                         lightmapBorder = qtrue;
2719                         Sys_Printf( "Adding debug border to lightmaps\n" );
2720                 }
2721                 else if( !strcmp( argv[ i ], "-nosurf" ) )
2722                 {
2723                         noSurfaces = qtrue;
2724                         Sys_Printf( "Not tracing against surfaces\n" );
2725                 }
2726                 else if( !strcmp( argv[ i ], "-dump" ) )
2727                 {
2728                         dump = qtrue;
2729                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2730                 }
2731                 else if( !strcmp( argv[ i ], "-lomem" ) )
2732                 {
2733                         loMem = qtrue;
2734                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2735                 }
2736                 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2737                 {
2738                         if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2739                         {
2740                                 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2741                                 if( lightAngleHL )
2742                                         Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2743                                 else
2744                                         Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2745                         }
2746                 }
2747                 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2748                 {
2749                         noStyles = qtrue;
2750                         Sys_Printf( "Disabling lightstyles\n" );
2751                 }
2752                 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2753                 {
2754                         noStyles = qfalse;
2755                         Sys_Printf( "Enabling lightstyles\n" );
2756                 }
2757                 else if( !strcmp( argv[ i ], "-cpma" ) )
2758                 {
2759                         cpmaHack = qtrue;
2760                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2761                 }
2762                 else if( !strcmp( argv[ i ], "-floodlight" ) )
2763                 {
2764                         floodlighty = qtrue;
2765                         Sys_Printf( "FloodLighting enabled\n" );
2766                 }
2767                 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2768                 {
2769                         debugnormals = qtrue;
2770                         Sys_Printf( "DebugNormals enabled\n" );
2771                 }
2772                 else if( !strcmp( argv[ i ], "-lowquality" ) )
2773                 {
2774                         floodlight_lowquality = qtrue;
2775                         Sys_Printf( "Low Quality FloodLighting enabled\n" );
2776                 }
2777                 
2778                 /* r7: dirtmapping */
2779                 else if( !strcmp( argv[ i ], "-dirty" ) )
2780                 {
2781                         dirty = qtrue;
2782                         Sys_Printf( "Dirtmapping enabled\n" );
2783                 }
2784                 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2785                 {
2786                         dirtDebug = qtrue;
2787                         Sys_Printf( "Dirtmap debugging enabled\n" );
2788                 }
2789                 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2790                 {
2791                         dirtMode = atoi( argv[ i + 1 ] );
2792                         if( dirtMode != 0 && dirtMode != 1 )
2793                                 dirtMode = 0;
2794                         if( dirtMode == 1 )
2795                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2796                         else
2797                                 Sys_Printf( "Enabling ordered dir mapping\n" );
2798                         i++;
2799                 }
2800                 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2801                 {
2802                         dirtDepth = atof( argv[ i + 1 ] );
2803                         if( dirtDepth <= 0.0f )
2804                                 dirtDepth = 128.0f;
2805                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2806                         i++;
2807                 }
2808                 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2809                 {
2810                         dirtScale = atof( argv[ i + 1 ] );
2811                         if( dirtScale <= 0.0f )
2812                                 dirtScale = 1.0f;
2813                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2814                         i++;
2815                 }
2816                 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2817                 {
2818                         dirtGain = atof( argv[ i + 1 ] );
2819                         if( dirtGain <= 0.0f )
2820                                 dirtGain = 1.0f;
2821                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2822                         i++;
2823                 }
2824                 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2825                 {
2826                         lightmapTriangleCheck = qtrue;
2827                 }
2828                 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2829                 {
2830                         lightmapExtraVisClusterNudge = qtrue;
2831                 }
2832                 else if( !strcmp( argv[ i ], "-fill" ) )
2833                 {
2834                         lightmapFill = qtrue;
2835                         Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2836                 }
2837                 /* unhandled args */
2838                 else
2839                 {
2840                         Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2841                 }
2842
2843         }
2844
2845         /* fix up samples count */
2846         if(lightRandomSamples)
2847         {
2848                 if(!lightSamplesInsist)
2849                 {
2850                         /* approximately match -samples in quality */
2851                         switch(lightSamples)
2852                         {
2853                                 /* somewhat okay */
2854                                 case 1:
2855                                 case 2:
2856                                         lightSamples = 16;
2857                                         Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2858                                         break;
2859
2860                                 /* good */
2861                    &nb