]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light.c
79ebf77fe4ea11d62933455e0a5da3549db84edb
[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         float           step, start;
152         sun_t           sun;
153         
154         
155         /* dummy check */
156         if( value <= 0.0f || iterations < 2 )
157                 return;
158         
159         /* calculate some stuff */
160         step = 2.0f / (iterations - 1);
161         start = -1.0f;
162         
163         /* basic sun setup */
164         VectorCopy( color, sun.color );
165         sun.deviance = 0.0f;
166         sun.filterRadius = filterRadius;
167         sun.numSamples = 1;
168         sun.style = noStyles ? LS_NORMAL : style;
169         sun.next = NULL;
170         
171         /* setup */
172         elevationSteps = iterations - 1;
173         angleSteps = elevationSteps * 4;
174         angle = 0.0f;
175         elevationStep = DEG2RAD( 90.0f / iterations );  /* skip elevation 0 */
176         angleStep = DEG2RAD( 360.0f / angleSteps );
177         
178         /* calc individual sun brightness */
179         numSuns = angleSteps * elevationSteps + 1;
180         sun.photons = value / numSuns;
181         
182         /* iterate elevation */
183         elevation = elevationStep * 0.5f;
184         angle = 0.0f;
185         for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
186         {
187                 /* iterate angle */
188                 for( j = 0; j < angleSteps; j++ )
189                 {
190                         /* create sun */
191                         sun.direction[ 0 ] = cos( angle ) * cos( elevation );
192                         sun.direction[ 1 ] = sin( angle ) * cos( elevation );
193                         sun.direction[ 2 ] = sin( elevation );
194                         CreateSunLight( &sun );
195                         
196                         /* move */
197                         angle += angleStep;
198                 }
199                         
200                 /* move */
201                 elevation += elevationStep;
202                 angle += angleStep / elevationSteps;
203         }
204         
205         /* create vertical sun */
206         VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
207         CreateSunLight( &sun );
208         
209         /* short circuit */
210         return;
211 }
212
213
214
215 /*
216 CreateEntityLights()
217 creates lights from light entities
218 */
219
220 void CreateEntityLights( void )
221 {
222         int                             i, j;
223         light_t                 *light, *light2;
224         entity_t                *e, *e2;
225         const char              *name;
226         const char              *target;
227         vec3_t                  dest;
228         const char              *_color;
229         float                   intensity, scale, deviance, filterRadius;
230         int                             spawnflags, flags, numSamples;
231         qboolean                junior;
232
233         
234         /* go throught entity list and find lights */
235         for( i = 0; i < numEntities; i++ )
236         {
237                 /* get entity */
238                 e = &entities[ i ];
239                 name = ValueForKey( e, "classname" );
240                 
241                 /* ydnar: check for lightJunior */
242                 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
243                         junior = qtrue;
244                 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
245                         junior = qfalse;
246                 else
247                         continue;
248                 
249                 /* lights with target names (and therefore styles) are only parsed from BSP */
250                 target = ValueForKey( e, "targetname" );
251                 if( target[ 0 ] != '\0' && i >= numBSPEntities )
252                         continue;
253                 
254                 /* create a light */
255                 numPointLights++;
256                 light = safe_malloc( sizeof( *light ) );
257                 memset( light, 0, sizeof( *light ) );
258                 light->next = lights;
259                 lights = light;
260                 
261                 /* handle spawnflags */
262                 spawnflags = IntForKey( e, "spawnflags" );
263                 
264                 /* ydnar: quake 3+ light behavior */
265                 if( wolfLight == qfalse )
266                 {
267                         /* set default flags */
268                         flags = LIGHT_Q3A_DEFAULT;
269                         
270                         /* linear attenuation? */
271                         if( spawnflags & 1 )
272                         {
273                                 flags |= LIGHT_ATTEN_LINEAR;
274                                 flags &= ~LIGHT_ATTEN_ANGLE;
275                         }
276                         
277                         /* no angle attenuate? */
278                         if( spawnflags & 2 )
279                                 flags &= ~LIGHT_ATTEN_ANGLE;
280                 }
281                 
282                 /* ydnar: wolf light behavior */
283                 else
284                 {
285                         /* set default flags */
286                         flags = LIGHT_WOLF_DEFAULT;
287                         
288                         /* inverse distance squared attenuation? */
289                         if( spawnflags & 1 )
290                         {
291                                 flags &= ~LIGHT_ATTEN_LINEAR;
292                                 flags |= LIGHT_ATTEN_ANGLE;
293                         }
294                         
295                         /* angle attenuate? */
296                         if( spawnflags & 2 )
297                                 flags |= LIGHT_ATTEN_ANGLE;
298                 }
299                 
300                 /* other flags (borrowed from wolf) */
301                 
302                 /* wolf dark light? */
303                 if( (spawnflags & 4) || (spawnflags & 8) )
304                         flags |= LIGHT_DARK;
305                 
306                 /* nogrid? */
307                 if( spawnflags & 16 )
308                         flags &= ~LIGHT_GRID;
309                 
310                 /* junior? */
311                 if( junior )
312                 {
313                         flags |= LIGHT_GRID;
314                         flags &= ~LIGHT_SURFACES;
315                 }
316
317                 /* vortex: unnormalized? */
318                 if (spawnflags & 32)
319                         flags |= LIGHT_UNNORMALIZED;
320
321                 /* vortex: distance atten? */
322                 if (spawnflags & 64)
323                         flags |= LIGHT_ATTEN_DISTANCE;
324
325                 /* store the flags */
326                 light->flags = flags;
327                 
328                 /* ydnar: set fade key (from wolf) */
329                 light->fade = 1.0f;
330                 if( light->flags & LIGHT_ATTEN_LINEAR )
331                 {
332                         light->fade = FloatForKey( e, "fade" );
333                         if( light->fade == 0.0f )
334                                 light->fade = 1.0f;
335                 }
336                 
337                 /* ydnar: set angle scaling (from vlight) */
338                 light->angleScale = FloatForKey( e, "_anglescale" );
339                 if( light->angleScale != 0.0f )
340                         light->flags |= LIGHT_ATTEN_ANGLE;
341                 
342                 /* set origin */
343                 GetVectorForKey( e, "origin", light->origin);
344                 light->style = IntForKey( e, "_style" );
345                 if( light->style == LS_NORMAL )
346                         light->style = IntForKey( e, "style" );
347                 if( light->style < LS_NORMAL || light->style >= LS_NONE )
348                         Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
349                 
350                 if( light->style != LS_NORMAL ) {
351                         Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
352                 }
353
354                 /* set light intensity */
355                 intensity = FloatForKey( e, "_light" );
356                 if( intensity == 0.0f )
357                         intensity = FloatForKey( e, "light" );
358                 if( intensity == 0.0f)
359                         intensity = 300.0f;
360                 
361                 /* ydnar: set light scale (sof2) */
362                 scale = FloatForKey( e, "scale" );
363                 if( scale == 0.0f )
364                         scale = 1.0f;
365                 intensity *= scale;
366                 
367                 /* ydnar: get deviance and samples */
368                 deviance = FloatForKey( e, "_deviance" );
369                 if( deviance == 0.0f )
370                         deviance = FloatForKey( e, "_deviation" );
371                 if( deviance == 0.0f )
372                         deviance = FloatForKey( e, "_jitter" );
373                 numSamples = IntForKey( e, "_samples" );
374                 if( deviance < 0.0f || numSamples < 1 )
375                 {
376                         deviance = 0.0f;
377                         numSamples = 1;
378                 }
379                 intensity /= numSamples;
380                 
381                 /* ydnar: get filter radius */
382                 filterRadius = FloatForKey( e, "_filterradius" );
383                 if( filterRadius == 0.0f )
384                         filterRadius = FloatForKey( e, "_filteradius" );
385                 if( filterRadius == 0.0f )
386                         filterRadius = FloatForKey( e, "_filter" );
387                 if( filterRadius < 0.0f )
388                         filterRadius = 0.0f;
389                 light->filterRadius = filterRadius;
390                 
391                 /* set light color */
392                 _color = ValueForKey( e, "_color" );
393                 if( _color && _color[ 0 ] )
394                 {
395                         sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
396                         if (!(light->flags & LIGHT_UNNORMALIZED))
397                         {
398                                 ColorNormalize( light->color, light->color );
399                         }
400                 }
401                 else
402                         light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
403
404                 intensity = intensity * pointScale;
405                 light->photons = intensity;
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         
748         
749         /* get light */
750         light = trace->light;
751         
752         /* clear color */
753         VectorClear( trace->color );
754         VectorClear( trace->colorNoShadow );
755         
756         /* ydnar: early out */
757         if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
758                 return 0;
759         
760         /* do some culling checks */
761         if( light->type != EMIT_SUN )
762         {
763                 /* MrE: if the light is behind the surface */
764                 if( trace->twoSided == qfalse )
765                         if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
766                                 return 0;
767                 
768                 /* ydnar: test pvs */
769                 if( !ClusterVisible( trace->cluster, light->cluster ) )
770                         return 0;
771         }
772         
773         /* exact point to polygon form factor */
774         if( light->type == EMIT_AREA )
775         {
776                 float           factor;
777                 float           d;
778                 vec3_t          pushedOrigin;
779                 
780                 /* project sample point into light plane */
781                 d = DotProduct( trace->origin, light->normal ) - light->dist;
782                 if( d < 3.0f )
783                 {
784                         /* sample point behind plane? */
785                         if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
786                                 return 0;
787                         
788                         /* sample plane coincident? */
789                         if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
790                                 return 0;
791                 }
792                 
793                 /* nudge the point so that it is clearly forward of the light */
794                 /* so that surfaces meeting a light emiter don't get black edges */
795                 if( d > -8.0f && d < 8.0f )
796                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
797                 else
798                         VectorCopy( trace->origin, pushedOrigin );
799                 
800                 /* get direction and distance */
801                 VectorCopy( light->origin, trace->end );
802                 dist = SetupTrace( trace );
803                 if( dist >= light->envelope )
804                         return 0;
805                 
806                 /* ptpff approximation */
807                 if( faster )
808                 {
809                         /* angle attenuation */
810                         angle = DotProduct( trace->normal, trace->direction );
811                         
812                         /* twosided lighting */
813                         if( trace->twoSided )
814                                 angle = fabs( angle );
815                         
816                         /* attenuate */
817                         angle *= -DotProduct( light->normal, trace->direction );
818                         if( angle == 0.0f )
819                                 return 0;
820                         else if( angle < 0.0f &&
821                                 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
822                                 angle = -angle;
823                         add = light->photons / (dist * dist) * angle;
824                 }
825                 else
826                 {
827                         /* calculate the contribution */
828                         factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
829                         if( factor == 0.0f )
830                                 return 0;
831                         else if( factor < 0.0f )
832                         {
833                                 /* twosided lighting */
834                                 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
835                                 {
836                                         factor = -factor;
837
838                                         /* push light origin to other side of the plane */
839                                         VectorMA( light->origin, -2.0f, light->normal, trace->end );
840                                         dist = SetupTrace( trace );
841                                         if( dist >= light->envelope )
842                                                 return 0;
843                                 }
844                                 else
845                                         return 0;
846                         }
847                         
848                         /* ydnar: moved to here */
849                         add = factor * light->add;
850                 }
851         }
852         
853         /* point/spot lights */
854         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
855         {
856                 /* get direction and distance */
857                 VectorCopy( light->origin, trace->end );
858                 dist = SetupTrace( trace );
859                 if( dist >= light->envelope )
860                         return 0;
861                 
862                 /* clamp the distance to prevent super hot spots */
863                 if( dist < 16.0f )
864                         dist = 16.0f;
865                 
866                 /* angle attenuation */
867                 angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
868                 if( light->angleScale != 0.0f )
869                 {
870                         angle /= light->angleScale;
871                         if( angle > 1.0f )
872                                 angle = 1.0f;
873                 }
874                 
875                 /* twosided lighting */
876                 if( trace->twoSided )
877                         angle = fabs( angle );
878                 
879                 /* attenuate */
880                 if( light->flags & LIGHT_ATTEN_LINEAR )
881                 {
882                         add = angle * light->photons * linearScale - (dist * light->fade);
883                         if( add < 0.0f )
884                                 add = 0.0f;
885                 }
886                 else
887                         add = light->photons / (dist * dist) * angle;
888                 
889                 /* handle spotlights */
890                 if( light->type == EMIT_SPOT )
891                 {
892                         float   distByNormal, radiusAtDist, sampleRadius;
893                         vec3_t  pointAtDist, distToSample;
894         
895                         /* do cone calculation */
896                         distByNormal = -DotProduct( trace->displacement, light->normal );
897                         if( distByNormal < 0.0f )
898                                 return 0;
899                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
900                         radiusAtDist = light->radiusByDist * distByNormal;
901                         VectorSubtract( trace->origin, pointAtDist, distToSample );
902                         sampleRadius = VectorLength( distToSample );
903                         
904                         /* outside the cone */
905                         if( sampleRadius >= radiusAtDist )
906                                 return 0;
907                         
908                         /* attenuate */
909                         if( sampleRadius > (radiusAtDist - 32.0f) )
910                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
911                 }
912         }
913         
914         /* ydnar: sunlight */
915         else if( light->type == EMIT_SUN )
916         {
917                 /* get origin and direction */
918                 VectorAdd( trace->origin, light->origin, trace->end );
919                 dist = SetupTrace( trace );
920                 
921                 /* angle attenuation */
922                 angle = (light->flags & LIGHT_ATTEN_ANGLE)
923                         ? DotProduct( trace->normal, trace->direction )
924                         : 1.0f;
925                 
926                 /* twosided lighting */
927                 if( trace->twoSided )
928                         angle = fabs( angle );
929                 
930                 /* attenuate */
931                 add = light->photons * angle;
932                 if( add <= 0.0f )
933                         return 0;
934
935                 /* VorteX: set noShadow color */
936                 VectorScale(light->color, add, trace->colorNoShadow);
937                 
938                 /* setup trace */
939                 trace->testAll = qtrue;
940                 VectorScale( light->color, add, trace->color );
941                 
942                 /* trace to point */
943                 if( trace->testOcclusion && !trace->forceSunlight )
944                 {
945                         /* trace */
946                         TraceLine( trace );
947                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
948                         {
949                                 VectorClear( trace->color );
950                                 return -1;
951                         }
952                 }
953                 
954                 /* return to sender */
955                 return 1;
956         }
957
958         /* VorteX: set noShadow color */
959         VectorScale(light->color, add, trace->colorNoShadow);
960         
961         /* ydnar: changed to a variable number */
962         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
963                 return 0;
964         
965         /* setup trace */
966         trace->testAll = qfalse;
967         VectorScale( light->color, add, trace->color );
968         
969         /* raytrace */
970         TraceLine( trace );
971         if( trace->passSolid || trace->opaque )
972         {
973                 VectorClear( trace->color );
974                 return -1;
975         }
976         
977         /* return to sender */
978         return 1;
979 }
980
981
982
983 /*
984 LightingAtSample()
985 determines the amount of light reaching a sample (luxel or vertex)
986 */
987
988 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
989 {
990         int                             i, lightmapNum;
991         
992         
993         /* clear colors */
994         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
995                 VectorClear( colors[ lightmapNum ] );
996         
997         /* ydnar: normalmap */
998         if( normalmap )
999         {
1000                 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1001                 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1002                 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1003                 return;
1004         }
1005         
1006         /* ydnar: don't bounce ambient all the time */
1007         if( !bouncing )
1008                 VectorCopy( ambientColor, colors[ 0 ] );
1009         
1010         /* ydnar: trace to all the list of lights pre-stored in tw */
1011         for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1012         {
1013                 /* set light */
1014                 trace->light = trace->lights[ i ];
1015                 
1016                 /* style check */
1017                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1018                 {
1019                         if( styles[ lightmapNum ] == trace->light->style ||
1020                                 styles[ lightmapNum ] == LS_NONE )
1021                                 break;
1022                 }
1023                 
1024                 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1025                 if( lightmapNum >= MAX_LIGHTMAPS )
1026                         continue;
1027                 
1028                 /* sample light */
1029                 LightContributionToSample( trace );
1030                 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1031                         continue;
1032                 
1033                 /* handle negative light */
1034                 if( trace->light->flags & LIGHT_NEGATIVE )
1035                         VectorScale( trace->color, -1.0f, trace->color );
1036                 
1037                 /* set style */
1038                 styles[ lightmapNum ] = trace->light->style;
1039                 
1040                 /* add it */
1041                 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1042                 
1043                 /* cheap mode */
1044                 if( cheap &&
1045                         colors[ 0 ][ 0 ] >= 255.0f &&
1046                         colors[ 0 ][ 1 ] >= 255.0f &&
1047                         colors[ 0 ][ 2 ] >= 255.0f )
1048                         break;
1049         }
1050 }
1051
1052
1053
1054 /*
1055 LightContributionToPoint()
1056 for a given light, how much light/color reaches a given point in space (with no facing)
1057 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1058 */
1059
1060 int LightContributionToPoint( trace_t *trace )
1061 {
1062         light_t         *light;
1063         float           add, dist;
1064         
1065         
1066         /* get light */
1067         light = trace->light;
1068         
1069         /* clear color */
1070         VectorClear( trace->color );
1071         
1072         /* ydnar: early out */
1073         if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1074                 return qfalse;
1075         
1076         /* is this a sun? */
1077         if( light->type != EMIT_SUN )
1078         {
1079                 /* sun only? */
1080                 if( sunOnly )
1081                         return qfalse;
1082                 
1083                 /* test pvs */
1084                 if( !ClusterVisible( trace->cluster, light->cluster ) )
1085                         return qfalse;
1086         }
1087         
1088         /* ydnar: check origin against light's pvs envelope */
1089         if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1090                 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1091                 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1092         {
1093                 gridBoundsCulled++;
1094                 return qfalse;
1095         }
1096         
1097         /* set light origin */
1098         if( light->type == EMIT_SUN )
1099                 VectorAdd( trace->origin, light->origin, trace->end );
1100         else
1101                 VectorCopy( light->origin, trace->end );
1102         
1103         /* set direction */
1104         dist = SetupTrace( trace );
1105         
1106         /* test envelope */
1107         if( dist > light->envelope )
1108         {
1109                 gridEnvelopeCulled++;
1110                 return qfalse;
1111         }
1112         
1113         /* ptpff approximation */
1114         if( light->type == EMIT_AREA && faster )
1115         {
1116                 /* clamp the distance to prevent super hot spots */
1117                 if( dist < 16.0f )
1118                         dist = 16.0f;
1119                 
1120                 /* attenuate */
1121                 add = light->photons / (dist * dist);
1122         }
1123         
1124         /* exact point to polygon form factor */
1125         else if( light->type == EMIT_AREA )
1126         {
1127                 float           factor, d;
1128                 vec3_t          pushedOrigin;
1129                 
1130                 
1131                 /* see if the point is behind the light */
1132                 d = DotProduct( trace->origin, light->normal ) - light->dist;
1133                 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1134                         return qfalse;
1135                 
1136                 /* nudge the point so that it is clearly forward of the light */
1137                 /* so that surfaces meeting a light emiter don't get black edges */
1138                 if( d > -8.0f && d < 8.0f )
1139                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
1140                 else
1141                         VectorCopy( trace->origin, pushedOrigin );
1142                 
1143                 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1144                 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1145                 if( factor == 0.0f )
1146                         return qfalse;
1147                 else if( factor < 0.0f )
1148                 {
1149                         if( light->flags & LIGHT_TWOSIDED )
1150                                 factor = -factor;
1151                         else
1152                                 return qfalse;
1153                 }
1154                 
1155                 /* ydnar: moved to here */
1156                 add = factor * light->add;
1157         }
1158         
1159         /* point/spot lights */
1160         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1161         {
1162                 /* clamp the distance to prevent super hot spots */
1163                 if( dist < 16.0f )
1164                         dist = 16.0f;
1165                 
1166                 /* attenuate */
1167                 if( light->flags & LIGHT_ATTEN_LINEAR )
1168                 {
1169                         add = light->photons * linearScale - (dist * light->fade);
1170                         if( add < 0.0f )
1171                                 add = 0.0f;
1172                 }
1173                 else
1174                         add = light->photons / (dist * dist);
1175                 
1176                 /* handle spotlights */
1177                 if( light->type == EMIT_SPOT )
1178                 {
1179                         float   distByNormal, radiusAtDist, sampleRadius;
1180                         vec3_t  pointAtDist, distToSample;
1181                         
1182                         
1183                         /* do cone calculation */
1184                         distByNormal = -DotProduct( trace->displacement, light->normal );
1185                         if( distByNormal < 0.0f )
1186                                 return qfalse;
1187                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1188                         radiusAtDist = light->radiusByDist * distByNormal;
1189                         VectorSubtract( trace->origin, pointAtDist, distToSample );
1190                         sampleRadius = VectorLength( distToSample );
1191                         
1192                         /* outside the cone */
1193                         if( sampleRadius >= radiusAtDist )
1194                                 return qfalse;
1195                         
1196                         /* attenuate */
1197                         if( sampleRadius > (radiusAtDist - 32.0f) )
1198                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1199                 }
1200         }
1201         
1202         /* ydnar: sunlight */
1203         else if( light->type == EMIT_SUN )
1204         {
1205                 /* attenuate */
1206                 add = light->photons;
1207                 if( add <= 0.0f )
1208                         return qfalse;
1209                 
1210                 /* setup trace */
1211                 trace->testAll = qtrue;
1212                 VectorScale( light->color, add, trace->color );
1213                 
1214                 /* trace to point */
1215                 if( trace->testOcclusion && !trace->forceSunlight )
1216                 {
1217                         /* trace */
1218                         TraceLine( trace );
1219                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
1220                         {
1221                                 VectorClear( trace->color );
1222                                 return -1;
1223                         }
1224                 }
1225                 
1226                 /* return to sender */
1227                 return qtrue;
1228         }
1229         
1230         /* unknown light type */
1231         else
1232                 return qfalse;
1233         
1234         /* ydnar: changed to a variable number */
1235         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1236                 return qfalse;
1237         
1238         /* setup trace */
1239         trace->testAll = qfalse;
1240         VectorScale( light->color, add, trace->color );
1241         
1242         /* trace */
1243         TraceLine( trace );
1244         if( trace->passSolid )
1245         {
1246                 VectorClear( trace->color );
1247                 return qfalse;
1248         }
1249         
1250         /* we have a valid sample */
1251         return qtrue;
1252 }
1253
1254
1255
1256 /*
1257 TraceGrid()
1258 grid samples are for quickly determining the lighting
1259 of dynamically placed entities in the world
1260 */
1261
1262 #define MAX_CONTRIBUTIONS       1024
1263
1264 typedef struct
1265 {
1266         vec3_t          dir;
1267         vec3_t          color;
1268         int                     style;
1269 }
1270 contribution_t;
1271
1272 void TraceGrid( int num )
1273 {
1274         int                                             i, j, x, y, z, mod, step, numCon, numStyles;
1275         float                                   d;
1276         vec3_t                                  baseOrigin, cheapColor, color;
1277         rawGridPoint_t                  *gp;
1278         bspGridPoint_t                  *bgp;
1279         contribution_t                  contributions[ MAX_CONTRIBUTIONS ];
1280         trace_t                                 trace;
1281         
1282         
1283         /* get grid points */
1284         gp = &rawGridPoints[ num ];
1285         bgp = &bspGridPoints[ num ];
1286         
1287         /* get grid origin */
1288         mod = num;
1289         z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1290         mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1291         y = mod / gridBounds[ 0 ];
1292         mod -= y * gridBounds[ 0 ];
1293         x = mod;
1294         
1295         trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1296         trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1297         trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1298         
1299         /* set inhibit sphere */
1300         if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1301                 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1302         else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1303                 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1304         else
1305                 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1306         
1307         /* find point cluster */
1308         trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1309         if( trace.cluster < 0 )
1310         {
1311                 /* try to nudge the origin around to find a valid point */
1312                 VectorCopy( trace.origin, baseOrigin );
1313                 for( step = 9; step <= 18; step += 9 )
1314                 {
1315                         for( i = 0; i < 8; i++ )
1316                         {
1317                                 VectorCopy( baseOrigin, trace.origin );
1318                                 if( i & 1 )
1319                                         trace.origin[ 0 ] += step;
1320                                 else
1321                                         trace.origin[ 0 ] -= step;
1322                                 
1323                                 if( i & 2 )
1324                                         trace.origin[ 1 ] += step;
1325                                 else
1326                                         trace.origin[ 1 ] -= step;
1327                                 
1328                                 if( i & 4 )
1329                                         trace.origin[ 2 ] += step;
1330                                 else
1331                                         trace.origin[ 2 ] -= step;
1332                                 
1333                                 /* ydnar: changed to find cluster num */
1334                                 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1335                                 if( trace.cluster >= 0 )
1336                                         break;
1337                         }
1338                         
1339                         if( i != 8 )
1340                                 break;
1341                 }
1342                 
1343                 /* can't find a valid point at all */
1344                 if( step > 18 )
1345                         return;
1346         }
1347         
1348         /* setup trace */
1349         trace.testOcclusion = !noTrace;
1350         trace.forceSunlight = qfalse;
1351         trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1352         trace.numSurfaces = 0;
1353         trace.surfaces = NULL;
1354         trace.numLights = 0;
1355         trace.lights = NULL;
1356         
1357         /* clear */
1358         numCon = 0;
1359         VectorClear( cheapColor );
1360         
1361         /* trace to all the lights, find the major light direction, and divide the
1362            total light between that along the direction and the remaining in the ambient */
1363         for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1364         {
1365                 float           addSize;
1366                 
1367                 
1368                 /* sample light */
1369                 if( !LightContributionToPoint( &trace ) )
1370                         continue;
1371                 
1372                 /* handle negative light */
1373                 if( trace.light->flags & LIGHT_NEGATIVE )
1374                         VectorScale( trace.color, -1.0f, trace.color );
1375                 
1376                 /* add a contribution */
1377                 VectorCopy( trace.color, contributions[ numCon ].color );
1378                 VectorCopy( trace.direction, contributions[ numCon ].dir );
1379                 contributions[ numCon ].style = trace.light->style;
1380                 numCon++;
1381                 
1382                 /* push average direction around */
1383                 addSize = VectorLength( trace.color );
1384                 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1385                 
1386                 /* stop after a while */
1387                 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1388                         break;
1389                 
1390                 /* ydnar: cheap mode */
1391                 VectorAdd( cheapColor, trace.color, cheapColor );
1392                 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1393                         break;
1394         }
1395         
1396         /////// Floodlighting for point //////////////////
1397         //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1398         if (floodlighty)
1399         {
1400                 int q;
1401                 float addSize,f;
1402                 vec3_t col,dir;
1403                 col[0]=col[1]=col[2]=floodlightIntensity;
1404                 dir[0]=dir[1]=0;
1405                 dir[2]=1;
1406
1407                 trace.testOcclusion = qtrue;
1408                 trace.forceSunlight = qfalse;
1409                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1410                 trace.testAll = qtrue;
1411
1412                 for (q=0;q<2;q++)
1413                 {
1414                         if (q==0) //upper hemisphere
1415                         {
1416                                 trace.normal[0]=0;
1417                                 trace.normal[1]=0;
1418                                 trace.normal[2]=1;
1419                         }
1420                         else //lower hemisphere
1421                         {
1422                                 trace.normal[0]=0;
1423                                 trace.normal[1]=0;
1424                                 trace.normal[2]=-1;
1425                         }
1426
1427                         f = FloodLightForSample(&trace, floodlightDistance, floodlight_lowquality);
1428
1429                         contributions[ numCon ].color[0]=col[0]*f;
1430                         contributions[ numCon ].color[1]=col[1]*f;
1431                         contributions[ numCon ].color[2]=col[2]*f;
1432
1433                         contributions[ numCon ].dir[0]=dir[0];
1434                         contributions[ numCon ].dir[1]=dir[1];
1435                         contributions[ numCon ].dir[2]=dir[2];
1436
1437                         contributions[ numCon ].style = 0;
1438                         numCon++;
1439                         /* push average direction around */
1440                         addSize = VectorLength( col );
1441                         VectorMA( gp->dir, addSize, dir, gp->dir );
1442                 }
1443         }
1444         /////////////////////
1445
1446         /* normalize to get primary light direction */
1447         VectorNormalize( gp->dir, gp->dir );
1448         
1449         /* now that we have identified the primary light direction,
1450            go back and separate all the light into directed and ambient */
1451         numStyles = 1;
1452         for( i = 0; i < numCon; i++ )
1453         {
1454                 /* get relative directed strength */
1455                 d = DotProduct( contributions[ i ].dir, gp->dir );
1456                 if( d < 0.0f )
1457                         d = 0.0f;
1458                 
1459                 /* find appropriate style */
1460                 for( j = 0; j < numStyles; j++ )
1461                 {
1462                         if( gp->styles[ j ] == contributions[ i ].style )
1463                                 break;
1464                 }
1465                 
1466                 /* style not found? */
1467                 if( j >= numStyles )
1468                 {
1469                         /* add a new style */
1470                         if( numStyles < MAX_LIGHTMAPS )
1471                         {
1472                                 gp->styles[ numStyles ] = contributions[ i ].style;
1473                                 bgp->styles[ numStyles ] = contributions[ i ].style;
1474                                 numStyles++;
1475                                 //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1476                         }
1477                         
1478                         /* fallback */
1479                         else
1480                                 j = 0;
1481                 }
1482                 
1483                 /* add the directed color */
1484                 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1485                 
1486                 /* ambient light will be at 1/4 the value of directed light */
1487                 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1488                 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1489 //              d = 0.25f;
1490                 /* (Hobbes: always setting it to .25 is hardly any better) */
1491                 d = 0.25f * (1.0f - d);
1492                 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1493         }
1494         
1495         
1496         /* store off sample */
1497         for( i = 0; i < MAX_LIGHTMAPS; i++ )
1498         {
1499                 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1500                 if( !bouncing )
1501                         VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1502                 
1503                 /* set minimum light and copy off to bytes */
1504                 VectorCopy( gp->ambient[ i ], color );
1505                 for( j = 0; j < 3; j++ )
1506                         if( color[ j ] < minGridLight[ j ] )
1507                                 color[ j ] = minGridLight[ j ];
1508
1509                 /* vortex: apply gridscale and gridambientscale here */
1510                 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1511                 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1512         }
1513         
1514         /* debug code */
1515         #if 0
1516                 //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1517                 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1518                         num,
1519                         gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1520                         gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1521         #endif
1522         
1523         /* store direction */
1524         if( !bouncing )
1525                 NormalToLatLong( gp->dir, bgp->latLong );
1526 }
1527
1528
1529
1530 /*
1531 SetupGrid()
1532 calculates the size of the lightgrid and allocates memory
1533 */
1534
1535 void SetupGrid( void )
1536 {
1537         int                     i, j;
1538         vec3_t          maxs, oldGridSize;
1539         const char      *value;
1540         char            temp[ 64 ];
1541         
1542          
1543         /* don't do this if not grid lighting */
1544         if( noGridLighting )
1545                 return;
1546         
1547         /* ydnar: set grid size */
1548         value = ValueForKey( &entities[ 0 ], "gridsize" );
1549         if( value[ 0 ] != '\0' )
1550                 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1551         
1552         /* quantize it */
1553         VectorCopy( gridSize, oldGridSize );
1554         for( i = 0; i < 3; i++ )
1555                 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1556         
1557         /* ydnar: increase gridSize until grid count is smaller than max allowed */
1558         numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1559         j = 0;
1560         while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1561         {
1562                 /* get world bounds */
1563                 for( i = 0; i < 3; i++ )
1564                 {
1565                         gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1566                         maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1567                         gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1568                 }
1569         
1570                 /* set grid size */
1571                 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1572                 
1573                 /* increase grid size a bit */
1574                 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1575                         gridSize[ j++ % 3 ] += 16.0f;
1576         }
1577         
1578         /* print it */
1579         Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1580         
1581         /* different? */
1582         if( !VectorCompare( gridSize, oldGridSize ) )
1583         {
1584                 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1585                 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1586                 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1587         }
1588         
1589         /* 2nd variable. fixme: is this silly? */
1590         numBSPGridPoints = numRawGridPoints;
1591         
1592         /* allocate lightgrid */
1593         rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1594         memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1595         
1596         if( bspGridPoints != NULL )
1597                 free( bspGridPoints );
1598         bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1599         memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1600         
1601         /* clear lightgrid */
1602         for( i = 0; i < numRawGridPoints; i++ )
1603         {
1604                 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1605                 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1606                 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1607                 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1608                 {
1609                         rawGridPoints[ i ].styles[ j ] = LS_NONE;
1610                         bspGridPoints[ i ].styles[ j ] = LS_NONE;
1611                 }
1612         }
1613         
1614         /* note it */
1615         Sys_Printf( "%9d grid points\n", numRawGridPoints );
1616 }
1617
1618
1619
1620 /*
1621 LightWorld()
1622 does what it says...
1623 */
1624
1625 void LightWorld( void )
1626 {
1627         vec3_t          color;
1628         float           f;
1629         int                     b, bt;
1630         qboolean        minVertex, minGrid;
1631         const char      *value;
1632         
1633
1634         /* ydnar: smooth normals */
1635         if( shade )
1636         {
1637                 Sys_Printf( "--- SmoothNormals ---\n" );
1638                 SmoothNormals();
1639         }
1640         
1641         /* determine the number of grid points */
1642         Sys_Printf( "--- SetupGrid ---\n" );
1643         SetupGrid();
1644         
1645         /* find the optional minimum lighting values */
1646         GetVectorForKey( &entities[ 0 ], "_color", color );
1647         if( VectorLength( color ) == 0.0f )
1648                 VectorSet( color, 1.0, 1.0, 1.0 );
1649         
1650         /* ambient */
1651         f = FloatForKey( &entities[ 0 ], "_ambient" );
1652         if( f == 0.0f )
1653                 f = FloatForKey( &entities[ 0 ], "ambient" );
1654         VectorScale( color, f, ambientColor );
1655         
1656         /* minvertexlight */
1657         minVertex = qfalse;
1658         value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1659         if( value[ 0 ] != '\0' )
1660         {
1661                 minVertex = qtrue;
1662                 f = atof( value );
1663                 VectorScale( color, f, minVertexLight );
1664         }
1665         
1666         /* mingridlight */
1667         minGrid = qfalse;
1668         value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1669         if( value[ 0 ] != '\0' )
1670         {
1671                 minGrid = qtrue;
1672                 f = atof( value );
1673                 VectorScale( color, f, minGridLight );
1674         }
1675         
1676         /* minlight */
1677         value = ValueForKey( &entities[ 0 ], "_minlight" );
1678         if( value[ 0 ] != '\0' )
1679         {
1680                 f = atof( value );
1681                 VectorScale( color, f, minLight );
1682                 if( minVertex == qfalse )
1683                         VectorScale( color, f, minVertexLight );
1684                 if( minGrid == qfalse )
1685                         VectorScale( color, f, minGridLight );
1686         }
1687         
1688         /* create world lights */
1689         Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1690         CreateEntityLights();
1691         CreateSurfaceLights();
1692         Sys_Printf( "%9d point lights\n", numPointLights );
1693         Sys_Printf( "%9d spotlights\n", numSpotLights );
1694         Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1695         Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1696         
1697         /* calculate lightgrid */
1698         if( !noGridLighting )
1699         {
1700                 /* ydnar: set up light envelopes */
1701                 SetupEnvelopes( qtrue, fastgrid );
1702                 
1703                 Sys_Printf( "--- TraceGrid ---\n" );
1704                 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1705                 Sys_Printf( "%d x %d x %d = %d grid\n",
1706                         gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1707                 
1708                 /* ydnar: emit statistics on light culling */
1709                 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1710                 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1711         }
1712         
1713         /* slight optimization to remove a sqrt */
1714         subdivideThreshold *= subdivideThreshold;
1715         
1716         /* map the world luxels */
1717         Sys_Printf( "--- MapRawLightmap ---\n" );
1718         RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1719         Sys_Printf( "%9d luxels\n", numLuxels );
1720         Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1721         Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1722         
1723         /* dirty them up */
1724         if( dirty )
1725         {
1726                 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1727
1728
1729
1730
1731                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1732         }
1733         
1734         /* floodlight pass */
1735         FloodlightRawLightmaps();
1736
1737         /* ydnar: set up light envelopes */
1738         SetupEnvelopes( qfalse, fast );
1739         
1740         /* light up my world */
1741         lightsPlaneCulled = 0;
1742         lightsEnvelopeCulled = 0;
1743         lightsBoundsCulled = 0;
1744         lightsClusterCulled = 0;
1745         
1746         Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1747         RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1748         Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1749         
1750         StitchSurfaceLightmaps();
1751         
1752         Sys_Printf( "--- IlluminateVertexes ---\n" );
1753         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1754         Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1755         
1756         /* ydnar: emit statistics on light culling */
1757         Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1758         Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1759         Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1760         Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1761         
1762         /* radiosity */
1763         b = 1;
1764         bt = bounce;
1765         while( bounce > 0 )
1766         {
1767                 /* store off the bsp between bounces */
1768                 StoreSurfaceLightmaps();
1769                 UnparseEntities();
1770                 Sys_Printf( "Writing %s\n", source );
1771                 WriteBSPFile( source );
1772                 
1773                 /* note it */
1774                 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1775                 
1776                 /* flag bouncing */
1777                 bouncing = qtrue;
1778                 VectorClear( ambientColor );
1779                 floodlighty = qfalse;
1780                 
1781                 /* generate diffuse lights */
1782                 RadFreeLights();
1783                 RadCreateDiffuseLights();
1784                 
1785                 /* setup light envelopes */
1786                 SetupEnvelopes( qfalse, fastbounce );
1787                 if( numLights == 0 )
1788                 {
1789                         Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1790                         break;
1791                 }
1792                 
1793                 /* add to lightgrid */
1794                 if( bouncegrid )
1795                 {
1796                         gridEnvelopeCulled = 0;
1797                         gridBoundsCulled = 0;
1798                         
1799                         Sys_Printf( "--- BounceGrid ---\n" );
1800                         RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1801                         Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1802                         Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1803                 }
1804                 
1805                 /* light up my world */
1806                 lightsPlaneCulled = 0;
1807                 lightsEnvelopeCulled = 0;
1808                 lightsBoundsCulled = 0;
1809                 lightsClusterCulled = 0;
1810                 
1811                 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1812                 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1813                 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1814                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1815                 
1816                 StitchSurfaceLightmaps();
1817                 
1818                 Sys_Printf( "--- IlluminateVertexes ---\n" );
1819                 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1820                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1821                 
1822                 /* ydnar: emit statistics on light culling */
1823                 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1824                 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1825                 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1826                 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1827                 
1828                 /* interate */
1829                 bounce--;
1830                 b++;
1831         }
1832 }
1833
1834
1835
1836 /*
1837 LightMain()
1838 main routine for light processing
1839 */
1840
1841 int LightMain( int argc, char **argv )
1842 {
1843         int                     i;
1844         float           f;
1845         char            mapSource[ 1024 ];
1846         const char      *value;
1847         
1848         
1849         /* note it */
1850         Sys_Printf( "--- Light ---\n" );
1851         Sys_Printf( "--- ProcessGameSpecific ---\n" );
1852
1853         /* set standard game flags */
1854         wolfLight = game->wolfLight;
1855         if (wolfLight == qtrue)
1856                 Sys_Printf( " lightning model: wolf\n" );
1857         else
1858                 Sys_Printf( " lightning model: quake3\n" );
1859
1860         lmCustomSize = game->lightmapSize;
1861         Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
1862
1863         lightmapGamma = game->lightmapGamma;
1864         Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
1865
1866         lightmapCompensate = game->lightmapCompensate;
1867         Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
1868
1869         lightmapExposure = game->lightmapExposure;
1870         Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
1871
1872         gridScale = game->gridScale;
1873         Sys_Printf( " lightgrid scale: %f\n", gridScale );
1874
1875         gridAmbientScale = game->gridAmbientScale;
1876         Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
1877
1878         noStyles = game->noStyles;
1879         if (noStyles == qtrue)
1880                 Sys_Printf( " shader lightstyles hack: disabled\n" );
1881         else
1882                 Sys_Printf( " shader lightstyles hack: enabled\n" );
1883
1884         keepLights = game->keepLights;
1885         if (keepLights == qtrue)
1886                 Sys_Printf( " keep lights: enabled\n" );
1887         else
1888                 Sys_Printf( " keep lights: disabled\n" );
1889
1890         patchShadows = game->patchShadows;
1891         if (patchShadows == qtrue)
1892                 Sys_Printf( " patch shadows: enabled\n" );
1893         else
1894                 Sys_Printf( " patch shadows: disabled\n" );
1895
1896         deluxemap = game->deluxeMap;
1897         deluxemode = game->deluxeMode;
1898         if (deluxemap == qtrue)
1899         {
1900                 if (deluxemode)
1901                         Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
1902                 else
1903                         Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
1904         }
1905         else
1906                 Sys_Printf( " deluxemapping: disabled\n" );
1907
1908         Sys_Printf( "--- ProcessCommandLine ---\n" );
1909         
1910         /* process commandline arguments */
1911         for( i = 1; i < (argc - 1); i++ )
1912         {
1913                 /* lightsource scaling */
1914                 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
1915                 {
1916                         f = atof( argv[ i + 1 ] );
1917                         pointScale *= f;
1918                         Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1919                         i++;
1920                 }
1921                 
1922                 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
1923                 {
1924                         f = atof( argv[ i + 1 ] );
1925                         areaScale *= f;
1926                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1927                         i++;
1928                 }
1929                 
1930                 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
1931                 {
1932                         f = atof( argv[ i + 1 ] );
1933                         skyScale *= f;
1934                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1935                         i++;
1936                 }
1937                 
1938                 else if( !strcmp( argv[ i ], "-bouncescale" ) )
1939                 {
1940                         f = atof( argv[ i + 1 ] );
1941                         bounceScale *= f;
1942                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
1943                         i++;
1944                 }
1945                 
1946                 else if( !strcmp( argv[ i ], "-scale" ) )
1947                 {
1948                         f = atof( argv[ i + 1 ] );
1949                         pointScale *= f;
1950                         areaScale *= f;
1951                         skyScale *= f;
1952                         bounceScale *= f;
1953                         Sys_Printf( "All light scaled by %f\n", f );
1954                         i++;
1955                 }
1956
1957                 else if( !strcmp( argv[ i ], "-gridscale" ) )
1958                 {
1959                         f = atof( argv[ i + 1 ] );
1960                         Sys_Printf( "Grid lightning scaled by %f\n", f );
1961                         gridScale *= f;
1962                         i++;
1963                 }
1964
1965                 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
1966                 {
1967                         f = atof( argv[ i + 1 ] );
1968                         Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
1969                         gridAmbientScale *= f;
1970                         i++;
1971                 }
1972                 
1973                 else if( !strcmp( argv[ i ], "-gamma" ) )
1974                 {
1975                         f = atof( argv[ i + 1 ] );
1976                         lightmapGamma = f;
1977                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
1978                         i++;
1979                 }
1980                 
1981                 else if( !strcmp( argv[ i ], "-exposure" ) )
1982                 {
1983                         f = atof( argv[ i + 1 ] );
1984                         lightmapExposure = f;
1985                         Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
1986                         i++;
1987                 }
1988
1989                 else if( !strcmp( argv[ i ], "-compensate" ) )
1990                 {
1991                         f = atof( argv[ i + 1 ] );
1992                         if( f <= 0.0f )
1993                                 f = 1.0f;
1994                         lightmapCompensate = f;
1995                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
1996                         i++;
1997                 }
1998                 
1999                 /* ydnar switches */
2000                 else if( !strcmp( argv[ i ], "-bounce" ) )
2001                 {
2002                         bounce = atoi( argv[ i + 1 ] );
2003                         if( bounce < 0 )
2004                                 bounce = 0;
2005                         else if( bounce > 0 )
2006                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2007                         i++;
2008                 }
2009                 
2010                 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2011                 {
2012                         superSample = atoi( argv[ i + 1 ] );
2013                         if( superSample < 1 )
2014                                 superSample = 1;
2015                         else if( superSample > 1 )
2016                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2017                         i++;
2018                 }
2019                 
2020                 else if( !strcmp( argv[ i ], "-samples" ) )
2021                 {
2022                         lightSamples = atoi( argv[ i + 1 ] );
2023                         if( lightSamples < 1 )
2024                                 lightSamples = 1;
2025                         else if( lightSamples > 1 )
2026                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2027                         i++;
2028                 }
2029                 
2030                 else if( !strcmp( argv[ i ], "-filter" ) )
2031                 {
2032                         filter = qtrue;
2033                         Sys_Printf( "Lightmap filtering enabled\n" );
2034                 }
2035                 
2036                 else if( !strcmp( argv[ i ], "-dark" ) )
2037                 {
2038                         dark = qtrue;
2039                         Sys_Printf( "Dark lightmap seams enabled\n" );
2040                 }
2041                 
2042                 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2043                 {
2044                         shadeAngleDegrees = atof( argv[ i + 1 ] );
2045                         if( shadeAngleDegrees < 0.0f )
2046                                 shadeAngleDegrees = 0.0f;
2047                         else if( shadeAngleDegrees > 0.0f )
2048                         {
2049                                 shade = qtrue;
2050                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2051                         }
2052                         i++;
2053                 }
2054                 
2055                 else if( !strcmp( argv[ i ], "-thresh" ) )
2056                 {
2057                         subdivideThreshold = atof( argv[ i + 1 ] );
2058                         if( subdivideThreshold < 0 )
2059                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2060                         else
2061                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2062                         i++;
2063                 }
2064                 
2065                 else if( !strcmp( argv[ i ], "-approx" ) )
2066                 {
2067                         approximateTolerance = atoi( argv[ i + 1 ] );
2068                         if( approximateTolerance < 0 )
2069                                 approximateTolerance = 0;
2070                         else if( approximateTolerance > 0 )
2071                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2072                         i++;
2073                 }
2074                 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2075                 {
2076                         deluxemap = qtrue;
2077                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
2078                 }
2079                 else if( !strcmp( argv[ i ], "-deluxemode" ))
2080                 {
2081                         deluxemode = atoi( argv[ i + 1 ] );
2082                         if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2083                         {
2084                                 Sys_Printf( "Generating modelspace deluxemaps\n" );
2085                                 deluxemode = 0;
2086                         }
2087                         else 
2088                                 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2089                         i++;
2090                 }
2091                 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2092                 {
2093                         deluxemap = qfalse;
2094                         Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2095                 }
2096                 else if( !strcmp( argv[ i ], "-external" ) )
2097                 {
2098                         externalLightmaps = qtrue;
2099                         Sys_Printf( "Storing all lightmaps externally\n" );
2100                 }
2101
2102                 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2103                 {
2104                         lmCustomSize = atoi( argv[ i + 1 ] );
2105                         
2106                         /* must be a power of 2 and greater than 2 */
2107                         if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2108                         {
2109                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2110                                 lmCustomSize = game->lightmapSize;
2111                         }
2112                         i++;
2113                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2114                         
2115                         /* enable external lightmaps */
2116                         if( lmCustomSize != game->lightmapSize )
2117                         {
2118                                 externalLightmaps = qtrue;
2119                                 Sys_Printf( "Storing all lightmaps externally\n" );
2120                         }
2121                 }
2122                 
2123                 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2124                 {
2125                         lmCustomDir = argv[i + 1];
2126                         i++;
2127                         Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2128                         externalLightmaps = qtrue;
2129                         Sys_Printf( "Storing all lightmaps externally\n" );
2130                 }
2131                 
2132                 /* ydnar: add this to suppress warnings */
2133                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
2134                 {
2135                         Sys_Printf( "Custom info parms enabled\n" );
2136                         useCustomInfoParms = qtrue;
2137                 }
2138                 
2139                 else if( !strcmp( argv[ i ], "-wolf" ) )
2140                 {
2141                         /* -game should already be set */
2142                         wolfLight = qtrue;
2143                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2144                 }
2145                 
2146                 else if( !strcmp( argv[ i ], "-q3" ) )
2147                 {
2148                         /* -game should already be set */
2149                         wolfLight = qfalse;
2150                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2151                 }
2152                 
2153                 else if( !strcmp( argv[ i ], "-sunonly" ) )
2154                 {
2155                         sunOnly = qtrue;
2156                         Sys_Printf( "Only computing sunlight\n" );
2157                 }
2158                 
2159                 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2160                 {
2161                         bounceOnly = qtrue;
2162                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2163                 }
2164                 
2165                 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2166                 {
2167                         noCollapse = qtrue;
2168                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2169                 }
2170                 
2171                 else if( !strcmp( argv[ i ], "-shade" ) )
2172                 {
2173                         shade = qtrue;
2174                         Sys_Printf( "Phong shading enabled\n" );
2175                 }
2176                 
2177                 else if( !strcmp( argv[ i ], "-bouncegrid") )
2178                 {
2179                         bouncegrid = qtrue;
2180                         if( bounce > 0 )
2181                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2182                 }
2183                 
2184                 else if( !strcmp( argv[ i ], "-smooth" ) )
2185                 {
2186                         lightSamples = EXTRA_SCALE;
2187                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2188                 }
2189                 
2190                 else if( !strcmp( argv[ i ], "-fast" ) )
2191                 {
2192                         fast = qtrue;
2193                         fastgrid = qtrue;
2194                         fastbounce = qtrue;
2195                         Sys_Printf( "Fast mode enabled\n" );
2196                 }
2197                 
2198                 else if( !strcmp( argv[ i ], "-faster" ) )
2199                 {
2200                         faster = qtrue;
2201                         fast = qtrue;
2202                         fastgrid = qtrue;
2203                         fastbounce = qtrue;
2204                         Sys_Printf( "Faster mode enabled\n" );
2205                 }
2206                 
2207                 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2208                 {
2209                         fastgrid = qtrue;
2210                         Sys_Printf( "Fast grid lighting enabled\n" );
2211                 }
2212                 
2213                 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2214                 {
2215                         fastbounce = qtrue;
2216                         Sys_Printf( "Fast bounce mode enabled\n" );
2217                 }
2218                 
2219                 else if( !strcmp( argv[ i ], "-cheap" ) )
2220                 {
2221                         cheap = qtrue;
2222                         cheapgrid = qtrue;
2223                         Sys_Printf( "Cheap mode enabled\n" );
2224                 }
2225
2226                 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2227                 {
2228                         cheapgrid = qtrue;
2229                         Sys_Printf( "Cheap grid mode enabled\n" );
2230                 }
2231                 
2232                 else if( !strcmp( argv[ i ], "-normalmap" ) )
2233                 {
2234                         normalmap = qtrue;
2235                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2236                 }
2237                 
2238                 else if( !strcmp( argv[ i ], "-trisoup" ) )
2239                 {
2240                         trisoup = qtrue;
2241                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2242                 }
2243                 
2244                 else if( !strcmp( argv[ i ], "-debug" ) )
2245                 {
2246                         debug = qtrue;
2247                         Sys_Printf( "Lightmap debugging enabled\n" );
2248                 }
2249                 
2250                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2251                 {
2252                         debugSurfaces = qtrue;
2253                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2254                 }
2255                 
2256                 else if( !strcmp( argv[ i ], "-debugunused" ) )
2257                 {
2258                         debugUnused = qtrue;
2259                         Sys_Printf( "Unused luxel debugging enabled\n" );
2260                 }
2261
2262                 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2263                 {
2264                         debugAxis = qtrue;
2265                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2266                 }
2267                 
2268                 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2269                 {
2270                         debugCluster = qtrue;
2271                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2272                 }
2273                 
2274                 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2275                 {
2276                         debugOrigin = qtrue;
2277                         Sys_Printf( "Luxel origin debugging enabled\n" );
2278                 }
2279                 
2280                 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2281                 {
2282                         deluxemap = qtrue;
2283                         debugDeluxemap = qtrue;
2284                         Sys_Printf( "Deluxemap debugging enabled\n" );
2285                 }
2286                 
2287                 else if( !strcmp( argv[ i ], "-export" ) )
2288                 {
2289                         exportLightmaps = qtrue;
2290                         Sys_Printf( "Exporting lightmaps\n" );
2291                 }
2292                 
2293                 else if( !strcmp(argv[ i ], "-notrace" )) 
2294                 {
2295                         noTrace = qtrue;
2296                         Sys_Printf( "Shadow occlusion disabled\n" );
2297                 }
2298                 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2299                 {
2300                         patchShadows = qtrue;
2301                         Sys_Printf( "Patch shadow casting enabled\n" );
2302                 }
2303                 else if( !strcmp( argv[ i ], "-extra" ) )
2304                 {
2305                         superSample = EXTRA_SCALE;              /* ydnar */
2306                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2307                 }
2308                 else if( !strcmp( argv[ i ], "-extrawide" ) )
2309                 {
2310                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2311                         filter = qtrue;                                 /* ydnar */
2312                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2313                 }
2314                 else if( !strcmp( argv[ i ], "-samplesize" ) )
2315                 {
2316                         sampleSize = atoi( argv[ i + 1 ] );
2317                         if( sampleSize < 1 )
2318                                 sampleSize = 1;
2319                         i++;
2320                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2321                 }
2322                 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2323                 {
2324                         minSampleSize = atoi( argv[ i + 1 ] );
2325                         if( minSampleSize < 1 )
2326                                 minSampleSize = 1;
2327                         i++;
2328                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2329                 }
2330                 else if( !strcmp( argv[ i ],  "-samplescale" ) )
2331                 {
2332                         sampleScale = atoi( argv[ i + 1 ] );
2333                         i++;
2334                         Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2335                 }
2336                 else if( !strcmp( argv[ i ], "-novertex" ) )
2337                 {
2338                         noVertexLighting = qtrue;
2339                         Sys_Printf( "Disabling vertex lighting\n" );
2340                 }
2341                 else if( !strcmp( argv[ i ], "-nogrid" ) )
2342                 {
2343                         noGridLighting = qtrue;
2344                         Sys_Printf( "Disabling grid lighting\n" );
2345                 }
2346                 else if( !strcmp( argv[ i ], "-border" ) )
2347                 {
2348                         lightmapBorder = qtrue;
2349                         Sys_Printf( "Adding debug border to lightmaps\n" );
2350                 }
2351                 else if( !strcmp( argv[ i ], "-nosurf" ) )
2352                 {
2353                         noSurfaces = qtrue;
2354                         Sys_Printf( "Not tracing against surfaces\n" );
2355                 }
2356                 else if( !strcmp( argv[ i ], "-dump" ) )
2357                 {
2358                         dump = qtrue;
2359                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2360                 }
2361                 else if( !strcmp( argv[ i ], "-lomem" ) )
2362                 {
2363                         loMem = qtrue;
2364                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2365                 }
2366                 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2367                 {
2368                         noStyles = qtrue;
2369                         Sys_Printf( "Disabling lightstyles\n" );
2370                 }
2371                 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2372                 {
2373                         noStyles = qfalse;
2374                         Sys_Printf( "Enabling lightstyles\n" );
2375                 }
2376                 else if( !strcmp( argv[ i ], "-keeplights" ))
2377                 {
2378                         keepLights = qtrue;
2379                         Sys_Printf( "Leaving light entities on map after compile\n" );
2380                 }
2381                 else if( !strcmp( argv[ i ], "-cpma" ) )
2382                 {
2383                         cpmaHack = qtrue;
2384                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2385                 }
2386                 else if( !strcmp( argv[ i ], "-floodlight" ) )
2387                 {
2388                         floodlighty = qtrue;
2389                         Sys_Printf( "FloodLighting enabled\n" );
2390                 }
2391                 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2392                 {
2393                         debugnormals = qtrue;
2394                         Sys_Printf( "DebugNormals enabled\n" );
2395                 }
2396                 else if( !strcmp( argv[ i ], "-lowquality" ) )
2397                 {
2398                         floodlight_lowquality = qtrue;
2399                         Sys_Printf( "Low Quality FloodLighting enabled\n" );
2400                 }
2401                 
2402                 /* r7: dirtmapping */
2403                 else if( !strcmp( argv[ i ], "-dirty" ) )
2404                 {
2405                         dirty = qtrue;
2406                         Sys_Printf( "Dirtmapping enabled\n" );
2407                 }
2408                 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2409                 {
2410                         dirtDebug = qtrue;
2411                         Sys_Printf( "Dirtmap debugging enabled\n" );
2412                 }
2413                 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2414                 {
2415                         dirtMode = atoi( argv[ i + 1 ] );
2416                         if( dirtMode != 0 && dirtMode != 1 )
2417                                 dirtMode = 0;
2418                         if( dirtMode == 1 )
2419                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2420                         else
2421                                 Sys_Printf( "Enabling ordered dir mapping\n" );
2422                         i++;
2423                 }
2424                 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2425                 {
2426                         dirtDepth = atof( argv[ i + 1 ] );
2427                         if( dirtDepth <= 0.0f )
2428                                 dirtDepth = 128.0f;
2429                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2430                         i++;
2431                 }
2432                 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2433                 {
2434                         dirtScale = atof( argv[ i + 1 ] );
2435                         if( dirtScale <= 0.0f )
2436                                 dirtScale = 1.0f;
2437                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2438                         i++;
2439                 }
2440                 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2441                 {
2442                         dirtGain = atof( argv[ i + 1 ] );
2443                         if( dirtGain <= 0.0f )
2444                                 dirtGain = 1.0f;
2445                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2446                         i++;
2447                 }
2448                 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2449                 {
2450                         lightmapTriangleCheck = qtrue;
2451                 }
2452                 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2453                 {
2454                         lightmapExtraVisClusterNudge = qtrue;
2455                 }
2456                 /* unhandled args */
2457                 else
2458                 {
2459                         Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2460                 }
2461
2462         }
2463         
2464         /* clean up map name */
2465         strcpy( source, ExpandArg( argv[ i ] ) );
2466         StripExtension( source );
2467         DefaultExtension( source, ".bsp" );
2468         strcpy( mapSource, ExpandArg( argv[ i ] ) );
2469         StripExtension( mapSource );
2470         DefaultExtension( mapSource, ".map" );
2471         
2472         /* ydnar: set default sample size */
2473         SetDefaultSampleSize( sampleSize );
2474         
2475         /* ydnar: handle shaders */
2476         BeginMapShaderFile( source );
2477         LoadShaderInfo();
2478         
2479         /* note loading */
2480         Sys_Printf( "Loading %s\n", source );
2481         
2482         /* ydnar: load surface file */
2483         LoadSurfaceExtraFile( source );
2484         
2485         /* load bsp file */
2486         LoadBSPFile( source );
2487         
2488         /* parse bsp entities */
2489         ParseEntities();
2490
2491         /* inject command line parameters */
2492         InjectCommandLine(argv, 0, argc - 1);
2493         
2494         /* load map file */
2495         value = ValueForKey( &entities[ 0 ], "_keepLights" );
2496         if( value[ 0 ] != '1' )
2497                 LoadMapFile( mapSource, qtrue );
2498         
2499         /* set the entity/model origins and init yDrawVerts */
2500         SetEntityOrigins();
2501         
2502         /* ydnar: set up optimization */
2503         SetupBrushes();
2504         SetupDirt();
2505         SetupFloodLight();
2506         SetupSurfaceLightmaps();
2507         
2508         /* initialize the surface facet tracing */
2509         SetupTraceNodes();
2510         
2511         /* light the world */
2512         LightWorld();
2513         
2514         /* ydnar: store off lightmaps */
2515         StoreSurfaceLightmaps();
2516         
2517         /* write out the bsp */
2518         UnparseEntities();
2519         Sys_Printf( "Writing %s\n", source );
2520         WriteBSPFile( source );
2521         
2522         /* ydnar: export lightmaps */
2523         if( exportLightmaps && !externalLightmaps )
2524                 ExportLightmaps();
2525         
2526         /* return to sender */
2527         return 0;
2528 }
2529