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