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