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