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