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