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