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