]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light.c
initial code for converting .map to .map
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42 CreateSunLight() - ydnar
43 this creates a sun light
44 */
45
46 static void CreateSunLight( sun_t *sun )
47 {
48         int                     i;
49         float           photons, d, angle, elevation, da, de;
50         vec3_t          direction;
51         light_t         *light;
52         
53         
54         /* dummy check */
55         if( sun == NULL )
56                 return;
57         
58         /* fixup */
59         if( sun->numSamples < 1 )
60                 sun->numSamples = 1;
61         
62         /* set photons */
63         photons = sun->photons / sun->numSamples;
64         
65         /* create the right number of suns */
66         for( i = 0; i < sun->numSamples; i++ )
67         {
68                 /* calculate sun direction */
69                 if( i == 0 )
70                         VectorCopy( sun->direction, direction );
71                 else
72                 {
73                         /*
74                                 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
75                                 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
76                                 sun->direction[ 2 ] = sin( elevation );
77                                 
78                                 xz_dist   = sqrt( x*x + z*z )
79                                 latitude  = atan2( xz_dist, y ) * RADIANS
80                                 longitude = atan2( x,       z ) * RADIANS
81                         */
82                         
83                         d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
84                         angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
85                         elevation = atan2( sun->direction[ 2 ], d );
86                         
87                         /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
88                         do
89                         {
90                                 da = (Random() * 2.0f - 1.0f) * sun->deviance;
91                                 de = (Random() * 2.0f - 1.0f) * sun->deviance;
92                         }
93                         while( (da * da + de * de) > (sun->deviance * sun->deviance) );
94                         angle += da;
95                         elevation += de;
96                         
97                         /* debug code */
98                         //%     Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
99                         
100                         /* create new vector */
101                         direction[ 0 ] = cos( angle ) * cos( elevation );
102                         direction[ 1 ] = sin( angle ) * cos( elevation );
103                         direction[ 2 ] = sin( elevation );
104                 }
105                 
106                 /* create a light */
107                 numSunLights++;
108                 light = safe_malloc( sizeof( *light ) );
109                 memset( light, 0, sizeof( *light ) );
110                 light->next = lights;
111                 lights = light;
112                 
113                 /* initialize the light */
114                 light->flags = LIGHT_SUN_DEFAULT;
115                 light->type = EMIT_SUN;
116                 light->fade = 1.0f;
117                 light->falloffTolerance = falloffTolerance;
118                 light->filterRadius = sun->filterRadius / sun->numSamples;
119                 light->style = noStyles ? LS_NORMAL : sun->style;
120                 
121                 /* set the light's position out to infinity */
122                 VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin );    /* MAX_WORLD_COORD * 2.0f */
123                 
124                 /* set the facing to be the inverse of the sun direction */
125                 VectorScale( direction, -1.0, light->normal );
126                 light->dist = DotProduct( light->origin, light->normal );
127                 
128                 /* set color and photons */
129                 VectorCopy( sun->color, light->color );
130                 light->photons = photons * skyScale;
131         }
132
133         /* another sun? */
134         if( sun->next != NULL )
135                 CreateSunLight( sun->next );
136 }
137
138
139
140 /*
141 CreateSkyLights() - ydnar
142 simulates sky light with multiple suns
143 */
144
145 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius, int style )
146 {
147         int                     i, j, numSuns;
148         int                     angleSteps, elevationSteps;
149         float           angle, elevation;
150         float           angleStep, elevationStep;
151         float           step, start;
152         sun_t           sun;
153         
154         
155         /* dummy check */
156         if( value <= 0.0f || iterations < 2 )
157                 return;
158         
159         /* calculate some stuff */
160         step = 2.0f / (iterations - 1);
161         start = -1.0f;
162         
163         /* basic sun setup */
164         VectorCopy( color, sun.color );
165         sun.deviance = 0.0f;
166         sun.filterRadius = filterRadius;
167         sun.numSamples = 1;
168         sun.style = noStyles ? LS_NORMAL : style;
169         sun.next = NULL;
170         
171         /* setup */
172         elevationSteps = iterations - 1;
173         angleSteps = elevationSteps * 4;
174         angle = 0.0f;
175         elevationStep = DEG2RAD( 90.0f / iterations );  /* skip elevation 0 */
176         angleStep = DEG2RAD( 360.0f / angleSteps );
177         
178         /* calc individual sun brightness */
179         numSuns = angleSteps * elevationSteps + 1;
180         sun.photons = value / numSuns;
181         
182         /* iterate elevation */
183         elevation = elevationStep * 0.5f;
184         angle = 0.0f;
185         for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
186         {
187                 /* iterate angle */
188                 for( j = 0; j < angleSteps; j++ )
189                 {
190                         /* create sun */
191                         sun.direction[ 0 ] = cos( angle ) * cos( elevation );
192                         sun.direction[ 1 ] = sin( angle ) * cos( elevation );
193                         sun.direction[ 2 ] = sin( elevation );
194                         CreateSunLight( &sun );
195                         
196                         /* move */
197                         angle += angleStep;
198                 }
199                         
200                 /* move */
201                 elevation += elevationStep;
202                 angle += angleStep / elevationSteps;
203         }
204         
205         /* create vertical sun */
206         VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
207         CreateSunLight( &sun );
208         
209         /* short circuit */
210         return;
211 }
212
213
214
215 /*
216 CreateEntityLights()
217 creates lights from light entities
218 */
219
220 void CreateEntityLights( void )
221 {
222         int                             i, j;
223         light_t                 *light, *light2;
224         entity_t                *e, *e2;
225         const char              *name;
226         const char              *target;
227         vec3_t                  dest;
228         const char              *_color;
229         float                   intensity, scale, deviance, filterRadius;
230         int                             spawnflags, flags, numSamples;
231         qboolean                junior;
232
233         
234         /* go throught entity list and find lights */
235         for( i = 0; i < numEntities; i++ )
236         {
237                 /* get entity */
238                 e = &entities[ i ];
239                 name = ValueForKey( e, "classname" );
240                 
241                 /* ydnar: check for lightJunior */
242                 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
243                         junior = qtrue;
244                 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
245                         junior = qfalse;
246                 else
247                         continue;
248                 
249                 /* lights with target names (and therefore styles) are only parsed from BSP */
250                 target = ValueForKey( e, "targetname" );
251                 if( target[ 0 ] != '\0' && i >= numBSPEntities )
252                         continue;
253                 
254                 /* create a light */
255                 numPointLights++;
256                 light = safe_malloc( sizeof( *light ) );
257                 memset( light, 0, sizeof( *light ) );
258                 light->next = lights;
259                 lights = light;
260                 
261                 /* handle spawnflags */
262                 spawnflags = IntForKey( e, "spawnflags" );
263                 
264                 /* ydnar: quake 3+ light behavior */
265                 if( wolfLight == qfalse )
266                 {
267                         /* set default flags */
268                         flags = LIGHT_Q3A_DEFAULT;
269                         
270                         /* linear attenuation? */
271                         if( spawnflags & 1 )
272                         {
273                                 flags |= LIGHT_ATTEN_LINEAR;
274                                 flags &= ~LIGHT_ATTEN_ANGLE;
275                         }
276                         
277                         /* no angle attenuate? */
278                         if( spawnflags & 2 )
279                                 flags &= ~LIGHT_ATTEN_ANGLE;
280                 }
281                 
282                 /* ydnar: wolf light behavior */
283                 else
284                 {
285                         /* set default flags */
286                         flags = LIGHT_WOLF_DEFAULT;
287                         
288                         /* inverse distance squared attenuation? */
289                         if( spawnflags & 1 )
290                         {
291                                 flags &= ~LIGHT_ATTEN_LINEAR;
292                                 flags |= LIGHT_ATTEN_ANGLE;
293                         }
294                         
295                         /* angle attenuate? */
296                         if( spawnflags & 2 )
297                                 flags |= LIGHT_ATTEN_ANGLE;
298                 }
299                 
300                 /* other flags (borrowed from wolf) */
301                 
302                 /* wolf dark light? */
303                 if( (spawnflags & 4) || (spawnflags & 8) )
304                         flags |= LIGHT_DARK;
305                 
306                 /* nogrid? */
307                 if( spawnflags & 16 )
308                         flags &= ~LIGHT_GRID;
309                 
310                 /* junior? */
311                 if( junior )
312                 {
313                         flags |= LIGHT_GRID;
314                         flags &= ~LIGHT_SURFACES;
315                 }
316
317                 /* vortex: unnormalized? */
318                 if (spawnflags & 32)
319                         flags |= LIGHT_UNNORMALIZED;
320
321                 /* vortex: distance atten? */
322                 if (spawnflags & 64)
323                         flags |= LIGHT_ATTEN_DISTANCE;
324
325                 /* store the flags */
326                 light->flags = flags;
327                 
328                 /* ydnar: set fade key (from wolf) */
329                 light->fade = 1.0f;
330                 if( light->flags & LIGHT_ATTEN_LINEAR )
331                 {
332                         light->fade = FloatForKey( e, "fade" );
333                         if( light->fade == 0.0f )
334                                 light->fade = 1.0f;
335                 }
336                 
337                 /* ydnar: set angle scaling (from vlight) */
338                 light->angleScale = FloatForKey( e, "_anglescale" );
339                 if( light->angleScale != 0.0f )
340                         light->flags |= LIGHT_ATTEN_ANGLE;
341                 
342                 /* set origin */
343                 GetVectorForKey( e, "origin", light->origin);
344                 light->style = IntForKey( e, "_style" );
345                 if( light->style == LS_NORMAL )
346                         light->style = IntForKey( e, "style" );
347                 if( light->style < LS_NORMAL || light->style >= LS_NONE )
348                         Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
349                 
350                 if( light->style != LS_NORMAL ) {
351                         Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
352                 }
353
354                 /* set light intensity */
355                 intensity = FloatForKey( e, "_light" );
356                 if( intensity == 0.0f )
357                         intensity = FloatForKey( e, "light" );
358                 if( intensity == 0.0f)
359                         intensity = 300.0f;
360                 
361                 /* ydnar: set light scale (sof2) */
362                 scale = FloatForKey( e, "scale" );
363                 if( scale == 0.0f )
364                         scale = 1.0f;
365                 intensity *= scale;
366                 
367                 /* ydnar: get deviance and samples */
368                 deviance = FloatForKey( e, "_deviance" );
369                 if( deviance == 0.0f )
370                         deviance = FloatForKey( e, "_deviation" );
371                 if( deviance == 0.0f )
372                         deviance = FloatForKey( e, "_jitter" );
373                 numSamples = IntForKey( e, "_samples" );
374                 if( deviance < 0.0f || numSamples < 1 )
375                 {
376                         deviance = 0.0f;
377                         numSamples = 1;
378                 }
379                 intensity /= numSamples;
380                 
381                 /* ydnar: get filter radius */
382                 filterRadius = FloatForKey( e, "_filterradius" );
383                 if( filterRadius == 0.0f )
384                         filterRadius = FloatForKey( e, "_filteradius" );
385                 if( filterRadius == 0.0f )
386                         filterRadius = FloatForKey( e, "_filter" );
387                 if( filterRadius < 0.0f )
388                         filterRadius = 0.0f;
389                 light->filterRadius = filterRadius;
390                 
391                 /* set light color */
392                 _color = ValueForKey( e, "_color" );
393                 if( _color && _color[ 0 ] )
394                 {
395                         sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
396                         if (!(light->flags & LIGHT_UNNORMALIZED))
397                         {
398                                 ColorNormalize( light->color, light->color );
399                         }
400                 }
401                 else
402                         light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
403
404                 light->extraDist = FloatForKey( e, "_extradist" );
405                 if(light->extraDist == 0.0f)
406                         light->extraDist = extraDist;
407                 
408                 intensity = intensity * pointScale;
409                 light->photons = intensity;
410
411                 light->type = EMIT_POINT;
412                 
413                 /* set falloff threshold */
414                 light->falloffTolerance = falloffTolerance / numSamples;
415                 
416                 /* lights with a target will be spotlights */
417                 target = ValueForKey( e, "target" );
418                 if( target[ 0 ] )
419                 {
420                         float           radius;
421                         float           dist;
422                         sun_t           sun;
423                         const char      *_sun;
424                         
425                         
426                         /* get target */
427                         e2 = FindTargetEntity( target );
428                         if( e2 == NULL )
429                         {
430                                 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
431                                         (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
432                         }
433                         else
434                         {
435                                 /* not a point light */
436                                 numPointLights--;
437                                 numSpotLights++;
438                                 
439                                 /* make a spotlight */
440                                 GetVectorForKey( e2, "origin", dest );
441                                 VectorSubtract( dest, light->origin, light->normal );
442                                 dist = VectorNormalize( light->normal, light->normal );
443                                 radius = FloatForKey( e, "radius" );
444                                 if( !radius )
445                                         radius = 64;
446                                 if( !dist )
447                                         dist = 64;
448                                 light->radiusByDist = (radius + 16) / dist;
449                                 light->type = EMIT_SPOT;
450                                 
451                                 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
452                                 light->flags &= ~LIGHT_ATTEN_LINEAR;
453                                 light->flags |= LIGHT_ATTEN_ANGLE;
454                                 light->fade = 1.0f;
455                                 
456                                 /* ydnar: is this a sun? */
457                                 _sun = ValueForKey( e, "_sun" );
458                                 if( _sun[ 0 ] == '1' )
459                                 {
460                                         /* not a spot light */
461                                         numSpotLights--;
462                                         
463                                         /* unlink this light */
464                                         lights = light->next;
465                                         
466                                         /* make a sun */
467                                         VectorScale( light->normal, -1.0f, sun.direction );
468                                         VectorCopy( light->color, sun.color );
469                                         sun.photons = (intensity / pointScale);
470                                         sun.deviance = deviance / 180.0f * Q_PI;
471                                         sun.numSamples = numSamples;
472                                         sun.style = noStyles ? LS_NORMAL : light->style;
473                                         sun.next = NULL;
474                                         
475                                         /* make a sun light */
476                                         CreateSunLight( &sun );
477                                         
478                                         /* free original light */
479                                         free( light );
480                                         light = NULL;
481                                         
482                                         /* skip the rest of this love story */
483                                         continue;
484                                 }
485                         }
486                 }
487                 
488                 /* jitter the light */
489                 for( j = 1; j < numSamples; j++ )
490                 {
491                         /* create a light */
492                         light2 = safe_malloc( sizeof( *light ) );
493                         memcpy( light2, light, sizeof( *light ) );
494                         light2->next = lights;
495                         lights = light2;
496                         
497                         /* add to counts */
498                         if( light->type == EMIT_SPOT )
499                                 numSpotLights++;
500                         else
501                                 numPointLights++;
502                         
503                         /* jitter it */
504                         light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
505                         light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
506                         light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
507                 }
508         }
509 }
510
511
512
513 /*
514 CreateSurfaceLights() - ydnar
515 this hijacks the radiosity code to generate surface lights for first pass
516 */
517
518 #define APPROX_BOUNCE   1.0f
519
520 void CreateSurfaceLights( void )
521 {
522         int                                     i;
523         bspDrawSurface_t        *ds;
524         surfaceInfo_t           *info;
525         shaderInfo_t            *si;
526         light_t                         *light;
527         float                           subdivide;
528         vec3_t                          origin;
529         clipWork_t                      cw;
530         const char                      *nss;
531         
532         
533         /* get sun shader supressor */
534         nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
535         
536         /* walk the list of surfaces */
537         for( i = 0; i < numBSPDrawSurfaces; i++ )
538         {
539                 /* get surface and other bits */
540                 ds = &bspDrawSurfaces[ i ];
541                 info = &surfaceInfos[ i ];
542                 si = info->si;
543                 
544                 /* sunlight? */
545                 if( si->sun != NULL && nss[ 0 ] != '1' )
546                 {
547                         Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
548                         CreateSunLight( si->sun );
549                         si->sun = NULL; /* FIXME: leak! */
550                 }
551                 
552                 /* sky light? */
553                 if( si->skyLightValue > 0.0f )
554                 {
555                         Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
556                         CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
557                         si->skyLightValue = 0.0f;       /* FIXME: hack! */
558                 }
559                 
560                 /* try to early out */
561                 if( si->value <= 0 )
562                         continue;
563                 
564                 /* autosprite shaders become point lights */
565                 if( si->autosprite )
566                 {
567                         /* create an average xyz */
568                         VectorAdd( info->mins, info->maxs, origin );
569                         VectorScale( origin, 0.5f, origin );
570                         
571                         /* create a light */
572                         light = safe_malloc( sizeof( *light ) );
573                         memset( light, 0, sizeof( *light ) );
574                         light->next = lights;
575                         lights = light;
576                         
577                         /* set it up */
578                         light->flags = LIGHT_Q3A_DEFAULT;
579                         light->type = EMIT_POINT;
580                         light->photons = si->value * pointScale;
581                         light->fade = 1.0f;
582                         light->si = si;
583                         VectorCopy( origin, light->origin );
584                         VectorCopy( si->color, light->color );
585                         light->falloffTolerance = falloffTolerance;
586                         light->style = si->lightStyle;
587                         
588                         /* add to point light count and continue */
589                         numPointLights++;
590                         continue;
591                 }
592                 
593                 /* get subdivision amount */
594                 if( si->lightSubdivide > 0 )
595                         subdivide = si->lightSubdivide;
596                 else
597                         subdivide = defaultLightSubdivide;
598                 
599                 /* switch on type */
600                 switch( ds->surfaceType )
601                 {
602                         case MST_PLANAR:
603                         case MST_TRIANGLE_SOUP:
604                                 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
605                                 break;
606                         
607                         case MST_PATCH:
608                                 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
609                                 break;
610                         
611                         default:
612                                 break;
613                 }
614         }
615 }
616
617
618
619 /*
620 SetEntityOrigins()
621 find the offset values for inline models
622 */
623
624 void SetEntityOrigins( void )
625 {
626         int                                     i, j, k, f;
627         entity_t                        *e;
628         vec3_t                          origin;
629         const char                      *key;
630         int                                     modelnum;
631         bspModel_t                      *dm;
632         bspDrawSurface_t        *ds;
633         
634         
635         /* ydnar: copy drawverts into private storage for nefarious purposes */
636         yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
637         memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
638         
639         /* set the entity origins */
640         for( i = 0; i < numEntities; i++ )
641         {
642                 /* get entity and model */
643                 e = &entities[ i ];
644                 key = ValueForKey( e, "model" );
645                 if( key[ 0 ] != '*' )
646                         continue;
647                 modelnum = atoi( key + 1 );
648                 dm = &bspModels[ modelnum ];
649                 
650                 /* get entity origin */
651                 key = ValueForKey( e, "origin" );
652                 if( key[ 0 ] == '\0' )
653                         continue;
654                 GetVectorForKey( e, "origin", origin );
655                 
656                 /* set origin for all surfaces for this model */
657                 for( j = 0; j < dm->numBSPSurfaces; j++ )
658                 {
659                         /* get drawsurf */
660                         ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
661                         
662                         /* set its verts */
663                         for( k = 0; k < ds->numVerts; k++ )
664                         {
665                                 f = ds->firstVert + k;
666                                 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
667                         }
668                 }
669         }
670 }
671
672
673
674 /*
675 PointToPolygonFormFactor()
676 calculates the area over a point/normal hemisphere a winding covers
677 ydnar: fixme: there has to be a faster way to calculate this
678 without the expensive per-vert sqrts and transcendental functions
679 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
680 between this and the approximation
681 */
682
683 #define ONE_OVER_2PI    0.159154942f    //% (1.0f / (2.0f * 3.141592657f))
684
685 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
686 {
687         vec3_t          triVector, triNormal;
688         int                     i, j;
689         vec3_t          dirs[ MAX_POINTS_ON_WINDING ];
690         float           total;
691         float           dot, angle, facing;
692         
693         
694         /* this is expensive */
695         for( i = 0; i < w->numpoints; i++ )
696         {
697                 VectorSubtract( w->p[ i ], point, dirs[ i ] );
698                 VectorNormalize( dirs[ i ], dirs[ i ] );
699         }
700         
701         /* duplicate first vertex to avoid mod operation */
702         VectorCopy( dirs[ 0 ], dirs[ i ] );
703         
704         /* calculcate relative area */
705         total = 0.0f;
706         for( i = 0; i < w->numpoints; i++ )
707         {
708                 /* get a triangle */
709                 j = i + 1;
710                 dot = DotProduct( dirs[ i ], dirs[ j ] );
711                 
712                 /* roundoff can cause slight creep, which gives an IND from acos */
713                 if( dot > 1.0f )
714                         dot = 1.0f;
715                 else if( dot < -1.0f )
716                         dot = -1.0f;
717                 
718                 /* get the angle */
719                 angle = acos( dot );
720                 
721                 CrossProduct( dirs[ i ], dirs[ j ], triVector );
722                 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
723                         continue;
724                 
725                 facing = DotProduct( normal, triNormal );
726                 total += facing * angle;
727                 
728                 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
729                 if( total > 6.3f || total < -6.3f )
730                         return 0.0f;
731         }
732         
733         /* now in the range of 0 to 1 over the entire incoming hemisphere */
734         //%     total /= (2.0f * 3.141592657f);
735         total *= ONE_OVER_2PI;
736         return total;
737 }
738
739
740
741 /*
742 LightContributionTosample()
743 determines the amount of light reaching a sample (luxel or vertex) from a given light
744 */
745
746 int LightContributionToSample( trace_t *trace )
747 {
748         light_t                 *light;
749         float                   angle;
750         float                   add;
751         float                   dist;
752         float                   addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
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         
2054         
2055         /* note it */
2056         Sys_Printf( "--- Light ---\n" );
2057         Sys_Printf( "--- ProcessGameSpecific ---\n" );
2058
2059         /* set standard game flags */
2060         wolfLight = game->wolfLight;
2061         if (wolfLight == qtrue)
2062                 Sys_Printf( " lightning model: wolf\n" );
2063         else
2064                 Sys_Printf( " lightning model: quake3\n" );
2065
2066         lmCustomSize = game->lightmapSize;
2067         Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2068
2069         lightmapGamma = game->lightmapGamma;
2070         Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2071
2072         lightmapCompensate = game->lightmapCompensate;
2073         Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2074
2075         lightmapExposure = game->lightmapExposure;
2076         Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2077
2078         gridScale = game->gridScale;
2079         Sys_Printf( " lightgrid scale: %f\n", gridScale );
2080
2081         gridAmbientScale = game->gridAmbientScale;
2082         Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2083
2084         lightAngleHL = game->lightAngleHL;
2085         if( lightAngleHL )
2086                 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2087
2088         noStyles = game->noStyles;
2089         if (noStyles == qtrue)
2090                 Sys_Printf( " shader lightstyles hack: disabled\n" );
2091         else
2092                 Sys_Printf( " shader lightstyles hack: enabled\n" );
2093
2094         keepLights = game->keepLights;
2095         if (keepLights == qtrue)
2096                 Sys_Printf( " keep lights: enabled\n" );
2097         else
2098                 Sys_Printf( " keep lights: disabled\n" );
2099
2100         patchShadows = game->patchShadows;
2101         if (patchShadows == qtrue)
2102                 Sys_Printf( " patch shadows: enabled\n" );
2103         else
2104                 Sys_Printf( " patch shadows: disabled\n" );
2105
2106         deluxemap = game->deluxeMap;
2107         deluxemode = game->deluxeMode;
2108         if (deluxemap == qtrue)
2109         {
2110                 if (deluxemode)
2111                         Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2112                 else
2113                         Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2114         }
2115         else
2116                 Sys_Printf( " deluxemapping: disabled\n" );
2117
2118         Sys_Printf( "--- ProcessCommandLine ---\n" );
2119         
2120         /* process commandline arguments */
2121         for( i = 1; i < (argc - 1); i++ )
2122         {
2123                 /* lightsource scaling */
2124                 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2125                 {
2126                         f = atof( argv[ i + 1 ] );
2127                         pointScale *= f;
2128                         Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2129                         i++;
2130                 }
2131                 
2132                 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2133                 {
2134                         f = atof( argv[ i + 1 ] );
2135                         areaScale *= f;
2136                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2137                         i++;
2138                 }
2139                 
2140                 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2141                 {
2142                         f = atof( argv[ i + 1 ] );
2143                         skyScale *= f;
2144                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2145                         i++;
2146                 }
2147                 
2148                 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2149                 {
2150                         f = atof( argv[ i + 1 ] );
2151                         bounceScale *= f;
2152                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2153                         i++;
2154                 }
2155                 
2156                 else if( !strcmp( argv[ i ], "-scale" ) )
2157                 {
2158                         f = atof( argv[ i + 1 ] );
2159                         pointScale *= f;
2160                         areaScale *= f;
2161                         skyScale *= f;
2162                         bounceScale *= f;
2163                         Sys_Printf( "All light scaled by %f\n", f );
2164                         i++;
2165                 }
2166
2167                 else if( !strcmp( argv[ i ], "-gridscale" ) )
2168                 {
2169                         f = atof( argv[ i + 1 ] );
2170                         Sys_Printf( "Grid lightning scaled by %f\n", f );
2171                         gridScale *= f;
2172                         i++;
2173                 }
2174
2175                 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2176                 {
2177                         f = atof( argv[ i + 1 ] );
2178                         Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2179                         gridAmbientScale *= f;
2180                         i++;
2181                 }
2182
2183                 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2184                 {
2185                         f = atof( argv[ i + 1 ] );
2186                         if(f < 0) f = 0;
2187                         if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2188                         Sys_Printf( "Grid directionality is %f\n", f );
2189                         gridDirectionality *= f;
2190                         i++;
2191                 }
2192
2193                 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2194                 {
2195                         f = atof( argv[ i + 1 ] );
2196                         if(f > gridDirectionality) f = gridDirectionality;
2197                         if(f > 1) f = 1;
2198                         Sys_Printf( "Grid ambient directionality is %f\n", f );
2199                         gridAmbientDirectionality *= f;
2200                         i++;
2201                 }
2202                 
2203                 else if( !strcmp( argv[ i ], "-gamma" ) )
2204                 {
2205                         f = atof( argv[ i + 1 ] );
2206                         lightmapGamma = f;
2207                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2208                         i++;
2209                 }
2210                 
2211                 else if( !strcmp( argv[ i ], "-exposure" ) )
2212                 {
2213                         f = atof( argv[ i + 1 ] );
2214                         lightmapExposure = f;
2215                         Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2216                         i++;
2217                 }
2218
2219                 else if( !strcmp( argv[ i ], "-compensate" ) )
2220                 {
2221                         f = atof( argv[ i + 1 ] );
2222                         if( f <= 0.0f )
2223                                 f = 1.0f;
2224                         lightmapCompensate = f;
2225                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2226                         i++;
2227                 }
2228                 
2229                 /* ydnar switches */
2230                 else if( !strcmp( argv[ i ], "-bounce" ) )
2231                 {
2232                         bounce = atoi( argv[ i + 1 ] );
2233                         if( bounce < 0 )
2234                                 bounce = 0;
2235                         else if( bounce > 0 )
2236                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2237                         i++;
2238                 }
2239                 
2240                 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2241                 {
2242                         superSample = atoi( argv[ i + 1 ] );
2243                         if( superSample < 1 )
2244                                 superSample = 1;
2245                         else if( superSample > 1 )
2246                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2247                         i++;
2248                 }
2249                 
2250                 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2251                 {
2252                         lightRandomSamples = qtrue;
2253                         Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2254                 }
2255                 
2256                 else if( !strcmp( argv[ i ], "-samples" ) )
2257                 {
2258                         lightSamples = atoi( argv[ i + 1 ] );
2259                         if( lightSamples < 1 )
2260                                 lightSamples = 1;
2261                         else if( lightSamples > 1 )
2262                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2263                         i++;
2264                 }
2265                 
2266                 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2267                 {
2268                         lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2269                         if( lightSamplesSearchBoxSize <= 0 )
2270                                 lightSamplesSearchBoxSize = 1;
2271                         if( lightSamplesSearchBoxSize > 4 )
2272                                 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2273                         else if( lightSamplesSearchBoxSize != 1 )
2274                                 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2275                         i++;
2276                 }
2277
2278                 else if( !strcmp( argv[ i ], "-filter" ) )
2279                 {
2280                         filter = qtrue;
2281                         Sys_Printf( "Lightmap filtering enabled\n" );
2282                 }
2283                 
2284                 else if( !strcmp( argv[ i ], "-dark" ) )
2285                 {
2286                         dark = qtrue;
2287                         Sys_Printf( "Dark lightmap seams enabled\n" );
2288                 }
2289                 
2290                 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2291                 {
2292                         shadeAngleDegrees = atof( argv[ i + 1 ] );
2293                         if( shadeAngleDegrees < 0.0f )
2294                                 shadeAngleDegrees = 0.0f;
2295                         else if( shadeAngleDegrees > 0.0f )
2296                         {
2297                                 shade = qtrue;
2298                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2299                         }
2300                         i++;
2301                 }
2302                 
2303                 else if( !strcmp( argv[ i ], "-thresh" ) )
2304                 {
2305                         subdivideThreshold = atof( argv[ i + 1 ] );
2306                         if( subdivideThreshold < 0 )
2307                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2308                         else
2309                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2310                         i++;
2311                 }
2312                 
2313                 else if( !strcmp( argv[ i ], "-approx" ) )
2314                 {
2315                         approximateTolerance = atoi( argv[ i + 1 ] );
2316                         if( approximateTolerance < 0 )
2317                                 approximateTolerance = 0;
2318                         else if( approximateTolerance > 0 )
2319                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2320                         i++;
2321                 }
2322                 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2323                 {
2324                         deluxemap = qtrue;
2325                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
2326                 }
2327                 else if( !strcmp( argv[ i ], "-deluxemode" ))
2328                 {
2329                         deluxemode = atoi( argv[ i + 1 ] );
2330                         if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2331                         {
2332                                 Sys_Printf( "Generating modelspace deluxemaps\n" );
2333                                 deluxemode = 0;
2334                         }
2335                         else 
2336                                 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2337                         i++;
2338                 }
2339                 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2340                 {
2341                         deluxemap = qfalse;
2342                         Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2343                 }
2344                 else if( !strcmp( argv[ i ], "-external" ) )
2345                 {
2346                         externalLightmaps = qtrue;
2347                         Sys_Printf( "Storing all lightmaps externally\n" );
2348                 }
2349
2350                 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2351                 {
2352                         lmCustomSize = atoi( argv[ i + 1 ] );
2353                         
2354                         /* must be a power of 2 and greater than 2 */
2355                         if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2356                         {
2357                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2358                                 lmCustomSize = game->lightmapSize;
2359                         }
2360                         i++;
2361                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2362                         
2363                         /* enable external lightmaps */
2364                         if( lmCustomSize != game->lightmapSize )
2365                         {
2366                                 externalLightmaps = qtrue;
2367                                 Sys_Printf( "Storing all lightmaps externally\n" );
2368                         }
2369                 }
2370                 
2371                 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2372                 {
2373                         lmLimitSize = atoi( argv[ i + 1 ] );
2374                         
2375                         i++;
2376                         Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2377                 }
2378                 
2379                 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2380                 {
2381                         lmCustomDir = argv[i + 1];
2382                         i++;
2383                         Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2384                         externalLightmaps = qtrue;
2385                         Sys_Printf( "Storing all lightmaps externally\n" );
2386                 }
2387                 
2388                 /* ydnar: add this to suppress warnings */
2389                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
2390                 {
2391                         Sys_Printf( "Custom info parms enabled\n" );
2392                         useCustomInfoParms = qtrue;
2393                 }
2394                 
2395                 else if( !strcmp( argv[ i ], "-wolf" ) )
2396                 {
2397                         /* -game should already be set */
2398                         wolfLight = qtrue;
2399                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2400                 }
2401                 
2402                 else if( !strcmp( argv[ i ], "-q3" ) )
2403                 {
2404                         /* -game should already be set */
2405                         wolfLight = qfalse;
2406                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2407                 }
2408
2409                 else if( !strcmp( argv[ i ], "-extradist" ) )
2410                 {
2411                         extraDist = atof( argv[ i + 1 ] );
2412                         if( extraDist < 0 )
2413                                 extraDist = 0;
2414                         i++;
2415                         Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2416                 }
2417                 
2418                 else if( !strcmp( argv[ i ], "-sunonly" ) )
2419                 {
2420                         sunOnly = qtrue;
2421                         Sys_Printf( "Only computing sunlight\n" );
2422                 }
2423                 
2424                 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2425                 {
2426                         bounceOnly = qtrue;
2427                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2428                 }
2429                 
2430                 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2431                 {
2432                         noCollapse = qtrue;
2433                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2434                 }
2435
2436                 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2437                 {
2438                         lightmapSearchBlockSize = 1;
2439                         Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2440                 }
2441                 
2442                 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2443                 {
2444                         lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2445                         ++i;
2446                         Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2447                 }
2448                 
2449                 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2450                 {
2451                         lightmapSearchBlockSize = atoi(argv[i+1]);
2452                         ++i;
2453                         Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2454                 }
2455                 
2456                 else if( !strcmp( argv[ i ], "-shade" ) )
2457                 {
2458                         shade = qtrue;
2459                         Sys_Printf( "Phong shading enabled\n" );
2460                 }
2461                 
2462                 else if( !strcmp( argv[ i ], "-bouncegrid") )
2463                 {
2464                         bouncegrid = qtrue;
2465                         if( bounce > 0 )
2466                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2467                 }
2468                 
2469                 else if( !strcmp( argv[ i ], "-smooth" ) )
2470                 {
2471                         lightSamples = EXTRA_SCALE;
2472                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2473                 }
2474                 
2475                 else if( !strcmp( argv[ i ], "-fast" ) )
2476                 {
2477                         fast = qtrue;
2478                         fastgrid = qtrue;
2479                         fastbounce = qtrue;
2480                         Sys_Printf( "Fast mode enabled\n" );
2481                 }
2482                 
2483                 else if( !strcmp( argv[ i ], "-faster" ) )
2484                 {
2485                         faster = qtrue;
2486                         fast = qtrue;
2487                         fastgrid = qtrue;
2488                         fastbounce = qtrue;
2489                         Sys_Printf( "Faster mode enabled\n" );
2490                 }
2491                 
2492                 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2493                 {
2494                         fastgrid = qtrue;
2495                         Sys_Printf( "Fast grid lighting enabled\n" );
2496                 }
2497                 
2498                 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2499                 {
2500                         fastbounce = qtrue;
2501                         Sys_Printf( "Fast bounce mode enabled\n" );
2502                 }
2503                 
2504                 else if( !strcmp( argv[ i ], "-cheap" ) )
2505                 {
2506                         cheap = qtrue;
2507                         cheapgrid = qtrue;
2508                         Sys_Printf( "Cheap mode enabled\n" );
2509                 }
2510
2511                 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2512                 {
2513                         cheapgrid = qtrue;
2514                         Sys_Printf( "Cheap grid mode enabled\n" );
2515                 }
2516                 
2517                 else if( !strcmp( argv[ i ], "-normalmap" ) )
2518                 {
2519                         normalmap = qtrue;
2520                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2521                 }
2522                 
2523                 else if( !strcmp( argv[ i ], "-trisoup" ) )
2524                 {
2525                         trisoup = qtrue;
2526                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2527                 }
2528                 
2529                 else if( !strcmp( argv[ i ], "-debug" ) )
2530                 {
2531                         debug = qtrue;
2532                         Sys_Printf( "Lightmap debugging enabled\n" );
2533                 }
2534                 
2535                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2536                 {
2537                         debugSurfaces = qtrue;
2538                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2539                 }
2540                 
2541                 else if( !strcmp( argv[ i ], "-debugunused" ) )
2542                 {
2543                         debugUnused = qtrue;
2544                         Sys_Printf( "Unused luxel debugging enabled\n" );
2545                 }
2546
2547                 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2548                 {
2549                         debugAxis = qtrue;
2550                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2551                 }
2552                 
2553                 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2554                 {
2555                         debugCluster = qtrue;
2556                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2557                 }
2558                 
2559                 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2560                 {
2561                         debugOrigin = qtrue;
2562                         Sys_Printf( "Luxel origin debugging enabled\n" );
2563                 }
2564                 
2565                 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2566                 {
2567                         deluxemap = qtrue;
2568                         debugDeluxemap = qtrue;
2569                         Sys_Printf( "Deluxemap debugging enabled\n" );
2570                 }
2571                 
2572                 else if( !strcmp( argv[ i ], "-export" ) )
2573                 {
2574                         exportLightmaps = qtrue;
2575                         Sys_Printf( "Exporting lightmaps\n" );
2576                 }
2577                 
2578                 else if( !strcmp(argv[ i ], "-notrace" )) 
2579                 {
2580                         noTrace = qtrue;
2581                         Sys_Printf( "Shadow occlusion disabled\n" );
2582                 }
2583                 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2584                 {
2585                         patchShadows = qtrue;
2586                         Sys_Printf( "Patch shadow casting enabled\n" );
2587                 }
2588                 else if( !strcmp( argv[ i ], "-extra" ) )
2589                 {
2590                         superSample = EXTRA_SCALE;              /* ydnar */
2591                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2592                 }
2593                 else if( !strcmp( argv[ i ], "-extrawide" ) )
2594                 {
2595                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2596                         filter = qtrue;                                 /* ydnar */
2597                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2598                 }
2599                 else if( !strcmp( argv[ i ], "-samplesize" ) )
2600                 {
2601                         sampleSize = atoi( argv[ i + 1 ] );
2602                         if( sampleSize < 1 )
2603                                 sampleSize = 1;
2604                         i++;
2605                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2606                 }
2607                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2608                 {
2609                         minSampleSize = atoi( argv[ i + 1 ] );
2610                         if( minSampleSize < 1 )
2611                                 minSampleSize = 1;
2612                         i++;
2613                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2614                 }
2615                 else if( !strcmp( argv[ i ],  "-samplescale" ) )
2616                 {
2617                         sampleScale = atoi( argv[ i + 1 ] );
2618                         i++;
2619                         Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2620                 }
2621                 else if( !strcmp( argv[ i ], "-novertex" ) )
2622                 {
2623                         noVertexLighting = qtrue;
2624                         Sys_Printf( "Disabling vertex lighting\n" );
2625                 }
2626                 else if( !strcmp( argv[ i ], "-nogrid" ) )
2627                 {
2628                         noGridLighting = qtrue;
2629                         Sys_Printf( "Disabling grid lighting\n" );
2630                 }
2631                 else if( !strcmp( argv[ i ], "-border" ) )
2632                 {
2633                         lightmapBorder = qtrue;
2634                         Sys_Printf( "Adding debug border to lightmaps\n" );
2635                 }
2636                 else if( !strcmp( argv[ i ], "-nosurf" ) )
2637                 {
2638                         noSurfaces = qtrue;
2639                         Sys_Printf( "Not tracing against surfaces\n" );
2640                 }
2641                 else if( !strcmp( argv[ i ], "-dump" ) )
2642                 {
2643                         dump = qtrue;
2644                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2645                 }
2646                 else if( !strcmp( argv[ i ], "-lomem" ) )
2647                 {
2648                         loMem = qtrue;
2649                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2650                 }
2651                 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2652                 {
2653                         if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2654                         {
2655                                 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2656                                 if( lightAngleHL )
2657                                         Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2658                                 else
2659                                         Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2660                         }
2661                 }
2662                 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2663                 {
2664                         noStyles = qtrue;
2665                         Sys_Printf( "Disabling lightstyles\n" );
2666                 }
2667                 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2668                 {
2669                         noStyles = qfalse;
2670                         Sys_Printf( "Enabling lightstyles\n" );
2671                 }
2672                 else if( !strcmp( argv[ i ], "-keeplights" ))
2673                 {
2674                         keepLights = qtrue;
2675                         Sys_Printf( "Leaving light entities on map after compile\n" );
2676                 }
2677                 else if( !strcmp( argv[ i ], "-cpma" ) )
2678                 {
2679                         cpmaHack = qtrue;
2680                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2681                 }
2682                 else if( !strcmp( argv[ i ], "-floodlight" ) )
2683                 {
2684                         floodlighty = qtrue;
2685                         Sys_Printf( "FloodLighting enabled\n" );
2686                 }
2687                 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2688                 {
2689                         debugnormals = qtrue;
2690                         Sys_Printf( "DebugNormals enabled\n" );
2691                 }
2692                 else if( !strcmp( argv[ i ], "-lowquality" ) )
2693                 {
2694                         floodlight_lowquality = qtrue;
2695                         Sys_Printf( "Low Quality FloodLighting enabled\n" );
2696                 }
2697                 
2698                 /* r7: dirtmapping */
2699                 else if( !strcmp( argv[ i ], "-dirty" ) )
2700                 {
2701                         dirty = qtrue;
2702                         Sys_Printf( "Dirtmapping enabled\n" );
2703                 }
2704                 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2705                 {
2706                         dirtDebug = qtrue;
2707                         Sys_Printf( "Dirtmap debugging enabled\n" );
2708                 }
2709                 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2710                 {
2711                         dirtMode = atoi( argv[ i + 1 ] );
2712                         if( dirtMode != 0 && dirtMode != 1 )
2713                                 dirtMode = 0;
2714                         if( dirtMode == 1 )
2715                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2716                         else
2717                                 Sys_Printf( "Enabling ordered dir mapping\n" );
2718                         i++;
2719                 }
2720                 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2721                 {
2722                         dirtDepth = atof( argv[ i + 1 ] );
2723                         if( dirtDepth <= 0.0f )
2724                                 dirtDepth = 128.0f;
2725                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2726                         i++;
2727                 }
2728                 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2729                 {
2730                         dirtScale = atof( argv[ i + 1 ] );
2731                         if( dirtScale <= 0.0f )
2732                                 dirtScale = 1.0f;
2733                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2734                         i++;
2735                 }
2736                 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2737                 {
2738                         dirtGain = atof( argv[ i + 1 ] );
2739                         if( dirtGain <= 0.0f )
2740                                 dirtGain = 1.0f;
2741                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2742                         i++;
2743                 }
2744                 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2745                 {
2746                         lightmapTriangleCheck = qtrue;
2747                 }
2748                 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2749                 {
2750                         lightmapExtraVisClusterNudge = qtrue;
2751                 }
2752                 /* unhandled args */
2753                 else
2754                 {
2755                         Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2756                 }
2757
2758         }
2759
2760         /* fix up lightmap search power */
2761         if(lightmapMergeSize)
2762         {
2763                 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2764                 if(lightmapSearchBlockSize < 1)
2765                         lightmapSearchBlockSize = 1;
2766
2767                 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2768         }
2769         
2770         /* clean up map name */
2771         strcpy( source, ExpandArg( argv[ i ] ) );
2772         StripExtension( source );
2773         DefaultExtension( source, ".bsp" );
2774         strcpy( mapSource, ExpandArg( argv[ i ] ) );
2775         StripExtension( mapSource );
2776         DefaultExtension( mapSource, ".map" );
2777         
2778         /* ydnar: set default sample size */
2779         SetDefaultSampleSize( sampleSize );
2780         
2781         /* ydnar: handle shaders */
2782         BeginMapShaderFile( source );
2783         LoadShaderInfo();
2784         
2785         /* note loading */
2786         Sys_Printf( "Loading %s\n", source );
2787         
2788         /* ydnar: load surface file */
2789         LoadSurfaceExtraFile( source );
2790         
2791         /* load bsp file */
2792         LoadBSPFile( source );
2793         
2794         /* parse bsp entities */
2795         ParseEntities();
2796
2797         /* inject command line parameters */
2798         InjectCommandLine(argv, 0, argc - 1);
2799         
2800         /* load map file */
2801         value = ValueForKey( &entities[ 0 ], "_keepLights" );
2802         if( value[ 0 ] != '1' )
2803                 LoadMapFile( mapSource, qtrue, qfalse );
2804         
2805         /* set the entity/model origins and init yDrawVerts */
2806         SetEntityOrigins();
2807         
2808         /* ydnar: set up optimization */
2809         SetupBrushes();
2810         SetupDirt();
2811         SetupFloodLight();
2812         SetupSurfaceLightmaps();
2813         
2814         /* initialize the surface facet tracing */
2815         SetupTraceNodes();
2816         
2817         /* light the world */
2818         LightWorld();
2819         
2820         /* ydnar: store off lightmaps */
2821         StoreSurfaceLightmaps();
2822         
2823         /* write out the bsp */
2824         UnparseEntities();
2825         Sys_Printf( "Writing %s\n", source );
2826         WriteBSPFile( source );
2827         
2828         /* ydnar: export lightmaps */
2829         if( exportLightmaps && !externalLightmaps )
2830                 ExportLightmaps();
2831         
2832         /* return to sender */
2833         return 0;
2834 }
2835