]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light.c
new option -extradist to improve lighting a bit, also a light entity field _extradist...
[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         
753         
754         /* get light */
755         light = trace->light;
756         
757         /* clear color */
758         VectorClear( trace->color );
759         VectorClear( trace->colorNoShadow );
760         
761         /* ydnar: early out */
762         if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
763                 return 0;
764         
765         /* do some culling checks */
766         if( light->type != EMIT_SUN )
767         {
768                 /* MrE: if the light is behind the surface */
769                 if( trace->twoSided == qfalse )
770                         if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
771                                 return 0;
772                 
773                 /* ydnar: test pvs */
774                 if( !ClusterVisible( trace->cluster, light->cluster ) )
775                         return 0;
776         }
777         
778         /* exact point to polygon form factor */
779         if( light->type == EMIT_AREA )
780         {
781                 float           factor;
782                 float           d;
783                 vec3_t          pushedOrigin;
784                 
785                 /* project sample point into light plane */
786                 d = DotProduct( trace->origin, light->normal ) - light->dist;
787                 if( d < 3.0f )
788                 {
789                         /* sample point behind plane? */
790                         if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
791                                 return 0;
792                         
793                         /* sample plane coincident? */
794                         if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
795                                 return 0;
796                 }
797                 
798                 /* nudge the point so that it is clearly forward of the light */
799                 /* so that surfaces meeting a light emiter don't get black edges */
800                 if( d > -8.0f && d < 8.0f )
801                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
802                 else
803                         VectorCopy( trace->origin, pushedOrigin );
804                 
805                 /* get direction and distance */
806                 VectorCopy( light->origin, trace->end );
807                 dist = SetupTrace( trace );
808                 if( dist >= light->envelope )
809                         return 0;
810                 
811                 /* ptpff approximation */
812                 if( faster )
813                 {
814                         /* angle attenuation */
815                         angle = DotProduct( trace->normal, trace->direction );
816                         
817                         /* twosided lighting */
818                         if( trace->twoSided )
819                                 angle = fabs( angle );
820                         
821                         /* attenuate */
822                         angle *= -DotProduct( light->normal, trace->direction );
823                         if( angle == 0.0f )
824                                 return 0;
825                         else if( angle < 0.0f &&
826                                 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
827                                 angle = -angle;
828
829                         /* clamp the distance to prevent super hot spots */
830                         dist = sqrt(dist * dist + light->extraDist * light->extraDist);
831                         if( dist < 16.0f )
832                                 dist = 16.0f;
833
834                         add = light->photons / (dist * dist) * angle;
835                 }
836                 else
837                 {
838                         /* calculate the contribution */
839                         factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
840                         if( factor == 0.0f )
841                                 return 0;
842                         else if( factor < 0.0f )
843                         {
844                                 /* twosided lighting */
845                                 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
846                                 {
847                                         factor = -factor;
848
849                                         /* push light origin to other side of the plane */
850                                         VectorMA( light->origin, -2.0f, light->normal, trace->end );
851                                         dist = SetupTrace( trace );
852                                         if( dist >= light->envelope )
853                                                 return 0;
854                                 }
855                                 else
856                                         return 0;
857                         }
858                         
859                         /* ydnar: moved to here */
860                         add = factor * light->add;
861                 }
862         }
863         
864         /* point/spot lights */
865         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
866         {
867                 /* get direction and distance */
868                 VectorCopy( light->origin, trace->end );
869                 dist = SetupTrace( trace );
870                 if( dist >= light->envelope )
871                         return 0;
872
873                 /* clamp the distance to prevent super hot spots */
874                 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
875                 if( dist < 16.0f )
876                         dist = 16.0f;
877
878                 /* angle attenuation */
879                 if( light->flags & LIGHT_ATTEN_ANGLE )
880                 {
881                         /* standard Lambert attenuation */
882                         float dot = DotProduct( trace->normal, trace->direction ); 
883
884                         /* twosided lighting */
885                         if( trace->twoSided )
886                                 dot = fabs( dot );
887
888                         /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
889                         if( lightAngleHL )
890                         {
891                                 if( dot > 0.001f ) // skip coplanar
892                                 {
893                                         if( dot > 1.0f ) dot = 1.0f;
894                                         dot = ( dot * 0.5f ) + 0.5f;
895                                         dot *= dot;
896                                 }
897                                 else
898                                         dot = 0;
899                         }
900
901                         angle = dot;
902                 }
903                 else
904                         angle = 1.0f;
905
906                 if( light->angleScale != 0.0f )
907                 {
908                         angle /= light->angleScale;
909                         if( angle > 1.0f )
910                                 angle = 1.0f;
911                 }
912                 
913                 /* attenuate */
914                 if( light->flags & LIGHT_ATTEN_LINEAR )
915                 {
916                         add = angle * light->photons * linearScale - (dist * light->fade);
917                         if( add < 0.0f )
918                                 add = 0.0f;
919                 }
920                 else
921                         add = (light->photons / (dist * dist)) * angle;
922                 
923                 /* handle spotlights */
924                 if( light->type == EMIT_SPOT )
925                 {
926                         float   distByNormal, radiusAtDist, sampleRadius;
927                         vec3_t  pointAtDist, distToSample;
928         
929                         /* do cone calculation */
930                         distByNormal = -DotProduct( trace->displacement, light->normal );
931                         if( distByNormal < 0.0f )
932                                 return 0;
933                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
934                         radiusAtDist = light->radiusByDist * distByNormal;
935                         VectorSubtract( trace->origin, pointAtDist, distToSample );
936                         sampleRadius = VectorLength( distToSample );
937                         
938                         /* outside the cone */
939                         if( sampleRadius >= radiusAtDist )
940                                 return 0;
941                         
942                         /* attenuate */
943                         if( sampleRadius > (radiusAtDist - 32.0f) )
944                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
945                 }
946         }
947         
948         /* ydnar: sunlight */
949         else if( light->type == EMIT_SUN )
950         {
951                 /* get origin and direction */
952                 VectorAdd( trace->origin, light->origin, trace->end );
953                 dist = SetupTrace( trace );
954
955                 /* angle attenuation */
956                 if( light->flags & LIGHT_ATTEN_ANGLE )
957                 {
958                         /* standard Lambert attenuation */
959                         float dot = DotProduct( trace->normal, trace->direction ); 
960
961                         /* twosided lighting */
962                         if( trace->twoSided )
963                                 dot = fabs( dot );
964
965                         /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
966                         if( lightAngleHL )
967                         {
968                                 if( dot > 0.001f ) // skip coplanar
969                                 {
970                                         if( dot > 1.0f ) dot = 1.0f;
971                                         dot = ( dot * 0.5f ) + 0.5f;
972                                         dot *= dot;
973                                 }
974                                 else
975                                         dot = 0;
976                         }
977                         
978                         angle = dot;
979                 }
980                 else
981                         angle = 1.0f;
982                 
983                 /* attenuate */
984                 add = light->photons * angle;
985                 if( add <= 0.0f )
986                         return 0;
987
988                 /* VorteX: set noShadow color */
989                 VectorScale(light->color, add, trace->colorNoShadow);
990                 
991                 /* setup trace */
992                 trace->testAll = qtrue;
993                 VectorScale( light->color, add, trace->color );
994                 
995                 /* trace to point */
996                 if( trace->testOcclusion && !trace->forceSunlight )
997                 {
998                         /* trace */
999                         TraceLine( trace );
1000                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
1001                         {
1002                                 VectorClear( trace->color );
1003                                 return -1;
1004                         }
1005                 }
1006                 
1007                 /* return to sender */
1008                 return 1;
1009         }
1010
1011         /* VorteX: set noShadow color */
1012         VectorScale(light->color, add, trace->colorNoShadow);
1013         
1014         /* ydnar: changed to a variable number */
1015         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1016                 return 0;
1017         
1018         /* setup trace */
1019         trace->testAll = qfalse;
1020         VectorScale( light->color, add, trace->color );
1021         
1022         /* raytrace */
1023         TraceLine( trace );
1024         if( trace->passSolid || trace->opaque )
1025         {
1026                 VectorClear( trace->color );
1027                 return -1;
1028         }
1029         
1030         /* return to sender */
1031         return 1;
1032 }
1033
1034
1035
1036 /*
1037 LightingAtSample()
1038 determines the amount of light reaching a sample (luxel or vertex)
1039 */
1040
1041 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1042 {
1043         int                             i, lightmapNum;
1044         
1045         
1046         /* clear colors */
1047         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1048                 VectorClear( colors[ lightmapNum ] );
1049         
1050         /* ydnar: normalmap */
1051         if( normalmap )
1052         {
1053                 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1054                 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1055                 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1056                 return;
1057         }
1058         
1059         /* ydnar: don't bounce ambient all the time */
1060         if( !bouncing )
1061                 VectorCopy( ambientColor, colors[ 0 ] );
1062         
1063         /* ydnar: trace to all the list of lights pre-stored in tw */
1064         for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1065         {
1066                 /* set light */
1067                 trace->light = trace->lights[ i ];
1068                 
1069                 /* style check */
1070                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1071                 {
1072                         if( styles[ lightmapNum ] == trace->light->style ||
1073                                 styles[ lightmapNum ] == LS_NONE )
1074                                 break;
1075                 }
1076                 
1077                 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1078                 if( lightmapNum >= MAX_LIGHTMAPS )
1079                         continue;
1080                 
1081                 /* sample light */
1082                 LightContributionToSample( trace );
1083                 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1084                         continue;
1085                 
1086                 /* handle negative light */
1087                 if( trace->light->flags & LIGHT_NEGATIVE )
1088                         VectorScale( trace->color, -1.0f, trace->color );
1089                 
1090                 /* set style */
1091                 styles[ lightmapNum ] = trace->light->style;
1092                 
1093                 /* add it */
1094                 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1095                 
1096                 /* cheap mode */
1097                 if( cheap &&
1098                         colors[ 0 ][ 0 ] >= 255.0f &&
1099                         colors[ 0 ][ 1 ] >= 255.0f &&
1100                         colors[ 0 ][ 2 ] >= 255.0f )
1101                         break;
1102         }
1103 }
1104
1105
1106
1107 /*
1108 LightContributionToPoint()
1109 for a given light, how much light/color reaches a given point in space (with no facing)
1110 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1111 */
1112
1113 int LightContributionToPoint( trace_t *trace )
1114 {
1115         light_t         *light;
1116         float           add, dist;
1117         
1118         
1119         /* get light */
1120         light = trace->light;
1121         
1122         /* clear color */
1123         VectorClear( trace->color );
1124         
1125         /* ydnar: early out */
1126         if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1127                 return qfalse;
1128         
1129         /* is this a sun? */
1130         if( light->type != EMIT_SUN )
1131         {
1132                 /* sun only? */
1133                 if( sunOnly )
1134                         return qfalse;
1135                 
1136                 /* test pvs */
1137                 if( !ClusterVisible( trace->cluster, light->cluster ) )
1138                         return qfalse;
1139         }
1140         
1141         /* ydnar: check origin against light's pvs envelope */
1142         if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1143                 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1144                 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1145         {
1146                 gridBoundsCulled++;
1147                 return qfalse;
1148         }
1149         
1150         /* set light origin */
1151         if( light->type == EMIT_SUN )
1152                 VectorAdd( trace->origin, light->origin, trace->end );
1153         else
1154                 VectorCopy( light->origin, trace->end );
1155         
1156         /* set direction */
1157         dist = SetupTrace( trace );
1158         
1159         /* test envelope */
1160         if( dist > light->envelope )
1161         {
1162                 gridEnvelopeCulled++;
1163                 return qfalse;
1164         }
1165         
1166         /* ptpff approximation */
1167         if( light->type == EMIT_AREA && faster )
1168         {
1169                 /* clamp the distance to prevent super hot spots */
1170                 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1171                 if( dist < 16.0f )
1172                         dist = 16.0f;
1173
1174                 /* attenuate */
1175                 add = light->photons / (dist * dist);
1176         }
1177         
1178         /* exact point to polygon form factor */
1179         else if( light->type == EMIT_AREA )
1180         {
1181                 float           factor, d;
1182                 vec3_t          pushedOrigin;
1183                 
1184                 
1185                 /* see if the point is behind the light */
1186                 d = DotProduct( trace->origin, light->normal ) - light->dist;
1187                 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1188                         return qfalse;
1189                 
1190                 /* nudge the point so that it is clearly forward of the light */
1191                 /* so that surfaces meeting a light emiter don't get black edges */
1192                 if( d > -8.0f && d < 8.0f )
1193                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
1194                 else
1195                         VectorCopy( trace->origin, pushedOrigin );
1196                 
1197                 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1198                 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1199                 if( factor == 0.0f )
1200                         return qfalse;
1201                 else if( factor < 0.0f )
1202                 {
1203                         if( light->flags & LIGHT_TWOSIDED )
1204                                 factor = -factor;
1205                         else
1206                                 return qfalse;
1207                 }
1208                 
1209                 /* ydnar: moved to here */
1210                 add = factor * light->add;
1211         }
1212         
1213         /* point/spot lights */
1214         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1215         {
1216                 /* clamp the distance to prevent super hot spots */
1217                 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1218                 if( dist < 16.0f )
1219                         dist = 16.0f;
1220                 
1221                 /* attenuate */
1222                 if( light->flags & LIGHT_ATTEN_LINEAR )
1223                 {
1224                         add = light->photons * linearScale - (dist * light->fade);
1225                         if( add < 0.0f )
1226                                 add = 0.0f;
1227                 }
1228                 else
1229                         add = light->photons / (dist * dist);
1230                 
1231                 /* handle spotlights */
1232                 if( light->type == EMIT_SPOT )
1233                 {
1234                         float   distByNormal, radiusAtDist, sampleRadius;
1235                         vec3_t  pointAtDist, distToSample;
1236                         
1237                         
1238                         /* do cone calculation */
1239                         distByNormal = -DotProduct( trace->displacement, light->normal );
1240                         if( distByNormal < 0.0f )
1241                                 return qfalse;
1242                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1243                         radiusAtDist = light->radiusByDist * distByNormal;
1244                         VectorSubtract( trace->origin, pointAtDist, distToSample );
1245                         sampleRadius = VectorLength( distToSample );
1246                         
1247                         /* outside the cone */
1248                         if( sampleRadius >= radiusAtDist )
1249                                 return qfalse;
1250                         
1251                         /* attenuate */
1252                         if( sampleRadius > (radiusAtDist - 32.0f) )
1253                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1254                 }
1255         }
1256         
1257         /* ydnar: sunlight */
1258         else if( light->type == EMIT_SUN )
1259         {
1260                 /* attenuate */
1261                 add = light->photons;
1262                 if( add <= 0.0f )
1263                         return qfalse;
1264                 
1265                 /* setup trace */
1266                 trace->testAll = qtrue;
1267                 VectorScale( light->color, add, trace->color );
1268                 
1269                 /* trace to point */
1270                 if( trace->testOcclusion && !trace->forceSunlight )
1271                 {
1272                         /* trace */
1273                         TraceLine( trace );
1274                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
1275                         {
1276                                 VectorClear( trace->color );
1277                                 return -1;
1278                         }
1279                 }
1280                 
1281                 /* return to sender */
1282                 return qtrue;
1283         }
1284         
1285         /* unknown light type */
1286         else
1287                 return qfalse;
1288         
1289         /* ydnar: changed to a variable number */
1290         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1291                 return qfalse;
1292         
1293         /* setup trace */
1294         trace->testAll = qfalse;
1295         VectorScale( light->color, add, trace->color );
1296         
1297         /* trace */
1298         TraceLine( trace );
1299         if( trace->passSolid )
1300         {
1301                 VectorClear( trace->color );
1302                 return qfalse;
1303         }
1304         
1305         /* we have a valid sample */
1306         return qtrue;
1307 }
1308
1309
1310
1311 /*
1312 TraceGrid()
1313 grid samples are for quickly determining the lighting
1314 of dynamically placed entities in the world
1315 */
1316
1317 #define MAX_CONTRIBUTIONS       32768
1318
1319 typedef struct
1320 {
1321         vec3_t          dir;
1322         vec3_t          color;
1323         int                     style;
1324 }
1325 contribution_t;
1326
1327 void TraceGrid( int num )
1328 {
1329         int                                             i, j, x, y, z, mod, numCon, numStyles;
1330         float                                   d, step;
1331         vec3_t                                  baseOrigin, cheapColor, color, thisdir;
1332         rawGridPoint_t                  *gp;
1333         bspGridPoint_t                  *bgp;
1334         contribution_t                  contributions[ MAX_CONTRIBUTIONS ];
1335         trace_t                                 trace;
1336         
1337         /* get grid points */
1338         gp = &rawGridPoints[ num ];
1339         bgp = &bspGridPoints[ num ];
1340         
1341         /* get grid origin */
1342         mod = num;
1343         z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1344         mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1345         y = mod / gridBounds[ 0 ];
1346         mod -= y * gridBounds[ 0 ];
1347         x = mod;
1348         
1349         trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1350         trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1351         trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1352         
1353         /* set inhibit sphere */
1354         if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1355                 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1356         else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1357                 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1358         else
1359                 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1360         
1361         /* find point cluster */
1362         trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1363         if( trace.cluster < 0 )
1364         {
1365                 /* try to nudge the origin around to find a valid point */
1366                 VectorCopy( trace.origin, baseOrigin );
1367                 for( step = 0; (step += 0.005) <= 1.0; )
1368                 {
1369                         VectorCopy( baseOrigin, trace.origin );
1370                         trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1371                         trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1372                         trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1373                                 
1374                         /* ydnar: changed to find cluster num */
1375                         trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1376                         if( trace.cluster >= 0 )
1377                                 break;
1378                 }
1379                 
1380                 /* can't find a valid point at all */
1381                 if( step > 1.0 )
1382                         return;
1383         }
1384         
1385         /* setup trace */
1386         trace.testOcclusion = !noTrace;
1387         trace.forceSunlight = qfalse;
1388         trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1389         trace.numSurfaces = 0;
1390         trace.surfaces = NULL;
1391         trace.numLights = 0;
1392         trace.lights = NULL;
1393         
1394         /* clear */
1395         numCon = 0;
1396         VectorClear( cheapColor );
1397         
1398         /* trace to all the lights, find the major light direction, and divide the
1399            total light between that along the direction and the remaining in the ambient */
1400         for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1401         {
1402                 float           addSize;
1403                 
1404                 
1405                 /* sample light */
1406                 if( !LightContributionToPoint( &trace ) )
1407                         continue;
1408                 
1409                 /* handle negative light */
1410                 if( trace.light->flags & LIGHT_NEGATIVE )
1411                         VectorScale( trace.color, -1.0f, trace.color );
1412                 
1413                 /* add a contribution */
1414                 VectorCopy( trace.color, contributions[ numCon ].color );
1415                 VectorCopy( trace.direction, contributions[ numCon ].dir );
1416                 contributions[ numCon ].style = trace.light->style;
1417                 numCon++;
1418                 
1419                 /* push average direction around */
1420                 addSize = VectorLength( trace.color );
1421                 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1422                 
1423                 /* stop after a while */
1424                 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1425                         break;
1426                 
1427                 /* ydnar: cheap mode */
1428                 VectorAdd( cheapColor, trace.color, cheapColor );
1429                 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1430                         break;
1431         }
1432         
1433         /////// Floodlighting for point //////////////////
1434         //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1435         if (floodlighty)
1436         {
1437                 int q;
1438                 float addSize,f;
1439                 vec3_t col,dir;
1440                 col[0]=col[1]=col[2]=floodlightIntensity;
1441                 dir[0]=dir[1]=0;
1442                 dir[2]=1;
1443
1444                 trace.testOcclusion = qtrue;
1445                 trace.forceSunlight = qfalse;
1446                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1447                 trace.testAll = qtrue;
1448
1449                 for (q=0;q<2;q++)
1450                 {
1451                         if (q==0) //upper hemisphere
1452                         {
1453                                 trace.normal[0]=0;
1454                                 trace.normal[1]=0;
1455                                 trace.normal[2]=1;
1456                         }
1457                         else //lower hemisphere
1458                         {
1459                                 trace.normal[0]=0;
1460                                 trace.normal[1]=0;
1461                                 trace.normal[2]=-1;
1462                         }
1463
1464                         f = FloodLightForSample(&trace, floodlightDistance, floodlight_lowquality);
1465
1466                         contributions[ numCon ].color[0]=col[0]*f;
1467                         contributions[ numCon ].color[1]=col[1]*f;
1468                         contributions[ numCon ].color[2]=col[2]*f;
1469
1470                         contributions[ numCon ].dir[0]=dir[0];
1471                         contributions[ numCon ].dir[1]=dir[1];
1472                         contributions[ numCon ].dir[2]=dir[2];
1473
1474                         contributions[ numCon ].style = 0;
1475                         numCon++;
1476                         /* push average direction around */
1477                         addSize = VectorLength( col );
1478                         VectorMA( gp->dir, addSize, dir, gp->dir );
1479                 }
1480         }
1481         /////////////////////
1482
1483         /* normalize to get primary light direction */
1484         VectorNormalize( gp->dir, thisdir );
1485         
1486         /* now that we have identified the primary light direction,
1487            go back and separate all the light into directed and ambient */
1488
1489         numStyles = 1;
1490         for( i = 0; i < numCon; i++ )
1491         {
1492                 /* get relative directed strength */
1493                 d = DotProduct( contributions[ i ].dir, thisdir );
1494                 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1495                 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1496                 if( d < 0.0f )
1497                         d = 0.0f;
1498                 
1499                 /* find appropriate style */
1500                 for( j = 0; j < numStyles; j++ )
1501                 {
1502                         if( gp->styles[ j ] == contributions[ i ].style )
1503                                 break;
1504                 }
1505                 
1506                 /* style not found? */
1507                 if( j >= numStyles )
1508                 {
1509                         /* add a new style */
1510                         if( numStyles < MAX_LIGHTMAPS )
1511                         {
1512                                 gp->styles[ numStyles ] = contributions[ i ].style;
1513                                 bgp->styles[ numStyles ] = contributions[ i ].style;
1514                                 numStyles++;
1515                                 //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1516                         }
1517                         
1518                         /* fallback */
1519                         else
1520                                 j = 0;
1521                 }
1522                 
1523                 /* add the directed color */
1524                 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1525                 
1526                 /* ambient light will be at 1/4 the value of directed light */
1527                 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1528                 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1529 //              d = 0.25f;
1530                 /* (Hobbes: always setting it to .25 is hardly any better) */
1531                 d = 0.25f * (1.0f - d);
1532                 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1533
1534 /*
1535  * div0:
1536  * the total light average = ambient value + 0.25 * sum of all directional values
1537  * we can also get the total light average as 0.25 * the sum of all contributions
1538  *
1539  * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1540  *
1541  * THIS YIELDS:
1542  * ambient == 0.25 * sum((1 - d_i) contribution_i)
1543  *
1544  * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1545  */
1546         }
1547         
1548         
1549         /* store off sample */
1550         for( i = 0; i < MAX_LIGHTMAPS; i++ )
1551         {
1552 #if 0
1553                 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1554                 if( !bouncing )
1555                         VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1556 #endif
1557                 
1558                 /* set minimum light and copy off to bytes */
1559                 VectorCopy( gp->ambient[ i ], color );
1560                 for( j = 0; j < 3; j++ )
1561                         if( color[ j ] < minGridLight[ j ] )
1562                                 color[ j ] = minGridLight[ j ];
1563
1564                 /* vortex: apply gridscale and gridambientscale here */
1565                 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1566                 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1567         }
1568         
1569         /* debug code */
1570         #if 0
1571                 //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1572                 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1573                         num,
1574                         gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1575                         gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1576         #endif
1577         
1578         /* store direction */
1579         NormalToLatLong( thisdir, bgp->latLong );
1580 }
1581
1582
1583
1584 /*
1585 SetupGrid()
1586 calculates the size of the lightgrid and allocates memory
1587 */
1588
1589 void SetupGrid( void )
1590 {
1591         int                     i, j;
1592         vec3_t          maxs, oldGridSize;
1593         const char      *value;
1594         char            temp[ 64 ];
1595         
1596          
1597         /* don't do this if not grid lighting */
1598         if( noGridLighting )
1599                 return;
1600         
1601         /* ydnar: set grid size */
1602         value = ValueForKey( &entities[ 0 ], "gridsize" );
1603         if( value[ 0 ] != '\0' )
1604                 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1605         
1606         /* quantize it */
1607         VectorCopy( gridSize, oldGridSize );
1608         for( i = 0; i < 3; i++ )
1609                 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1610         
1611         /* ydnar: increase gridSize until grid count is smaller than max allowed */
1612         numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1613         j = 0;
1614         while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1615         {
1616                 /* get world bounds */
1617                 for( i = 0; i < 3; i++ )
1618                 {
1619                         gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1620                         maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1621                         gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1622                 }
1623         
1624                 /* set grid size */
1625                 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1626                 
1627                 /* increase grid size a bit */
1628                 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1629                         gridSize[ j++ % 3 ] += 16.0f;
1630         }
1631         
1632         /* print it */
1633         Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1634         
1635         /* different? */
1636         if( !VectorCompare( gridSize, oldGridSize ) )
1637         {
1638                 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1639                 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1640                 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1641         }
1642         
1643         /* 2nd variable. fixme: is this silly? */
1644         numBSPGridPoints = numRawGridPoints;
1645         
1646         /* allocate lightgrid */
1647         rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1648         memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1649         
1650         if( bspGridPoints != NULL )
1651                 free( bspGridPoints );
1652         bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1653         memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1654         
1655         /* clear lightgrid */
1656         for( i = 0; i < numRawGridPoints; i++ )
1657         {
1658                 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1659                 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1660                 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1661                 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1662                 {
1663                         rawGridPoints[ i ].styles[ j ] = LS_NONE;
1664                         bspGridPoints[ i ].styles[ j ] = LS_NONE;
1665                 }
1666         }
1667         
1668         /* note it */
1669         Sys_Printf( "%9d grid points\n", numRawGridPoints );
1670 }
1671
1672
1673
1674 /*
1675 LightWorld()
1676 does what it says...
1677 */
1678
1679 void LightWorld( void )
1680 {
1681         vec3_t          color;
1682         float           f;
1683         int                     b, bt;
1684         qboolean        minVertex, minGrid, ps;
1685         const char      *value;
1686         
1687
1688         /* ydnar: smooth normals */
1689         if( shade )
1690         {
1691                 Sys_Printf( "--- SmoothNormals ---\n" );
1692                 SmoothNormals();
1693         }
1694         
1695         /* determine the number of grid points */
1696         Sys_Printf( "--- SetupGrid ---\n" );
1697         SetupGrid();
1698         
1699         /* find the optional minimum lighting values */
1700         GetVectorForKey( &entities[ 0 ], "_color", color );
1701         if( VectorLength( color ) == 0.0f )
1702                 VectorSet( color, 1.0, 1.0, 1.0 );
1703         
1704         /* ambient */
1705         f = FloatForKey( &entities[ 0 ], "_ambient" );
1706         if( f == 0.0f )
1707                 f = FloatForKey( &entities[ 0 ], "ambient" );
1708         VectorScale( color, f, ambientColor );
1709         
1710         /* minvertexlight */
1711         minVertex = qfalse;
1712         value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1713         if( value[ 0 ] != '\0' )
1714         {
1715                 minVertex = qtrue;
1716                 f = atof( value );
1717                 VectorScale( color, f, minVertexLight );
1718         }
1719         
1720         /* mingridlight */
1721         minGrid = qfalse;
1722         value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1723         if( value[ 0 ] != '\0' )
1724         {
1725                 minGrid = qtrue;
1726                 f = atof( value );
1727                 VectorScale( color, f, minGridLight );
1728         }
1729         
1730         /* minlight */
1731         value = ValueForKey( &entities[ 0 ], "_minlight" );
1732         if( value[ 0 ] != '\0' )
1733         {
1734                 f = atof( value );
1735                 VectorScale( color, f, minLight );
1736                 if( minVertex == qfalse )
1737                         VectorScale( color, f, minVertexLight );
1738                 if( minGrid == qfalse )
1739                         VectorScale( color, f, minGridLight );
1740         }
1741         
1742         /* create world lights */
1743         Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1744         CreateEntityLights();
1745         CreateSurfaceLights();
1746         Sys_Printf( "%9d point lights\n", numPointLights );
1747         Sys_Printf( "%9d spotlights\n", numSpotLights );
1748         Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1749         Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1750         
1751         /* calculate lightgrid */
1752         if( !noGridLighting )
1753         {
1754                 /* ydnar: set up light envelopes */
1755                 SetupEnvelopes( qtrue, fastgrid );
1756                 
1757                 Sys_Printf( "--- TraceGrid ---\n" );
1758                 inGrid = qtrue;
1759                 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1760                 inGrid = qfalse;
1761                 Sys_Printf( "%d x %d x %d = %d grid\n",
1762                         gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1763                 
1764                 /* ydnar: emit statistics on light culling */
1765                 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1766                 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1767         }
1768         
1769         /* slight optimization to remove a sqrt */
1770         subdivideThreshold *= subdivideThreshold;
1771         
1772         /* map the world luxels */
1773         Sys_Printf( "--- MapRawLightmap ---\n" );
1774         RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1775         Sys_Printf( "%9d luxels\n", numLuxels );
1776         Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1777         Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1778         
1779         /* dirty them up */
1780         if( dirty )
1781         {
1782                 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1783
1784
1785
1786
1787                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1788         }
1789         
1790         /* floodlight pass */
1791         FloodlightRawLightmaps();
1792
1793         /* ydnar: set up light envelopes */
1794         SetupEnvelopes( qfalse, fast );
1795         
1796         /* light up my world */
1797         lightsPlaneCulled = 0;
1798         lightsEnvelopeCulled = 0;
1799         lightsBoundsCulled = 0;
1800         lightsClusterCulled = 0;
1801         
1802         Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1803         RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1804         Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1805         
1806         StitchSurfaceLightmaps();
1807         
1808         Sys_Printf( "--- IlluminateVertexes ---\n" );
1809         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1810         Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1811         
1812         /* ydnar: emit statistics on light culling */
1813         Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1814         Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1815         Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1816         Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1817         
1818         /* radiosity */
1819         b = 1;
1820         bt = bounce;
1821         while( bounce > 0 )
1822         {
1823                 /* store off the bsp between bounces */
1824                 StoreSurfaceLightmaps();
1825                 UnparseEntities();
1826                 Sys_Printf( "Writing %s\n", source );
1827                 WriteBSPFile( source );
1828                 
1829                 /* note it */
1830                 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1831                 
1832                 /* flag bouncing */
1833                 bouncing = qtrue;
1834                 VectorClear( ambientColor );
1835                 floodlighty = qfalse;
1836                 
1837                 /* generate diffuse lights */
1838                 RadFreeLights();
1839                 RadCreateDiffuseLights();
1840                 
1841                 /* setup light envelopes */
1842                 SetupEnvelopes( qfalse, fastbounce );
1843                 if( numLights == 0 )
1844                 {
1845                         Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1846                         break;
1847                 }
1848                 
1849                 /* add to lightgrid */
1850                 if( bouncegrid )
1851                 {
1852                         gridEnvelopeCulled = 0;
1853                         gridBoundsCulled = 0;
1854                         
1855                         Sys_Printf( "--- BounceGrid ---\n" );
1856                         inGrid = qtrue;
1857                         RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1858                         inGrid = qfalse;
1859                         Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1860                         Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1861                 }
1862                 
1863                 /* light up my world */
1864                 lightsPlaneCulled = 0;
1865                 lightsEnvelopeCulled = 0;
1866                 lightsBoundsCulled = 0;
1867                 lightsClusterCulled = 0;
1868                 
1869                 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1870                 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1871                 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1872                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1873                 
1874                 StitchSurfaceLightmaps();
1875                 
1876                 Sys_Printf( "--- IlluminateVertexes ---\n" );
1877                 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1878                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1879                 
1880                 /* ydnar: emit statistics on light culling */
1881                 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1882                 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1883                 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1884                 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1885                 
1886                 /* interate */
1887                 bounce--;
1888                 b++;
1889         }
1890 }
1891
1892
1893
1894 /*
1895 LightMain()
1896 main routine for light processing
1897 */
1898
1899 int LightMain( int argc, char **argv )
1900 {
1901         int                     i;
1902         float           f;
1903         char            mapSource[ 1024 ];
1904         const char      *value;
1905         int lightmapMergeSize = 0;
1906         
1907         
1908         /* note it */
1909         Sys_Printf( "--- Light ---\n" );
1910         Sys_Printf( "--- ProcessGameSpecific ---\n" );
1911
1912         /* set standard game flags */
1913         wolfLight = game->wolfLight;
1914         if (wolfLight == qtrue)
1915                 Sys_Printf( " lightning model: wolf\n" );
1916         else
1917                 Sys_Printf( " lightning model: quake3\n" );
1918
1919         lmCustomSize = game->lightmapSize;
1920         Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
1921
1922         lightmapGamma = game->lightmapGamma;
1923         Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
1924
1925         lightmapCompensate = game->lightmapCompensate;
1926         Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
1927
1928         lightmapExposure = game->lightmapExposure;
1929         Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
1930
1931         gridScale = game->gridScale;
1932         Sys_Printf( " lightgrid scale: %f\n", gridScale );
1933
1934         gridAmbientScale = game->gridAmbientScale;
1935         Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
1936
1937         lightAngleHL = game->lightAngleHL;
1938         if( lightAngleHL )
1939                 Sys_Printf( " half lambert light angle attenuation enabled \n" );
1940
1941         noStyles = game->noStyles;
1942         if (noStyles == qtrue)
1943                 Sys_Printf( " shader lightstyles hack: disabled\n" );
1944         else
1945                 Sys_Printf( " shader lightstyles hack: enabled\n" );
1946
1947         keepLights = game->keepLights;
1948         if (keepLights == qtrue)
1949                 Sys_Printf( " keep lights: enabled\n" );
1950         else
1951                 Sys_Printf( " keep lights: disabled\n" );
1952
1953         patchShadows = game->patchShadows;
1954         if (patchShadows == qtrue)
1955                 Sys_Printf( " patch shadows: enabled\n" );
1956         else
1957                 Sys_Printf( " patch shadows: disabled\n" );
1958
1959         deluxemap = game->deluxeMap;
1960         deluxemode = game->deluxeMode;
1961         if (deluxemap == qtrue)
1962         {
1963                 if (deluxemode)
1964                         Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
1965                 else
1966                         Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
1967         }
1968         else
1969                 Sys_Printf( " deluxemapping: disabled\n" );
1970
1971         Sys_Printf( "--- ProcessCommandLine ---\n" );
1972         
1973         /* process commandline arguments */
1974         for( i = 1; i < (argc - 1); i++ )
1975         {
1976                 /* lightsource scaling */
1977                 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
1978                 {
1979                         f = atof( argv[ i + 1 ] );
1980                         pointScale *= f;
1981                         Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1982                         i++;
1983                 }
1984                 
1985                 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
1986                 {
1987                         f = atof( argv[ i + 1 ] );
1988                         areaScale *= f;
1989                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1990                         i++;
1991                 }
1992                 
1993                 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
1994                 {
1995                         f = atof( argv[ i + 1 ] );
1996                         skyScale *= f;
1997                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1998                         i++;
1999                 }
2000                 
2001                 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2002                 {
2003                         f = atof( argv[ i + 1 ] );
2004                         bounceScale *= f;
2005                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2006                         i++;
2007                 }
2008                 
2009                 else if( !strcmp( argv[ i ], "-scale" ) )
2010                 {
2011                         f = atof( argv[ i + 1 ] );
2012                         pointScale *= f;
2013                         areaScale *= f;
2014                         skyScale *= f;
2015                         bounceScale *= f;
2016                         Sys_Printf( "All light scaled by %f\n", f );
2017                         i++;
2018                 }
2019
2020                 else if( !strcmp( argv[ i ], "-gridscale" ) )
2021                 {
2022                         f = atof( argv[ i + 1 ] );
2023                         Sys_Printf( "Grid lightning scaled by %f\n", f );
2024                         gridScale *= f;
2025                         i++;
2026                 }
2027
2028                 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2029                 {
2030                         f = atof( argv[ i + 1 ] );
2031                         Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2032                         gridAmbientScale *= f;
2033                         i++;
2034                 }
2035
2036                 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2037                 {
2038                         f = atof( argv[ i + 1 ] );
2039                         if(f < 0) f = 0;
2040                         if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2041                         Sys_Printf( "Grid directionality is %f\n", f );
2042                         gridDirectionality *= f;
2043                         i++;
2044                 }
2045
2046                 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2047                 {
2048                         f = atof( argv[ i + 1 ] );
2049                         if(f > gridDirectionality) f = gridDirectionality;
2050                         if(f > 1) f = 1;
2051                         Sys_Printf( "Grid ambient directionality is %f\n", f );
2052                         gridAmbientDirectionality *= f;
2053                         i++;
2054                 }
2055                 
2056                 else if( !strcmp( argv[ i ], "-gamma" ) )
2057                 {
2058                         f = atof( argv[ i + 1 ] );
2059                         lightmapGamma = f;
2060                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2061                         i++;
2062                 }
2063                 
2064                 else if( !strcmp( argv[ i ], "-exposure" ) )
2065                 {
2066                         f = atof( argv[ i + 1 ] );
2067                         lightmapExposure = f;
2068                         Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2069                         i++;
2070                 }
2071
2072                 else if( !strcmp( argv[ i ], "-compensate" ) )
2073                 {
2074                         f = atof( argv[ i + 1 ] );
2075                         if( f <= 0.0f )
2076                                 f = 1.0f;
2077                         lightmapCompensate = f;
2078                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2079                         i++;
2080                 }
2081                 
2082                 /* ydnar switches */
2083                 else if( !strcmp( argv[ i ], "-bounce" ) )
2084                 {
2085                         bounce = atoi( argv[ i + 1 ] );
2086                         if( bounce < 0 )
2087                                 bounce = 0;
2088                         else if( bounce > 0 )
2089                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2090                         i++;
2091                 }
2092                 
2093                 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2094                 {
2095                         superSample = atoi( argv[ i + 1 ] );
2096                         if( superSample < 1 )
2097                                 superSample = 1;
2098                         else if( superSample > 1 )
2099                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2100                         i++;
2101                 }
2102                 
2103                 else if( !strcmp( argv[ i ], "-samples" ) )
2104                 {
2105                         lightSamples = atoi( argv[ i + 1 ] );
2106                         if( lightSamples < 1 )
2107                                 lightSamples = 1;
2108                         else if( lightSamples > 1 )
2109                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2110                         i++;
2111                 }
2112                 
2113                 else if( !strcmp( argv[ i ], "-filter" ) )
2114                 {
2115                         filter = qtrue;
2116                         Sys_Printf( "Lightmap filtering enabled\n" );
2117                 }
2118                 
2119                 else if( !strcmp( argv[ i ], "-dark" ) )
2120                 {
2121                         dark = qtrue;
2122                         Sys_Printf( "Dark lightmap seams enabled\n" );
2123                 }
2124                 
2125                 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2126                 {
2127                         shadeAngleDegrees = atof( argv[ i + 1 ] );
2128                         if( shadeAngleDegrees < 0.0f )
2129                                 shadeAngleDegrees = 0.0f;
2130                         else if( shadeAngleDegrees > 0.0f )
2131                         {
2132                                 shade = qtrue;
2133                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2134                         }
2135                         i++;
2136                 }
2137                 
2138                 else if( !strcmp( argv[ i ], "-thresh" ) )
2139                 {
2140                         subdivideThreshold = atof( argv[ i + 1 ] );
2141                         if( subdivideThreshold < 0 )
2142                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2143                         else
2144                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2145                         i++;
2146                 }
2147                 
2148                 else if( !strcmp( argv[ i ], "-approx" ) )
2149                 {
2150                         approximateTolerance = atoi( argv[ i + 1 ] );
2151                         if( approximateTolerance < 0 )
2152                                 approximateTolerance = 0;
2153                         else if( approximateTolerance > 0 )
2154                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2155                         i++;
2156                 }
2157                 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2158                 {
2159                         deluxemap = qtrue;
2160                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
2161                 }
2162                 else if( !strcmp( argv[ i ], "-deluxemode" ))
2163                 {
2164                         deluxemode = atoi( argv[ i + 1 ] );
2165                         if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2166                         {
2167                                 Sys_Printf( "Generating modelspace deluxemaps\n" );
2168                                 deluxemode = 0;
2169                         }
2170                         else 
2171                                 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2172                         i++;
2173                 }
2174                 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2175                 {
2176                         deluxemap = qfalse;
2177                         Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2178                 }
2179                 else if( !strcmp( argv[ i ], "-external" ) )
2180                 {
2181                         externalLightmaps = qtrue;
2182                         Sys_Printf( "Storing all lightmaps externally\n" );
2183                 }
2184
2185                 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2186                 {
2187                         lmCustomSize = atoi( argv[ i + 1 ] );
2188                         
2189                         /* must be a power of 2 and greater than 2 */
2190                         if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2191                         {
2192                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2193                                 lmCustomSize = game->lightmapSize;
2194                         }
2195                         i++;
2196                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2197                         
2198                         /* enable external lightmaps */
2199                         if( lmCustomSize != game->lightmapSize )
2200                         {
2201                                 externalLightmaps = qtrue;
2202                                 Sys_Printf( "Storing all lightmaps externally\n" );
2203                         }
2204                 }
2205                 
2206                 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2207                 {
2208                         lmLimitSize = atoi( argv[ i + 1 ] );
2209                         
2210                         i++;
2211                         Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2212                 }
2213                 
2214                 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2215                 {
2216                         lmCustomDir = argv[i + 1];
2217                         i++;
2218                         Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2219                         externalLightmaps = qtrue;
2220                         Sys_Printf( "Storing all lightmaps externally\n" );
2221                 }
2222                 
2223                 /* ydnar: add this to suppress warnings */
2224                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
2225                 {
2226                         Sys_Printf( "Custom info parms enabled\n" );
2227                         useCustomInfoParms = qtrue;
2228                 }
2229                 
2230                 else if( !strcmp( argv[ i ], "-wolf" ) )
2231                 {
2232                         /* -game should already be set */
2233                         wolfLight = qtrue;
2234                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2235                 }
2236                 
2237                 else if( !strcmp( argv[ i ], "-q3" ) )
2238                 {
2239                         /* -game should already be set */
2240                         wolfLight = qfalse;
2241                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2242                 }
2243
2244                 else if( !strcmp( argv[ i ], "-extradist" ) )
2245                 {
2246                         extraDist = atof( argv[ i + 1 ] );
2247                         if( extraDist < 0 )
2248                                 extraDist = 0;
2249                         i++;
2250                         Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2251                 }
2252                 
2253                 else if( !strcmp( argv[ i ], "-sunonly" ) )
2254                 {
2255                         sunOnly = qtrue;
2256                         Sys_Printf( "Only computing sunlight\n" );
2257                 }
2258                 
2259                 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2260                 {
2261                         bounceOnly = qtrue;
2262                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2263                 }
2264                 
2265                 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2266                 {
2267                         noCollapse = qtrue;
2268                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2269                 }
2270
2271                 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2272                 {
2273                         lightmapSearchBlockSize = 1;
2274                         Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2275                 }
2276                 
2277                 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2278                 {
2279                         lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2280                         ++i;
2281                         Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2282                 }
2283                 
2284                 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2285                 {
2286                         lightmapSearchBlockSize = atoi(argv[i+1]);
2287                         ++i;
2288                         Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2289                 }
2290                 
2291                 else if( !strcmp( argv[ i ], "-shade" ) )
2292                 {
2293                         shade = qtrue;
2294                         Sys_Printf( "Phong shading enabled\n" );
2295                 }
2296                 
2297                 else if( !strcmp( argv[ i ], "-bouncegrid") )
2298                 {
2299                         bouncegrid = qtrue;
2300                         if( bounce > 0 )
2301                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2302                 }
2303                 
2304                 else if( !strcmp( argv[ i ], "-smooth" ) )
2305                 {
2306                         lightSamples = EXTRA_SCALE;
2307                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2308                 }
2309                 
2310                 else if( !strcmp( argv[ i ], "-fast" ) )
2311                 {
2312                         fast = qtrue;
2313                         fastgrid = qtrue;
2314                         fastbounce = qtrue;
2315                         Sys_Printf( "Fast mode enabled\n" );
2316                 }
2317                 
2318                 else if( !strcmp( argv[ i ], "-faster" ) )
2319                 {
2320                         faster = qtrue;
2321                         fast = qtrue;
2322                         fastgrid = qtrue;
2323                         fastbounce = qtrue;
2324                         Sys_Printf( "Faster mode enabled\n" );
2325                 }
2326                 
2327                 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2328                 {
2329                         fastgrid = qtrue;
2330                         Sys_Printf( "Fast grid lighting enabled\n" );
2331                 }
2332                 
2333                 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2334                 {
2335                         fastbounce = qtrue;
2336                         Sys_Printf( "Fast bounce mode enabled\n" );
2337                 }
2338                 
2339                 else if( !strcmp( argv[ i ], "-cheap" ) )
2340                 {
2341                         cheap = qtrue;
2342                         cheapgrid = qtrue;
2343                         Sys_Printf( "Cheap mode enabled\n" );
2344                 }
2345
2346                 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2347                 {
2348                         cheapgrid = qtrue;
2349                         Sys_Printf( "Cheap grid mode enabled\n" );
2350                 }
2351                 
2352                 else if( !strcmp( argv[ i ], "-normalmap" ) )
2353                 {
2354                         normalmap = qtrue;
2355                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2356                 }
2357                 
2358                 else if( !strcmp( argv[ i ], "-trisoup" ) )
2359                 {
2360                         trisoup = qtrue;
2361                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2362                 }
2363                 
2364                 else if( !strcmp( argv[ i ], "-debug" ) )
2365                 {
2366                         debug = qtrue;
2367                         Sys_Printf( "Lightmap debugging enabled\n" );
2368                 }
2369                 
2370                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2371                 {
2372                         debugSurfaces = qtrue;
2373                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2374                 }
2375                 
2376                 else if( !strcmp( argv[ i ], "-debugunused" ) )
2377                 {
2378                         debugUnused = qtrue;
2379                         Sys_Printf( "Unused luxel debugging enabled\n" );
2380                 }
2381
2382                 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2383                 {
2384                         debugAxis = qtrue;
2385                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2386                 }
2387                 
2388                 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2389                 {
2390                         debugCluster = qtrue;
2391                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2392                 }
2393                 
2394                 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2395                 {
2396                         debugOrigin = qtrue;
2397                         Sys_Printf( "Luxel origin debugging enabled\n" );
2398                 }
2399                 
2400                 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2401                 {
2402                         deluxemap = qtrue;
2403                         debugDeluxemap = qtrue;
2404                         Sys_Printf( "Deluxemap debugging enabled\n" );
2405                 }
2406                 
2407                 else if( !strcmp( argv[ i ], "-export" ) )
2408                 {
2409                         exportLightmaps = qtrue;
2410                         Sys_Printf( "Exporting lightmaps\n" );
2411                 }
2412                 
2413                 else if( !strcmp(argv[ i ], "-notrace" )) 
2414                 {
2415                         noTrace = qtrue;
2416                         Sys_Printf( "Shadow occlusion disabled\n" );
2417                 }
2418                 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2419                 {
2420                         patchShadows = qtrue;
2421                         Sys_Printf( "Patch shadow casting enabled\n" );
2422                 }
2423                 else if( !strcmp( argv[ i ], "-extra" ) )
2424                 {
2425                         superSample = EXTRA_SCALE;              /* ydnar */
2426                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2427                 }
2428                 else if( !strcmp( argv[ i ], "-extrawide" ) )
2429                 {
2430                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2431                         filter = qtrue;                                 /* ydnar */
2432                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2433                 }
2434                 else if( !strcmp( argv[ i ], "-samplesize" ) )
2435                 {
2436                         sampleSize = atoi( argv[ i + 1 ] );
2437                         if( sampleSize < 1 )
2438                                 sampleSize = 1;
2439                         i++;
2440                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2441                 }
2442                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2443                 {
2444                         minSampleSize = atoi( argv[ i + 1 ] );
2445                         if( minSampleSize < 1 )
2446                                 minSampleSize = 1;
2447                         i++;
2448                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2449                 }
2450                 else if( !strcmp( argv[ i ],  "-samplescale" ) )
2451                 {
2452                         sampleScale = atoi( argv[ i + 1 ] );
2453                         i++;
2454                         Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2455                 }
2456                 else if( !strcmp( argv[ i ], "-novertex" ) )
2457                 {
2458                         noVertexLighting = qtrue;
2459                         Sys_Printf( "Disabling vertex lighting\n" );
2460                 }
2461                 else if( !strcmp( argv[ i ], "-nogrid" ) )
2462                 {
2463                         noGridLighting = qtrue;
2464                         Sys_Printf( "Disabling grid lighting\n" );
2465                 }
2466                 else if( !strcmp( argv[ i ], "-border" ) )
2467                 {
2468                         lightmapBorder = qtrue;
2469                         Sys_Printf( "Adding debug border to lightmaps\n" );
2470                 }
2471                 else if( !strcmp( argv[ i ], "-nosurf" ) )
2472                 {
2473                         noSurfaces = qtrue;
2474                         Sys_Printf( "Not tracing against surfaces\n" );
2475                 }
2476                 else if( !strcmp( argv[ i ], "-dump" ) )
2477                 {
2478                         dump = qtrue;
2479                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2480                 }
2481                 else if( !strcmp( argv[ i ], "-lomem" ) )
2482                 {
2483                         loMem = qtrue;
2484                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2485                 }
2486                 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2487                 {
2488                         if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2489                         {
2490                                 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2491                                 if( lightAngleHL )
2492                                         Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2493                                 else
2494                                         Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2495                         }
2496                 }
2497                 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2498                 {
2499                         noStyles = qtrue;
2500                         Sys_Printf( "Disabling lightstyles\n" );
2501                 }
2502                 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2503                 {
2504                         noStyles = qfalse;
2505                         Sys_Printf( "Enabling lightstyles\n" );
2506                 }
2507                 else if( !strcmp( argv[ i ], "-keeplights" ))
2508                 {
2509                         keepLights = qtrue;
2510                         Sys_Printf( "Leaving light entities on map after compile\n" );
2511                 }
2512                 else if( !strcmp( argv[ i ], "-cpma" ) )
2513                 {
2514                         cpmaHack = qtrue;
2515                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2516                 }
2517                 else if( !strcmp( argv[ i ], "-floodlight" ) )
2518                 {
2519                         floodlighty = qtrue;
2520                         Sys_Printf( "FloodLighting enabled\n" );
2521                 }
2522                 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2523                 {
2524                         debugnormals = qtrue;
2525                         Sys_Printf( "DebugNormals enabled\n" );
2526                 }
2527                 else if( !strcmp( argv[ i ], "-lowquality" ) )
2528                 {
2529                         floodlight_lowquality = qtrue;
2530                         Sys_Printf( "Low Quality FloodLighting enabled\n" );
2531                 }
2532                 
2533                 /* r7: dirtmapping */
2534                 else if( !strcmp( argv[ i ], "-dirty" ) )
2535                 {
2536                         dirty = qtrue;
2537                         Sys_Printf( "Dirtmapping enabled\n" );
2538                 }
2539                 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2540                 {
2541                         dirtDebug = qtrue;
2542                         Sys_Printf( "Dirtmap debugging enabled\n" );
2543                 }
2544                 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2545                 {
2546                         dirtMode = atoi( argv[ i + 1 ] );
2547                         if( dirtMode != 0 && dirtMode != 1 )
2548                                 dirtMode = 0;
2549                         if( dirtMode == 1 )
2550                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2551                         else
2552                                 Sys_Printf( "Enabling ordered dir mapping\n" );
2553                         i++;
2554                 }
2555                 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2556                 {
2557                         dirtDepth = atof( argv[ i + 1 ] );
2558                         if( dirtDepth <= 0.0f )
2559                                 dirtDepth = 128.0f;
2560                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2561                         i++;
2562                 }
2563                 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2564                 {
2565                         dirtScale = atof( argv[ i + 1 ] );
2566                         if( dirtScale <= 0.0f )
2567                                 dirtScale = 1.0f;
2568                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2569                         i++;
2570                 }
2571                 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2572                 {
2573                         dirtGain = atof( argv[ i + 1 ] );
2574                         if( dirtGain <= 0.0f )
2575                                 dirtGain = 1.0f;
2576                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2577                         i++;
2578                 }
2579                 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2580                 {
2581                         lightmapTriangleCheck = qtrue;
2582                 }
2583                 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2584                 {
2585                         lightmapExtraVisClusterNudge = qtrue;
2586                 }
2587                 /* unhandled args */
2588                 else
2589                 {
2590                         Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2591                 }
2592
2593         }
2594
2595         /* fix up lightmap search power */
2596         if(lightmapMergeSize)
2597         {
2598                 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2599                 if(lightmapSearchBlockSize < 1)
2600                         lightmapSearchBlockSize = 1;
2601
2602                 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2603         }
2604         
2605         /* clean up map name */
2606         strcpy( source, ExpandArg( argv[ i ] ) );
2607         StripExtension( source );
2608         DefaultExtension( source, ".bsp" );
2609         strcpy( mapSource, ExpandArg( argv[ i ] ) );
2610         StripExtension( mapSource );
2611         DefaultExtension( mapSource, ".map" );
2612         
2613         /* ydnar: set default sample size */
2614         SetDefaultSampleSize( sampleSize );
2615         
2616         /* ydnar: handle shaders */
2617         BeginMapShaderFile( source );
2618         LoadShaderInfo();
2619         
2620         /* note loading */
2621         Sys_Printf( "Loading %s\n", source );
2622         
2623         /* ydnar: load surface file */
2624         LoadSurfaceExtraFile( source );
2625         
2626         /* load bsp file */
2627         LoadBSPFile( source );
2628         
2629         /* parse bsp entities */
2630         ParseEntities();
2631
2632         /* inject command line parameters */
2633         InjectCommandLine(argv, 0, argc - 1);
2634         
2635         /* load map file */
2636         value = ValueForKey( &entities[ 0 ], "_keepLights" );
2637         if( value[ 0 ] != '1' )
2638                 LoadMapFile( mapSource, qtrue );
2639         
2640         /* set the entity/model origins and init yDrawVerts */
2641         SetEntityOrigins();
2642         
2643         /* ydnar: set up optimization */
2644         SetupBrushes();
2645         SetupDirt();
2646         SetupFloodLight();
2647         SetupSurfaceLightmaps();
2648         
2649         /* initialize the surface facet tracing */
2650         SetupTraceNodes();
2651         
2652         /* light the world */
2653         LightWorld();
2654         
2655         /* ydnar: store off lightmaps */
2656         StoreSurfaceLightmaps();
2657         
2658         /* write out the bsp */
2659         UnparseEntities();
2660         Sys_Printf( "Writing %s\n", source );
2661         WriteBSPFile( source );
2662         
2663         /* ydnar: export lightmaps */
2664         if( exportLightmaps && !externalLightmaps )
2665                 ExportLightmaps();
2666         
2667         /* return to sender */
2668         return 0;
2669 }
2670