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