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