]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light.c
more warnings be gone
[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         lightmapCompensate = game->lightmapCompensate;
2069         Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2070
2071         lightmapExposure = game->lightmapExposure;
2072         Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2073
2074         gridScale = game->gridScale;
2075         Sys_Printf( " lightgrid scale: %f\n", gridScale );
2076
2077         gridAmbientScale = game->gridAmbientScale;
2078         Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2079
2080         lightAngleHL = game->lightAngleHL;
2081         if( lightAngleHL )
2082                 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2083
2084         noStyles = game->noStyles;
2085         if (noStyles == qtrue)
2086                 Sys_Printf( " shader lightstyles hack: disabled\n" );
2087         else
2088                 Sys_Printf( " shader lightstyles hack: enabled\n" );
2089
2090         keepLights = game->keepLights;
2091         if (keepLights == qtrue)
2092                 Sys_Printf( " keep lights: enabled\n" );
2093         else
2094                 Sys_Printf( " keep lights: disabled\n" );
2095
2096         patchShadows = game->patchShadows;
2097         if (patchShadows == qtrue)
2098                 Sys_Printf( " patch shadows: enabled\n" );
2099         else
2100                 Sys_Printf( " patch shadows: disabled\n" );
2101
2102         deluxemap = game->deluxeMap;
2103         deluxemode = game->deluxeMode;
2104         if (deluxemap == qtrue)
2105         {
2106                 if (deluxemode)
2107                         Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2108                 else
2109                         Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2110         }
2111         else
2112                 Sys_Printf( " deluxemapping: disabled\n" );
2113
2114         Sys_Printf( "--- ProcessCommandLine ---\n" );
2115         
2116         /* process commandline arguments */
2117         for( i = 1; i < (argc - 1); i++ )
2118         {
2119                 /* lightsource scaling */
2120                 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2121                 {
2122                         f = atof( argv[ i + 1 ] );
2123                         pointScale *= f;
2124                         Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2125                         i++;
2126                 }
2127                 
2128                 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2129                 {
2130                         f = atof( argv[ i + 1 ] );
2131                         areaScale *= f;
2132                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2133                         i++;
2134                 }
2135                 
2136                 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2137                 {
2138                         f = atof( argv[ i + 1 ] );
2139                         skyScale *= f;
2140                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2141                         i++;
2142                 }
2143                 
2144                 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2145                 {
2146                         f = atof( argv[ i + 1 ] );
2147                         bounceScale *= f;
2148                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2149                         i++;
2150                 }
2151                 
2152                 else if( !strcmp( argv[ i ], "-scale" ) )
2153                 {
2154                         f = atof( argv[ i + 1 ] );
2155                         pointScale *= f;
2156                         areaScale *= f;
2157                         skyScale *= f;
2158                         bounceScale *= f;
2159                         Sys_Printf( "All light scaled by %f\n", f );
2160                         i++;
2161                 }
2162
2163                 else if( !strcmp( argv[ i ], "-gridscale" ) )
2164                 {
2165                         f = atof( argv[ i + 1 ] );
2166                         Sys_Printf( "Grid lightning scaled by %f\n", f );
2167                         gridScale *= f;
2168                         i++;
2169                 }
2170
2171                 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2172                 {
2173                         f = atof( argv[ i + 1 ] );
2174                         Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2175                         gridAmbientScale *= f;
2176                         i++;
2177                 }
2178
2179                 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2180                 {
2181                         f = atof( argv[ i + 1 ] );
2182                         if(f > 1) f = 1;
2183                         if(f < gridAmbientDirectionality) gridAmbientDirectionality = f;
2184                         Sys_Printf( "Grid directionality is %f\n", f );
2185                         gridDirectionality = f;
2186                         i++;
2187                 }
2188
2189                 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2190                 {
2191                         f = atof( argv[ i + 1 ] );
2192                         if(f < -1) f = -1;
2193                         if(f > gridDirectionality) gridDirectionality = f;
2194                         Sys_Printf( "Grid ambient directionality is %f\n", f );
2195                         gridAmbientDirectionality = f;
2196                         i++;
2197                 }
2198                 
2199                 else if( !strcmp( argv[ i ], "-gamma" ) )
2200                 {
2201                         f = atof( argv[ i + 1 ] );
2202                         lightmapGamma = f;
2203                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2204                         i++;
2205                 }
2206                 
2207                 else if( !strcmp( argv[ i ], "-exposure" ) )
2208                 {
2209                         f = atof( argv[ i + 1 ] );
2210                         lightmapExposure = f;
2211                         Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2212                         i++;
2213                 }
2214
2215                 else if( !strcmp( argv[ i ], "-compensate" ) )
2216                 {
2217                         f = atof( argv[ i + 1 ] );
2218                         if( f <= 0.0f )
2219                                 f = 1.0f;
2220                         lightmapCompensate = f;
2221                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2222                         i++;
2223                 }
2224                 
2225                 /* ydnar switches */
2226                 else if( !strcmp( argv[ i ], "-bounce" ) )
2227                 {
2228                         bounce = atoi( argv[ i + 1 ] );
2229                         if( bounce < 0 )
2230                                 bounce = 0;
2231                         else if( bounce > 0 )
2232                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2233                         i++;
2234                 }
2235                 
2236                 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2237                 {
2238                         superSample = atoi( argv[ i + 1 ] );
2239                         if( superSample < 1 )
2240                                 superSample = 1;
2241                         else if( superSample > 1 )
2242                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2243                         i++;
2244                 }
2245                 
2246                 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2247                 {
2248                         lightRandomSamples = qtrue;
2249                         Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2250                 }
2251                 
2252                 else if( !strcmp( argv[ i ], "-samples" ) )
2253                 {
2254                         if(*argv[i+1] == '+')
2255                                 lightSamplesInsist = qtrue;
2256                         else
2257                                 lightSamplesInsist = qfalse;
2258                         lightSamples = atoi( argv[ i + 1 ] );
2259                         if( lightSamples < 1 )
2260                                 lightSamples = 1;
2261                         else if( lightSamples > 1 )
2262                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2263                         i++;
2264                 }
2265                 
2266                 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2267                 {
2268                         lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2269                         if( lightSamplesSearchBoxSize <= 0 )
2270                                 lightSamplesSearchBoxSize = 1;
2271                         if( lightSamplesSearchBoxSize > 4 )
2272                                 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2273                         else if( lightSamplesSearchBoxSize != 1 )
2274                                 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2275                         i++;
2276                 }
2277
2278                 else if( !strcmp( argv[ i ], "-filter" ) )
2279                 {
2280                         filter = qtrue;
2281                         Sys_Printf( "Lightmap filtering enabled\n" );
2282                 }
2283                 
2284                 else if( !strcmp( argv[ i ], "-dark" ) )
2285                 {
2286                         dark = qtrue;
2287                         Sys_Printf( "Dark lightmap seams enabled\n" );
2288                 }
2289                 
2290                 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2291                 {
2292                         shadeAngleDegrees = atof( argv[ i + 1 ] );
2293                         if( shadeAngleDegrees < 0.0f )
2294                                 shadeAngleDegrees = 0.0f;
2295                         else if( shadeAngleDegrees > 0.0f )
2296                         {
2297                                 shade = qtrue;
2298                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2299                         }
2300                         i++;
2301                 }
2302                 
2303                 else if( !strcmp( argv[ i ], "-thresh" ) )
2304                 {
2305                         subdivideThreshold = atof( argv[ i + 1 ] );
2306                         if( subdivideThreshold < 0 )
2307                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2308                         else
2309                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2310                         i++;
2311                 }
2312                 
2313                 else if( !strcmp( argv[ i ], "-approx" ) )
2314                 {
2315                         approximateTolerance = atoi( argv[ i + 1 ] );
2316                         if( approximateTolerance < 0 )
2317                                 approximateTolerance = 0;
2318                         else if( approximateTolerance > 0 )
2319                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2320                         i++;
2321                 }
2322                 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2323                 {
2324                         deluxemap = qtrue;
2325                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
2326                 }
2327                 else if( !strcmp( argv[ i ], "-deluxemode" ))
2328                 {
2329                         deluxemode = atoi( argv[ i + 1 ] );
2330                         if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2331                         {
2332                                 Sys_Printf( "Generating modelspace deluxemaps\n" );
2333                                 deluxemode = 0;
2334                         }
2335                         else 
2336                                 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2337                         i++;
2338                 }
2339                 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2340                 {
2341                         deluxemap = qfalse;
2342                         Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2343                 }
2344                 else if( !strcmp( argv[ i ], "-external" ) )
2345                 {
2346                         externalLightmaps = qtrue;
2347                         Sys_Printf( "Storing all lightmaps externally\n" );
2348                 }
2349
2350                 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2351                 {
2352                         lmCustomSize = atoi( argv[ i + 1 ] );
2353                         
2354                         /* must be a power of 2 and greater than 2 */
2355                         if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2356                         {
2357                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2358                                 lmCustomSize = game->lightmapSize;
2359                         }
2360                         i++;
2361                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2362                         
2363                         /* enable external lightmaps */
2364                         if( lmCustomSize != game->lightmapSize )
2365                         {
2366                                 externalLightmaps = qtrue;
2367                                 Sys_Printf( "Storing all lightmaps externally\n" );
2368                         }
2369                 }
2370                 
2371                 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2372                 {
2373                         lmLimitSize = atoi( argv[ i + 1 ] );
2374                         
2375                         i++;
2376                         Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2377                 }
2378                 
2379                 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2380                 {
2381                         lmCustomDir = argv[i + 1];
2382                         i++;
2383                         Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2384                         externalLightmaps = qtrue;
2385                         Sys_Printf( "Storing all lightmaps externally\n" );
2386                 }
2387                 
2388                 /* ydnar: add this to suppress warnings */
2389                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
2390                 {
2391                         Sys_Printf( "Custom info parms enabled\n" );
2392                         useCustomInfoParms = qtrue;
2393                 }
2394                 
2395                 else if( !strcmp( argv[ i ], "-wolf" ) )
2396                 {
2397                         /* -game should already be set */
2398                         wolfLight = qtrue;
2399                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2400                 }
2401                 
2402                 else if( !strcmp( argv[ i ], "-q3" ) )
2403                 {
2404                         /* -game should already be set */
2405                         wolfLight = qfalse;
2406                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2407                 }
2408
2409                 else if( !strcmp( argv[ i ], "-extradist" ) )
2410                 {
2411                         extraDist = atof( argv[ i + 1 ] );
2412                         if( extraDist < 0 )
2413                                 extraDist = 0;
2414                         i++;
2415                         Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2416                 }
2417                 
2418                 else if( !strcmp( argv[ i ], "-sunonly" ) )
2419                 {
2420                         sunOnly = qtrue;
2421                         Sys_Printf( "Only computing sunlight\n" );
2422                 }
2423                 
2424                 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2425                 {
2426                         bounceOnly = qtrue;
2427                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2428                 }
2429                 
2430                 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2431                 {
2432                         noCollapse = qtrue;
2433                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2434                 }
2435
2436                 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2437                 {
2438                         lightmapSearchBlockSize = 1;
2439                         Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2440                 }
2441                 
2442                 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2443                 {
2444                         lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2445                         ++i;
2446                         Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2447                 }
2448                 
2449                 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2450                 {
2451                         lightmapSearchBlockSize = atoi(argv[i+1]);
2452                         ++i;
2453                         Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2454                 }
2455                 
2456                 else if( !strcmp( argv[ i ], "-shade" ) )
2457                 {
2458                         shade = qtrue;
2459                         Sys_Printf( "Phong shading enabled\n" );
2460                 }
2461                 
2462                 else if( !strcmp( argv[ i ], "-bouncegrid") )
2463                 {
2464                         bouncegrid = qtrue;
2465                         if( bounce > 0 )
2466                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2467                 }
2468                 
2469                 else if( !strcmp( argv[ i ], "-smooth" ) )
2470                 {
2471                         lightSamples = EXTRA_SCALE;
2472                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2473                 }
2474                 
2475                 else if( !strcmp( argv[ i ], "-fast" ) )
2476                 {
2477                         fast = qtrue;
2478                         fastgrid = qtrue;
2479                         fastbounce = qtrue;
2480                         Sys_Printf( "Fast mode enabled\n" );
2481                 }
2482                 
2483                 else if( !strcmp( argv[ i ], "-faster" ) )
2484                 {
2485                         faster = qtrue;
2486                         fast = qtrue;
2487                         fastgrid = qtrue;
2488                         fastbounce = qtrue;
2489                         Sys_Printf( "Faster mode enabled\n" );
2490                 }
2491                 
2492                 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2493                 {
2494                         fastgrid = qtrue;
2495                         Sys_Printf( "Fast grid lighting enabled\n" );
2496                 }
2497                 
2498                 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2499                 {
2500                         fastbounce = qtrue;
2501                         Sys_Printf( "Fast bounce mode enabled\n" );
2502                 }
2503                 
2504                 else if( !strcmp( argv[ i ], "-cheap" ) )
2505                 {
2506                         cheap = qtrue;
2507                         cheapgrid = qtrue;
2508                         Sys_Printf( "Cheap mode enabled\n" );
2509                 }
2510
2511                 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2512                 {
2513                         cheapgrid = qtrue;
2514                         Sys_Printf( "Cheap grid mode enabled\n" );
2515                 }
2516                 
2517                 else if( !strcmp( argv[ i ], "-normalmap" ) )
2518                 {
2519                         normalmap = qtrue;
2520                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2521                 }
2522                 
2523                 else if( !strcmp( argv[ i ], "-trisoup" ) )
2524                 {
2525                         trisoup = qtrue;
2526                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2527                 }
2528                 
2529                 else if( !strcmp( argv[ i ], "-debug" ) )
2530                 {
2531                         debug = qtrue;
2532                         Sys_Printf( "Lightmap debugging enabled\n" );
2533                 }
2534                 
2535                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2536                 {
2537                         debugSurfaces = qtrue;
2538                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2539                 }
2540                 
2541                 else if( !strcmp( argv[ i ], "-debugunused" ) )
2542                 {
2543                         debugUnused = qtrue;
2544                         Sys_Printf( "Unused luxel debugging enabled\n" );
2545                 }
2546
2547                 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2548                 {
2549                         debugAxis = qtrue;
2550                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2551                 }
2552                 
2553                 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2554                 {
2555                         debugCluster = qtrue;
2556                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2557                 }
2558                 
2559                 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2560                 {
2561                         debugOrigin = qtrue;
2562                         Sys_Printf( "Luxel origin debugging enabled\n" );
2563                 }
2564                 
2565                 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2566                 {
2567                         deluxemap = qtrue;
2568                         debugDeluxemap = qtrue;
2569                         Sys_Printf( "Deluxemap debugging enabled\n" );
2570                 }
2571                 
2572                 else if( !strcmp( argv[ i ], "-export" ) )
2573                 {
2574                         exportLightmaps = qtrue;
2575                         Sys_Printf( "Exporting lightmaps\n" );
2576                 }
2577                 
2578                 else if( !strcmp(argv[ i ], "-notrace" )) 
2579                 {
2580                         noTrace = qtrue;
2581                         Sys_Printf( "Shadow occlusion disabled\n" );
2582                 }
2583                 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2584                 {
2585                         patchShadows = qtrue;
2586                         Sys_Printf( "Patch shadow casting enabled\n" );
2587                 }
2588                 else if( !strcmp( argv[ i ], "-extra" ) )
2589                 {
2590                         superSample = EXTRA_SCALE;              /* ydnar */
2591                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2592                 }
2593                 else if( !strcmp( argv[ i ], "-extrawide" ) )
2594                 {
2595                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2596                         filter = qtrue;                                 /* ydnar */
2597                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2598                 }
2599                 else if( !strcmp( argv[ i ], "-samplesize" ) )
2600                 {
2601                         sampleSize = atoi( argv[ i + 1 ] );
2602                         if( sampleSize < 1 )
2603                                 sampleSize = 1;
2604                         i++;
2605                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2606                 }
2607                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2608                 {
2609                         minSampleSize = atoi( argv[ i + 1 ] );
2610                         if( minSampleSize < 1 )
2611                                 minSampleSize = 1;
2612                         i++;
2613                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2614                 }
2615                 else if( !strcmp( argv[ i ],  "-samplescale" ) )
2616                 {
2617                         sampleScale = atoi( argv[ i + 1 ] );
2618                         i++;
2619                         Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2620                 }
2621                 else if( !strcmp( argv[ i ], "-novertex" ) )
2622                 {
2623                         noVertexLighting = qtrue;
2624                         Sys_Printf( "Disabling vertex lighting\n" );
2625                 }
2626                 else if( !strcmp( argv[ i ], "-nogrid" ) )
2627                 {
2628                         noGridLighting = qtrue;
2629                         Sys_Printf( "Disabling grid lighting\n" );
2630                 }
2631                 else if( !strcmp( argv[ i ], "-border" ) )
2632                 {
2633                         lightmapBorder = qtrue;
2634                         Sys_Printf( "Adding debug border to lightmaps\n" );
2635                 }
2636                 else if( !strcmp( argv[ i ], "-nosurf" ) )
2637                 {
2638                         noSurfaces = qtrue;
2639                         Sys_Printf( "Not tracing against surfaces\n" );
2640                 }
2641                 else if( !strcmp( argv[ i ], "-dump" ) )
2642                 {
2643                         dump = qtrue;
2644                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2645                 }
2646                 else if( !strcmp( argv[ i ], "-lomem" ) )
2647                 {
2648                         loMem = qtrue;
2649                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2650                 }
2651                 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2652                 {
2653                         if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2654                         {
2655                                 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2656                                 if( lightAngleHL )
2657                                         Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2658                                 else
2659                                         Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2660                         }
2661                 }
2662                 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2663                 {
2664                         noStyles = qtrue;
2665                         Sys_Printf( "Disabling lightstyles\n" );
2666                 }
2667                 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2668                 {
2669                         noStyles = qfalse;
2670                         Sys_Printf( "Enabling lightstyles\n" );
2671                 }
2672                 else if( !strcmp( argv[ i ], "-keeplights" ))
2673                 {
2674                         keepLights = qtrue;
2675                         Sys_Printf( "Leaving light entities on map after compile\n" );
2676                 }
2677                 else if( !strcmp( argv[ i ], "-cpma" ) )
2678                 {
2679                         cpmaHack = qtrue;
2680                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2681                 }
2682                 else if( !strcmp( argv[ i ], "-floodlight" ) )
2683                 {
2684                         floodlighty = qtrue;
2685                         Sys_Printf( "FloodLighting enabled\n" );
2686                 }
2687                 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2688                 {
2689                         debugnormals = qtrue;
2690                         Sys_Printf( "DebugNormals enabled\n" );
2691                 }
2692                 else if( !strcmp( argv[ i ], "-lowquality" ) )
2693                 {
2694                         floodlight_lowquality = qtrue;
2695                         Sys_Printf( "Low Quality FloodLighting enabled\n" );
2696                 }
2697                 
2698                 /* r7: dirtmapping */
2699                 else if( !strcmp( argv[ i ], "-dirty" ) )
2700                 {
2701                         dirty = qtrue;
2702                         Sys_Printf( "Dirtmapping enabled\n" );
2703                 }
2704                 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2705                 {
2706                         dirtDebug = qtrue;
2707                         Sys_Printf( "Dirtmap debugging enabled\n" );
2708                 }
2709                 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2710                 {
2711                         dirtMode = atoi( argv[ i + 1 ] );
2712                         if( dirtMode != 0 && dirtMode != 1 )
2713                                 dirtMode = 0;
2714                         if( dirtMode == 1 )
2715                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2716                         else
2717                                 Sys_Printf( "Enabling ordered dir mapping\n" );
2718                         i++;
2719                 }
2720                 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2721                 {
2722                         dirtDepth = atof( argv[ i + 1 ] );
2723                         if( dirtDepth <= 0.0f )
2724                                 dirtDepth = 128.0f;
2725                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2726                         i++;
2727                 }
2728                 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2729                 {
2730                         dirtScale = atof( argv[ i + 1 ] );
2731                         if( dirtScale <= 0.0f )
2732                                 dirtScale = 1.0f;
2733                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2734                         i++;
2735                 }
2736                 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2737                 {
2738                         dirtGain = atof( argv[ i + 1 ] );
2739                         if( dirtGain <= 0.0f )
2740                                 dirtGain = 1.0f;
2741                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2742                         i++;
2743                 }
2744                 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2745                 {
2746                         lightmapTriangleCheck = qtrue;
2747                 }
2748                 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2749                 {
2750                         lightmapExtraVisClusterNudge = qtrue;
2751                 }
2752                 else if( !strcmp( argv[ i ], "-fill" ) )
2753                 {
2754                         lightmapFill = qtrue;
2755                         Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2756                 }
2757                 /* unhandled args */
2758                 else
2759                 {
2760                         Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2761                 }
2762
2763         }
2764
2765         /* fix up samples count */
2766         if(lightRandomSamples)
2767         {
2768                 if(!lightSamplesInsist)
2769                 {
2770                         /* approximately match -samples in quality */
2771                         switch(lightSamples)
2772                         {
2773                                 /* somewhat okay */
2774                                 case 1:
2775                                 case 2:
2776                                         lightSamples = 16;
2777                                         Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2778                                         break;
2779
2780                                 /* good */
2781                                 case 3:
2782                                         lightSamples = 64;
2783                                         Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2784                                         break;
2785
2786                                 /* perfect */
2787                                 case 4:
2788                                         lightSamples = 256;
2789                                         Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2790                                         break;
2791
2792                                 default: break;
2793                         }
2794                 }
2795         }
2796
2797         /* fix up lightmap search power */
2798         if(lightmapMergeSize)
2799         {
2800                 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2801                 if(lightmapSearchBlockSize < 1)
2802                         lightmapSearchBlockSize = 1;
2803
2804                 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2805         }
2806         
2807         /* clean up map name */
2808         strcpy( source, ExpandArg( argv[ i ] ) );
2809         StripExtension( source );
2810         DefaultExtension( source, ".bsp" );
2811         strcpy( mapSource, ExpandArg( argv[ i ] ) );
2812         StripExtension( mapSource );
2813         DefaultExtension( mapSource, ".map" );
2814         
2815         /* ydnar: set default sample size */
2816         SetDefaultSampleSize( sampleSize );
2817         
2818         /* ydnar: handle shaders */
2819         BeginMapShaderFile( source );
2820         LoadShaderInfo();
2821         
2822         /* note loading */
2823         Sys_Printf( "Loading %s\n", source );
2824         
2825         /* ydnar: load surface file */
2826         LoadSurfaceExtraFile( source );
2827         
2828         /* load bsp file */
2829         LoadBSPFile( source );
2830         
2831         /* parse bsp entities */
2832         ParseEntities();
2833
2834         /* inject command line parameters */
2835         InjectCommandLine(argv, 0, argc - 1);
2836         
2837         /* load map file */
2838         value = ValueForKey( &entities[ 0 ], "_keepLights" );
2839         if( value[ 0 ] != '1' )
2840                 LoadMapFile( mapSource, qtrue, qfalse );
2841         
2842         /* set the entity/model origins and init yDrawVerts */
2843         SetEntityOrigins();
2844         
2845         /* ydnar: set up optimization */
2846         SetupBrushes();
2847         SetupDirt();
2848         SetupFloodLight();
2849         SetupSurfaceLightmaps();
2850         
2851         /* initialize the surface facet tracing */
2852         SetupTraceNodes();
2853         
2854         /* light the world */
2855         LightWorld();
2856         
2857         /* ydnar: store off lightmaps */
2858         StoreSurfaceLightmaps();
2859         
2860         /* write out the bsp */
2861         UnparseEntities();
2862         Sys_Printf( "Writing %s\n", source );
2863         WriteBSPFile( source );
2864         
2865         /* ydnar: export lightmaps */
2866         if( exportLightmaps && !externalLightmaps )
2867                 ExportLightmaps();
2868         
2869         /* return to sender */
2870         return 0;
2871 }
2872