]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light.c
ABToSVK commit
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light.c
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 ----------------------------------------------------------------------------------
22
23 This code has been altered significantly from its original form, to support
24 several games based on the Quake III Arena engine, in the form of "Q3Map2."
25
26 ------------------------------------------------------------------------------- */
27
28
29
30 /* marker */
31 #define LIGHT_C
32
33
34
35 /* dependencies */
36 #include "q3map2.h"
37
38
39
40 /*
41 CreateSunLight() - ydnar
42 this creates a sun light
43 */
44
45 static void CreateSunLight( sun_t *sun )
46 {
47         int                     i;
48         float           photons, d, angle, elevation, da, de;
49         vec3_t          direction;
50         light_t         *light;
51         
52         
53         /* dummy check */
54         if( sun == NULL )
55                 return;
56         
57         /* fixup */
58         if( sun->numSamples < 1 )
59                 sun->numSamples = 1;
60         
61         /* set photons */
62         photons = sun->photons / sun->numSamples;
63         
64         /* create the right number of suns */
65         for( i = 0; i < sun->numSamples; i++ )
66         {
67                 /* calculate sun direction */
68                 if( i == 0 )
69                         VectorCopy( sun->direction, direction );
70                 else
71                 {
72                         /*
73                                 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
74                                 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
75                                 sun->direction[ 2 ] = sin( elevation );
76                                 
77                                 xz_dist   = sqrt( x*x + z*z )
78                                 latitude  = atan2( xz_dist, y ) * RADIANS
79                                 longitude = atan2( x,       z ) * RADIANS
80                         */
81                         
82                         d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
83                         angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
84                         elevation = atan2( sun->direction[ 2 ], d );
85                         
86                         /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
87                         do
88                         {
89                                 da = (Random() * 2.0f - 1.0f) * sun->deviance;
90                                 de = (Random() * 2.0f - 1.0f) * sun->deviance;
91                         }
92                         while( (da * da + de * de) > (sun->deviance * sun->deviance) );
93                         angle += da;
94                         elevation += de;
95                         
96                         /* debug code */
97                         //%     Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
98                         
99                         /* create new vector */
100                         direction[ 0 ] = cos( angle ) * cos( elevation );
101                         direction[ 1 ] = sin( angle ) * cos( elevation );
102                         direction[ 2 ] = sin( elevation );
103                 }
104                 
105                 /* create a light */
106                 numSunLights++;
107                 light = safe_malloc( sizeof( *light ) );
108                 memset( light, 0, sizeof( *light ) );
109                 light->next = lights;
110                 lights = light;
111                 
112                 /* initialize the light */
113                 light->flags = LIGHT_SUN_DEFAULT;
114                 light->type = EMIT_SUN;
115                 light->fade = 1.0f;
116                 light->falloffTolerance = falloffTolerance;
117                 light->filterRadius = sun->filterRadius / sun->numSamples;
118                 
119                 /* set the light's position out to infinity */
120                 VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin );    /* MAX_WORLD_COORD * 2.0f */
121                 
122                 /* set the facing to be the inverse of the sun direction */
123                 VectorScale( direction, -1.0, light->normal );
124                 light->dist = DotProduct( light->origin, light->normal );
125                 
126                 /* set color and photons */
127                 VectorCopy( sun->color, light->color );
128                 light->photons = photons * skyScale;
129         }
130
131         /* another sun? */
132         if( sun->next != NULL )
133                 CreateSunLight( sun->next );
134 }
135
136
137
138 /*
139 CreateSkyLights() - ydnar
140 simulates sky light with multiple suns
141 */
142
143 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius )
144 {
145         int                     c, i, j, k, numSuns;
146         float           step, start;
147         vec3_t          in;
148         sun_t           sun;
149         
150         
151         /* dummy check */
152         if( value <= 0.0f || iterations < 2 )
153                 return;
154         
155         /* calculate some stuff */
156         step = 2.0f / (iterations - 1);
157         start = -1.0f;
158         
159         /* basic sun setup */
160         VectorCopy( color, sun.color );
161         sun.deviance = 0.0f;
162         sun.filterRadius = filterRadius;
163         sun.numSamples = 1;
164         sun.next = NULL;
165         
166         /* iterate */
167         numSuns = 0;
168         for( c = 0; c < 2; c++ )
169         {
170                 for( k = 0, in[ 2 ] = start; k < iterations; k++, in[ 2 ] += step )
171                 {
172                         /* don't create sky light below the horizon */
173                         if( in[ 2 ] <= 0.0f )
174                                 continue;
175                         
176                         for( j = 0, in[ 1 ] = start; j < iterations; j++, in[ 1 ] += step )
177                         {
178                                 for( i = 0, in[ 0 ] = start; i < iterations; i++, in[ 0 ] += step )
179                                 {
180                                         if( VectorNormalize( in, sun.direction ) )
181                                         {
182                                                 if( c > 0 && numSuns > 0 )
183                                                 {
184                                                         sun.photons = value / numSuns;
185                                                         CreateSunLight( &sun );
186                                                 }
187                                                 else
188                                                         numSuns++;
189                                         }
190                                 }
191                         }
192                 }
193         }
194 }
195
196
197
198 /*
199 CreateEntityLights()
200 creates lights from light entities
201 */
202
203 void CreateEntityLights( void )
204 {
205         int                             i, j;
206         light_t                 *light, *light2;
207         entity_t                *e, *e2;
208         const char              *name;
209         const char              *target;
210         vec3_t                  dest;
211         const char              *_color;
212         float                   intensity, scale, deviance, filterRadius;
213         int                             spawnflags, flags, numSamples;
214         qboolean                junior;
215
216         
217         /* go throught entity list and find lights */
218         for( i = 0; i < numEntities; i++ )
219         {
220                 /* get entity */
221                 e = &entities[ i ];
222                 name = ValueForKey( e, "classname" );
223                 
224                 /* ydnar: check for lightJunior */
225                 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
226                         junior = qtrue;
227                 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
228                         junior = qfalse;
229                 else
230                         continue;
231                 
232                 /* lights with target names (and therefore styles) are only parsed from BSP */
233                 target = ValueForKey( e, "targetname" );
234                 if( target[ 0 ] != '\0' && i >= numBSPEntities )
235                         continue;
236                 
237                 /* create a light */
238                 numPointLights++;
239                 light = safe_malloc( sizeof( *light ) );
240                 memset( light, 0, sizeof( *light ) );
241                 light->next = lights;
242                 lights = light;
243                 
244                 /* handle spawnflags */
245                 spawnflags = IntForKey( e, "spawnflags" );
246                 
247                 /* ydnar: quake 3+ light behavior */
248                 if( game->wolfLight == qfalse )
249                 {
250                         /* set default flags */
251                         flags = LIGHT_Q3A_DEFAULT;
252                         
253                         /* linear attenuation? */
254                         if( spawnflags & 1 )
255                         {
256                                 flags |= LIGHT_ATTEN_LINEAR;
257                                 flags &= ~LIGHT_ATTEN_ANGLE;
258                         }
259                         
260                         /* no angle attenuate? */
261                         if( spawnflags & 2 )
262                                 flags &= ~LIGHT_ATTEN_ANGLE;
263                 }
264                 
265                 /* ydnar: wolf light behavior */
266                 else
267                 {
268                         /* set default flags */
269                         flags = LIGHT_WOLF_DEFAULT;
270                         
271                         /* inverse distance squared attenuation? */
272                         if( spawnflags & 1 )
273                         {
274                                 flags &= ~LIGHT_ATTEN_LINEAR;
275                                 flags |= LIGHT_ATTEN_ANGLE;
276                         }
277                         
278                         /* angle attenuate? */
279                         if( spawnflags & 2 )
280                                 flags |= LIGHT_ATTEN_ANGLE;
281                 }
282                 
283                 /* other flags (borrowed from wolf) */
284                 
285                 /* wolf dark light? */
286                 if( (spawnflags & 4) || (spawnflags & 8) )
287                         flags |= LIGHT_DARK;
288                 
289                 /* nogrid? */
290                 if( spawnflags & 16 )
291                         flags &= ~LIGHT_GRID;
292                 
293                 /* junior? */
294                 if( junior )
295                 {
296                         flags |= LIGHT_GRID;
297                         flags &= ~LIGHT_SURFACES;
298                 }
299                 
300                 /* store the flags */
301                 light->flags = flags;
302                 
303                 /* ydnar: set fade key (from wolf) */
304                 light->fade = 1.0f;
305                 if( light->flags & LIGHT_ATTEN_LINEAR )
306                 {
307                         light->fade = FloatForKey( e, "fade" );
308                         if( light->fade == 0.0f )
309                                 light->fade = 1.0f;
310                 }
311                 
312                 /* ydnar: set angle scaling (from vlight) */
313                 light->angleScale = FloatForKey( e, "_anglescale" );
314                 if( light->angleScale != 0.0f )
315                         light->flags |= LIGHT_ATTEN_ANGLE;
316                 
317                 /* set origin */
318                 GetVectorForKey( e, "origin", light->origin);
319                 light->style = IntForKey( e, "_style" );
320                 if( light->style == 0 )
321                         light->style = IntForKey( e, "style" );
322                 if( light->style < LS_NORMAL || light->style >= LS_NONE )
323                         Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
324                 
325                 if( light->style != LS_NORMAL ) {
326                         Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
327                 }
328
329                 /* set light intensity */
330                 intensity = FloatForKey( e, "_light" );
331                 if( intensity == 0.0f )
332                         intensity = FloatForKey( e, "light" );
333                 if( intensity == 0.0f)
334                         intensity = 300.0f;
335                 
336                 /* ydnar: set light scale (sof2) */
337                 scale = FloatForKey( e, "scale" );
338                 if( scale == 0.0f )
339                         scale = 1.0f;
340                 intensity *= scale;
341                 
342                 /* ydnar: get deviance and samples */
343                 deviance = FloatForKey( e, "_deviance" );
344                 if( deviance == 0.0f )
345                         deviance = FloatForKey( e, "_deviation" );
346                 if( deviance == 0.0f )
347                         deviance = FloatForKey( e, "_jitter" );
348                 numSamples = IntForKey( e, "_samples" );
349                 if( deviance < 0.0f || numSamples < 1 )
350                 {
351                         deviance = 0.0f;
352                         numSamples = 1;
353                 }
354                 intensity /= numSamples;
355                 
356                 /* ydnar: get filter radius */
357                 filterRadius = FloatForKey( e, "_filterradius" );
358                 if( filterRadius == 0.0f )
359                         filterRadius = FloatForKey( e, "_filteradius" );
360                 if( filterRadius == 0.0f )
361                         filterRadius = FloatForKey( e, "_filter" );
362                 if( filterRadius < 0.0f )
363                         filterRadius = 0.0f;
364                 light->filterRadius = filterRadius;
365                 
366                 /* set light color */
367                 _color = ValueForKey( e, "_color" );
368                 if( _color && _color[ 0 ] )
369                 {
370                         sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
371                         ColorNormalize( light->color, light->color );
372                 }
373                 else
374                         light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
375                 
376                 intensity = intensity * pointScale;
377                 light->photons = intensity;
378                 
379                 light->type = EMIT_POINT;
380                 
381                 /* set falloff threshold */
382                 light->falloffTolerance = falloffTolerance / numSamples;
383                 
384                 /* lights with a target will be spotlights */
385                 target = ValueForKey( e, "target" );
386                 if( target[ 0 ] )
387                 {
388                         float           radius;
389                         float           dist;
390                         sun_t           sun;
391                         const char      *_sun;
392                         
393                         
394                         /* get target */
395                         e2 = FindTargetEntity( target );
396                         if( e2 == NULL )
397                         {
398                                 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
399                                         (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
400                         }
401                         else
402                         {
403                                 /* not a point light */
404                                 numPointLights--;
405                                 numSpotLights++;
406                                 
407                                 /* make a spotlight */
408                                 GetVectorForKey( e2, "origin", dest );
409                                 VectorSubtract( dest, light->origin, light->normal );
410                                 dist = VectorNormalize( light->normal, light->normal );
411                                 radius = FloatForKey( e, "radius" );
412                                 if( !radius )
413                                         radius = 64;
414                                 if( !dist )
415                                         dist = 64;
416                                 light->radiusByDist = (radius + 16) / dist;
417                                 light->type = EMIT_SPOT;
418                                 
419                                 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
420                                 light->flags &= ~LIGHT_ATTEN_LINEAR;
421                                 light->flags |= LIGHT_ATTEN_ANGLE;
422                                 light->fade = 1.0f;
423                                 
424                                 /* ydnar: is this a sun? */
425                                 _sun = ValueForKey( e, "_sun" );
426                                 if( _sun[ 0 ] == '1' )
427                                 {
428                                         /* not a spot light */
429                                         numSpotLights--;
430                                         
431                                         /* unlink this light */
432                                         lights = light->next;
433                                         
434                                         /* make a sun */
435                                         VectorScale( light->normal, -1.0f, sun.direction );
436                                         VectorCopy( light->color, sun.color );
437                                         sun.photons = (intensity / pointScale);
438                                         sun.deviance = deviance / 180.0f * Q_PI;
439                                         sun.numSamples = numSamples;
440                                         sun.next = NULL;
441                                         
442                                         /* make a sun light */
443                                         CreateSunLight( &sun );
444                                         
445                                         /* free original light */
446                                         free( light );
447                                         light = NULL;
448                                         
449                                         /* skip the rest of this love story */
450                                         continue;
451                                 }
452                         }
453                 }
454                 
455                 /* jitter the light */
456                 for( j = 1; j < numSamples; j++ )
457                 {
458                         /* create a light */
459                         light2 = safe_malloc( sizeof( *light ) );
460                         memcpy( light2, light, sizeof( *light ) );
461                         light2->next = lights;
462                         lights = light2;
463                         
464                         /* add to counts */
465                         if( light->type == EMIT_SPOT )
466                                 numSpotLights++;
467                         else
468                                 numPointLights++;
469                         
470                         /* jitter it */
471                         light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
472                         light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
473                         light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
474                 }
475         }
476 }
477
478
479
480 /*
481 CreateSurfaceLights() - ydnar
482 this hijacks the radiosity code to generate surface lights for first pass
483 */
484
485 #define APPROX_BOUNCE   1.0f
486
487 void CreateSurfaceLights( void )
488 {
489         int                                     i;
490         bspDrawSurface_t        *ds;
491         surfaceInfo_t           *info;
492         shaderInfo_t            *si;
493         light_t                         *light;
494         float                           subdivide;
495         vec3_t                          origin;
496         clipWork_t                      cw;
497         const char                      *nss;
498         
499         
500         /* get sun shader supressor */
501         nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
502         
503         /* walk the list of surfaces */
504         for( i = 0; i < numBSPDrawSurfaces; i++ )
505         {
506                 /* get surface and other bits */
507                 ds = &bspDrawSurfaces[ i ];
508                 info = &surfaceInfos[ i ];
509                 si = info->si;
510                 
511                 /* sunlight? */
512                 if( si->sun != NULL && nss[ 0 ] != '1' )
513                 {
514                         Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
515                         CreateSunLight( si->sun );
516                         si->sun = NULL; /* FIXME: leak! */
517                 }
518                 
519                 /* sky light? */
520                 if( si->skyLightValue > 0.0f )
521                 {
522                         Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
523                         CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius );
524                         si->skyLightValue = 0.0f;       /* FIXME: hack! */
525                 }
526                 
527                 /* try to early out */
528                 if( si->value <= 0 )
529                         continue;
530                 
531                 /* autosprite shaders become point lights */
532                 if( si->autosprite )
533                 {
534                         /* create an average xyz */
535                         VectorAdd( info->mins, info->maxs, origin );
536                         VectorScale( origin, 0.5f, origin );
537                         
538                         /* create a light */
539                         light = safe_malloc( sizeof( *light ) );
540                         memset( light, 0, sizeof( *light ) );
541                         light->next = lights;
542                         lights = light;
543                         
544                         /* set it up */
545                         light->flags = LIGHT_Q3A_DEFAULT;
546                         light->type = EMIT_POINT;
547                         light->photons = si->value * pointScale;
548                         light->fade = 1.0f;
549                         light->si = si;
550                         VectorCopy( origin, light->origin );
551                         VectorCopy( si->color, light->color );
552                         light->falloffTolerance = falloffTolerance;
553                         light->style = light->style;
554                         
555                         /* add to point light count and continue */
556                         numPointLights++;
557                         continue;
558                 }
559                 
560                 /* get subdivision amount */
561                 if( si->lightSubdivide > 0 )
562                         subdivide = si->lightSubdivide;
563                 else
564                         subdivide = defaultLightSubdivide;
565                 
566                 /* switch on type */
567                 switch( ds->surfaceType )
568                 {
569                         case MST_PLANAR:
570                         case MST_TRIANGLE_SOUP:
571                                 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
572                                 break;
573                         
574                         case MST_PATCH:
575                                 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
576                                 break;
577                         
578                         default:
579                                 break;
580                 }
581         }
582 }
583
584
585
586 /*
587 SetEntityOrigins()
588 find the offset values for inline models
589 */
590
591 void SetEntityOrigins( void )
592 {
593         int                                     i, j, k, f;
594         entity_t                        *e;
595         vec3_t                          origin;
596         const char                      *key;
597         int                                     modelnum;
598         bspModel_t                      *dm;
599         bspDrawSurface_t        *ds;
600         
601         
602         /* ydnar: copy drawverts into private storage for nefarious purposes */
603         yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
604         memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
605         
606         /* set the entity origins */
607         for( i = 0; i < numEntities; i++ )
608         {
609                 /* get entity and model */
610                 e = &entities[ i ];
611                 key = ValueForKey( e, "model" );
612                 if( key[ 0 ] != '*' )
613                         continue;
614                 modelnum = atoi( key + 1 );
615                 dm = &bspModels[ modelnum ];
616                 
617                 /* get entity origin */
618                 key = ValueForKey( e, "origin" );
619                 if( key[ 0 ] == '\0' )
620                         continue;
621                 GetVectorForKey( e, "origin", origin );
622                 
623                 /* set origin for all surfaces for this model */
624                 for( j = 0; j < dm->numBSPSurfaces; j++ )
625                 {
626                         /* get drawsurf */
627                         ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
628                         
629                         /* set its verts */
630                         for( k = 0; k < ds->numVerts; k++ )
631                         {
632                                 f = ds->firstVert + k;
633                                 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
634                         }
635                 }
636         }
637 }
638
639
640
641 /*
642 PointToPolygonFormFactor()
643 calculates the area over a point/normal hemisphere a winding covers
644 ydnar: fixme: there has to be a faster way to calculate this
645 without the expensive per-vert sqrts and transcendental functions
646 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
647 between this and the approximation
648 */
649
650 #define ONE_OVER_2PI    0.159154942f    //% (1.0f / (2.0f * 3.141592657f))
651
652 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
653 {
654         vec3_t          triVector, triNormal;
655         int                     i, j;
656         vec3_t          dirs[ MAX_POINTS_ON_WINDING ];
657         float           total;
658         float           dot, angle, facing;
659         
660         
661         /* this is expensive */
662         for( i = 0; i < w->numpoints; i++ )
663         {
664                 VectorSubtract( w->p[ i ], point, dirs[ i ] );
665                 VectorNormalize( dirs[ i ], dirs[ i ] );
666         }
667         
668         /* duplicate first vertex to avoid mod operation */
669         VectorCopy( dirs[ 0 ], dirs[ i ] );
670         
671         /* calculcate relative area */
672         total = 0.0f;
673         for( i = 0; i < w->numpoints; i++ )
674         {
675                 /* get a triangle */
676                 j = i + 1;
677                 dot = DotProduct( dirs[ i ], dirs[ j ] );
678                 
679                 /* roundoff can cause slight creep, which gives an IND from acos */
680                 if( dot > 1.0f )
681                         dot = 1.0f;
682                 else if( dot < -1.0f )
683                         dot = -1.0f;
684                 
685                 /* get the angle */
686                 angle = acos( dot );
687                 
688                 CrossProduct( dirs[ i ], dirs[ j ], triVector );
689                 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
690                         continue;
691                 
692                 facing = DotProduct( normal, triNormal );
693                 total += facing * angle;
694                 
695                 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
696                 if( total > 6.3f || total < -6.3f )
697                         return 0.0f;
698         }
699         
700         /* now in the range of 0 to 1 over the entire incoming hemisphere */
701         //%     total /= (2.0f * 3.141592657f);
702         total *= ONE_OVER_2PI;
703         return total;
704 }
705
706
707
708 /*
709 LightContributionTosample()
710 determines the amount of light reaching a sample (luxel or vertex) from a given light
711 */
712
713 int LightContributionToSample( trace_t *trace )
714 {
715         light_t                 *light;
716         float                   angle;
717         float                   add;
718         float                   dist;
719         
720         
721         /* get light */
722         light = trace->light;
723         
724         /* clear color */
725         VectorClear( trace->color );
726         
727         /* ydnar: early out */
728         if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
729                 return 0;
730         
731         /* do some culling checks */
732         if( light->type != EMIT_SUN )
733         {
734                 /* MrE: if the light is behind the surface */
735                 if( trace->twoSided == qfalse )
736                         if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
737                                 return 0;
738                 
739                 /* ydnar: test pvs */
740                 if( !ClusterVisible( trace->cluster, light->cluster ) )
741                         return 0;
742         }
743         
744         /* ptpff approximation */
745         if( light->type == EMIT_AREA && faster )
746         {
747                 /* get direction and distance */
748                 VectorCopy( light->origin, trace->end );
749                 dist = SetupTrace( trace );
750                 if( dist >= light->envelope )
751                         return 0;
752                 
753                 /* clamp the distance to prevent super hot spots */
754                 if( dist < 16.0f )
755                         dist = 16.0f;
756                 
757                 /* angle attenuation */
758                 angle = DotProduct( trace->normal, trace->direction );
759                 
760                 /* twosided lighting */
761                 if( trace->twoSided )
762                         angle = fabs( angle );
763                 
764                 /* attenuate */
765                 angle *= -DotProduct( light->normal, trace->direction );
766                 if( angle <= 0.0f )
767                         return 0;
768                 add = light->photons / (dist * dist) * angle;
769         }
770         
771         /* exact point to polygon form factor */
772         else if( light->type == EMIT_AREA )
773         {
774                 float           factor;
775                 float           d;
776                 vec3_t          pushedOrigin;
777                 
778                 
779                 /* project sample point into light plane */
780                 d = DotProduct( trace->origin, light->normal ) - light->dist;
781                 //%     if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
782                 //%             return 0;
783                 if( d < 3.0f )
784                 {
785                         /* sample point behind plane? */
786                         if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
787                                 return 0;
788                         
789                         /* sample plane coincident? */
790                         if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
791                                 return 0;
792                 }
793                 
794                 /* nudge the point so that it is clearly forward of the light */
795                 /* so that surfaces meeting a light emiter don't get black edges */
796                 if( d > -8.0f && d < 8.0f )
797                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
798                 else
799                         VectorCopy( trace->origin, pushedOrigin );
800                 
801                 /* get direction and distance */
802                 VectorCopy( light->origin, trace->end );
803                 dist = SetupTrace( trace );
804                 if( dist >= light->envelope )
805                         return 0;
806                 
807                 /* calculate the contribution */
808                 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
809                 if( factor == 0.0f )
810                         return 0;
811                 else if( factor < 0.0f )
812                 {
813                         /* twosided lighting */
814                         if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
815                         {
816                                 factor = -factor;
817
818                                 /* push light origin to other side of the plane */
819                                 VectorMA( light->origin, -2.0f, light->normal, trace->end );
820                                 dist = SetupTrace( trace );
821                                 if( dist >= light->envelope )
822                                         return 0;
823                         }
824                         else
825                                 return 0;
826                 }
827                 
828                 /* ydnar: moved to here */
829                 add = factor * light->add;
830         }
831         
832         /* point/spot lights */
833         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
834         {
835                 /* get direction and distance */
836                 VectorCopy( light->origin, trace->end );
837                 dist = SetupTrace( trace );
838                 if( dist >= light->envelope )
839                         return 0;
840                 
841                 /* clamp the distance to prevent super hot spots */
842                 if( dist < 16.0f )
843                         dist = 16.0f;
844                 
845                 /* angle attenuation */
846                 angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
847                 if( light->angleScale != 0.0f )
848                 {
849                         angle /= light->angleScale;
850                         if( angle > 1.0f )
851                                 angle = 1.0f;
852                 }
853                 
854                 /* twosided lighting */
855                 if( trace->twoSided )
856                         angle = fabs( angle );
857                 
858                 /* attenuate */
859                 if( light->flags & LIGHT_ATTEN_LINEAR )
860                 {
861                         add = angle * light->photons * linearScale - (dist * light->fade);
862                         if( add < 0.0f )
863                                 add = 0.0f;
864                 }
865                 else
866                         add = light->photons / (dist * dist) * angle;
867                 
868                 /* handle spotlights */
869                 if( light->type == EMIT_SPOT )
870                 {
871                         float   distByNormal, radiusAtDist, sampleRadius;
872                         vec3_t  pointAtDist, distToSample;
873                         
874                         
875                         /* do cone calculation */
876                         distByNormal = -DotProduct( trace->displacement, light->normal );
877                         if( distByNormal < 0.0f )
878                                 return 0;
879                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
880                         radiusAtDist = light->radiusByDist * distByNormal;
881                         VectorSubtract( trace->origin, pointAtDist, distToSample );
882                         sampleRadius = VectorLength( distToSample );
883                         
884                         /* outside the cone */
885                         if( sampleRadius >= radiusAtDist )
886                                 return 0;
887                         
888                         /* attenuate */
889                         if( sampleRadius > (radiusAtDist - 32.0f) )
890                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
891                 }
892         }
893         
894         /* ydnar: sunlight */
895         else if( light->type == EMIT_SUN )
896         {
897                 /* get origin and direction */
898                 VectorAdd( trace->origin, light->origin, trace->end );
899                 dist = SetupTrace( trace );
900                 
901                 /* angle attenuation */
902                 angle = (light->flags & LIGHT_ATTEN_ANGLE)
903                         ? DotProduct( trace->normal, trace->direction )
904                         : 1.0f;
905                 
906                 /* twosided lighting */
907                 if( trace->twoSided )
908                         angle = fabs( angle );
909                 
910                 /* attenuate */
911                 add = light->photons * angle;
912                 if( add <= 0.0f )
913                         return 0;
914                 
915                 /* setup trace */
916                 trace->testAll = qtrue;
917                 VectorScale( light->color, add, trace->color );
918                 
919                 /* trace to point */
920                 if( trace->testOcclusion && !trace->forceSunlight )
921                 {
922                         /* trace */
923                         TraceLine( trace );
924                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
925                         {
926                                 VectorClear( trace->color );
927                                 return -1;
928                         }
929                 }
930                 
931                 /* return to sender */
932                 return 1;
933         }
934         
935         /* ydnar: changed to a variable number */
936         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
937                 return 0;
938         
939         /* setup trace */
940         trace->testAll = qfalse;
941         VectorScale( light->color, add, trace->color );
942         
943         /* raytrace */
944         TraceLine( trace );
945         if( trace->passSolid || trace->opaque )
946         {
947                 VectorClear( trace->color );
948                 return -1;
949         }
950         
951         /* return to sender */
952         return 1;
953 }
954
955
956
957 /*
958 LightingAtSample()
959 determines the amount of light reaching a sample (luxel or vertex)
960 */
961
962 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
963 {
964         int                             i, lightmapNum;
965         
966         
967         /* clear colors */
968         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
969                 VectorClear( colors[ lightmapNum ] );
970         
971         /* ydnar: normalmap */
972         if( normalmap )
973         {
974                 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
975                 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
976                 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
977                 return;
978         }
979         
980         /* ydnar: don't bounce ambient all the time */
981         if( !bouncing )
982                 VectorCopy( ambientColor, colors[ 0 ] );
983         
984         /* ydnar: trace to all the list of lights pre-stored in tw */
985         for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
986         {
987                 /* set light */
988                 trace->light = trace->lights[ i ];
989                 
990                 /* style check */
991                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
992                 {
993                         if( styles[ lightmapNum ] == trace->light->style ||
994                                 styles[ lightmapNum ] == LS_NONE )
995                                 break;
996                 }
997                 
998                 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
999                 if( lightmapNum >= MAX_LIGHTMAPS )
1000                         continue;
1001                 
1002                 /* sample light */
1003                 LightContributionToSample( trace );
1004                 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1005                         continue;
1006                 
1007                 /* handle negative light */
1008                 if( trace->light->flags & LIGHT_NEGATIVE )
1009                         VectorScale( trace->color, -1.0f, trace->color );
1010                 
1011                 /* set style */
1012                 styles[ lightmapNum ] = trace->light->style;
1013                 
1014                 /* add it */
1015                 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1016                 
1017                 /* cheap mode */
1018                 if( cheap &&
1019                         colors[ 0 ][ 0 ] >= 255.0f &&
1020                         colors[ 0 ][ 1 ] >= 255.0f &&
1021                         colors[ 0 ][ 2 ] >= 255.0f )
1022                         break;
1023         }
1024 }
1025
1026
1027
1028 /*
1029 LightContributionToPoint()
1030 for a given light, how much light/color reaches a given point in space (with no facing)
1031 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1032 */
1033
1034 int LightContributionToPoint( trace_t *trace )
1035 {
1036         light_t         *light;
1037         float           add, dist;
1038         
1039         
1040         /* get light */
1041         light = trace->light;
1042         
1043         /* clear color */
1044         VectorClear( trace->color );
1045         
1046         /* ydnar: early out */
1047         if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1048                 return qfalse;
1049         
1050         /* is this a sun? */
1051         if( light->type != EMIT_SUN )
1052         {
1053                 /* sun only? */
1054                 if( sunOnly )
1055                         return qfalse;
1056                 
1057                 /* test pvs */
1058                 if( !ClusterVisible( trace->cluster, light->cluster ) )
1059                         return qfalse;
1060         }
1061         
1062         /* ydnar: check origin against light's pvs envelope */
1063         if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1064                 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1065                 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1066         {
1067                 gridBoundsCulled++;
1068                 return qfalse;
1069         }
1070         
1071         /* set light origin */
1072         if( light->type == EMIT_SUN )
1073                 VectorAdd( trace->origin, light->origin, trace->end );
1074         else
1075                 VectorCopy( light->origin, trace->end );
1076         
1077         /* set direction */
1078         dist = SetupTrace( trace );
1079         
1080         /* test envelope */
1081         if( dist > light->envelope )
1082         {
1083                 gridEnvelopeCulled++;
1084                 return qfalse;
1085         }
1086         
1087         /* ptpff approximation */
1088         if( light->type == EMIT_AREA && faster )
1089         {
1090                 /* clamp the distance to prevent super hot spots */
1091                 if( dist < 16.0f )
1092                         dist = 16.0f;
1093                 
1094                 /* attenuate */
1095                 add = light->photons / (dist * dist);
1096         }
1097         
1098         /* exact point to polygon form factor */
1099         else if( light->type == EMIT_AREA )
1100         {
1101                 float           factor, d;
1102                 vec3_t          pushedOrigin;
1103                 
1104                 
1105                 /* see if the point is behind the light */
1106                 d = DotProduct( trace->origin, light->normal ) - light->dist;
1107                 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1108                         return qfalse;
1109                 
1110                 /* nudge the point so that it is clearly forward of the light */
1111                 /* so that surfaces meeting a light emiter don't get black edges */
1112                 if( d > -8.0f && d < 8.0f )
1113                         VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
1114                 else
1115                         VectorCopy( trace->origin, pushedOrigin );
1116                 
1117                 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1118                 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1119                 if( factor == 0.0f )
1120                         return qfalse;
1121                 else if( factor < 0.0f )
1122                 {
1123                         if( light->flags & LIGHT_TWOSIDED )
1124                                 factor = -factor;
1125                         else
1126                                 return qfalse;
1127                 }
1128                 
1129                 /* ydnar: moved to here */
1130                 add = factor * light->add;
1131         }
1132         
1133         /* point/spot lights */
1134         else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1135         {
1136                 /* clamp the distance to prevent super hot spots */
1137                 if( dist < 16.0f )
1138                         dist = 16.0f;
1139                 
1140                 /* attenuate */
1141                 if( light->flags & LIGHT_ATTEN_LINEAR )
1142                 {
1143                         add = light->photons * linearScale - (dist * light->fade);
1144                         if( add < 0.0f )
1145                                 add = 0.0f;
1146                 }
1147                 else
1148                         add = light->photons / (dist * dist);
1149                 
1150                 /* handle spotlights */
1151                 if( light->type == EMIT_SPOT )
1152                 {
1153                         float   distByNormal, radiusAtDist, sampleRadius;
1154                         vec3_t  pointAtDist, distToSample;
1155                         
1156                         
1157                         /* do cone calculation */
1158                         distByNormal = -DotProduct( trace->displacement, light->normal );
1159                         if( distByNormal < 0.0f )
1160                                 return qfalse;
1161                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1162                         radiusAtDist = light->radiusByDist * distByNormal;
1163                         VectorSubtract( trace->origin, pointAtDist, distToSample );
1164                         sampleRadius = VectorLength( distToSample );
1165                         
1166                         /* outside the cone */
1167                         if( sampleRadius >= radiusAtDist )
1168                                 return qfalse;
1169                         
1170                         /* attenuate */
1171                         if( sampleRadius > (radiusAtDist - 32.0f) )
1172                                 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1173                 }
1174         }
1175         
1176         /* ydnar: sunlight */
1177         else if( light->type == EMIT_SUN )
1178         {
1179                 /* attenuate */
1180                 add = light->photons;
1181                 if( add <= 0.0f )
1182                         return qfalse;
1183                 
1184                 /* setup trace */
1185                 trace->testAll = qtrue;
1186                 VectorScale( light->color, add, trace->color );
1187                 
1188                 /* trace to point */
1189                 if( trace->testOcclusion && !trace->forceSunlight )
1190                 {
1191                         /* trace */
1192                         TraceLine( trace );
1193                         if( !(trace->compileFlags & C_SKY) || trace->opaque )
1194                         {
1195                                 VectorClear( trace->color );
1196                                 return -1;
1197                         }
1198                 }
1199                 
1200                 /* return to sender */
1201                 return qtrue;
1202         }
1203         
1204         /* unknown light type */
1205         else
1206                 return qfalse;
1207         
1208         /* ydnar: changed to a variable number */
1209         if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1210                 return qfalse;
1211         
1212         /* setup trace */
1213         trace->testAll = qfalse;
1214         VectorScale( light->color, add, trace->color );
1215         
1216         /* trace */
1217         TraceLine( trace );
1218         if( trace->passSolid )
1219         {
1220                 VectorClear( trace->color );
1221                 return qfalse;
1222         }
1223         
1224         /* we have a valid sample */
1225         return qtrue;
1226 }
1227
1228
1229
1230 /*
1231 TraceGrid()
1232 grid samples are for quickly determining the lighting
1233 of dynamically placed entities in the world
1234 */
1235
1236 #define MAX_CONTRIBUTIONS       1024
1237
1238 typedef struct
1239 {
1240         vec3_t          dir;
1241         vec3_t          color;
1242         int                     style;
1243 }
1244 contribution_t;
1245
1246 void TraceGrid( int num )
1247 {
1248         int                                             i, j, x, y, z, mod, step, numCon, numStyles;
1249         float                                   d;
1250         vec3_t                                  baseOrigin, cheapColor, color;
1251         rawGridPoint_t                  *gp;
1252         bspGridPoint_t                  *bgp;
1253         contribution_t                  contributions[ MAX_CONTRIBUTIONS ];
1254         trace_t                                 trace;
1255         
1256         
1257         /* get grid points */
1258         gp = &rawGridPoints[ num ];
1259         bgp = &bspGridPoints[ num ];
1260         
1261         /* get grid origin */
1262         mod = num;
1263         z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1264         mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1265         y = mod / gridBounds[ 0 ];
1266         mod -= y * gridBounds[ 0 ];
1267         x = mod;
1268         
1269         trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1270         trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1271         trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1272         
1273         /* set inhibit sphere */
1274         if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1275                 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1276         else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1277                 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1278         else
1279                 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1280         
1281         /* find point cluster */
1282         trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1283         if( trace.cluster < 0 )
1284         {
1285                 /* try to nudge the origin around to find a valid point */
1286                 VectorCopy( trace.origin, baseOrigin );
1287                 for( step = 9; step <= 18; step += 9 )
1288                 {
1289                         for( i = 0; i < 8; i++ )
1290                         {
1291                                 VectorCopy( baseOrigin, trace.origin );
1292                                 if( i & 1 )
1293                                         trace.origin[ 0 ] += step;
1294                                 else
1295                                         trace.origin[ 0 ] -= step;
1296                                 
1297                                 if( i & 2 )
1298                                         trace.origin[ 1 ] += step;
1299                                 else
1300                                         trace.origin[ 1 ] -= step;
1301                                 
1302                                 if( i & 4 )
1303                                         trace.origin[ 2 ] += step;
1304                                 else
1305                                         trace.origin[ 2 ] -= step;
1306                                 
1307                                 /* ydnar: changed to find cluster num */
1308                                 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1309                                 if( trace.cluster >= 0 )
1310                                         break;
1311                         }
1312                         
1313                         if( i != 8 )
1314                                 break;
1315                 }
1316                 
1317                 /* can't find a valid point at all */
1318                 if( step > 18 )
1319                         return;
1320         }
1321         
1322         /* setup trace */
1323         trace.testOcclusion = !noTrace;
1324         trace.forceSunlight = qfalse;
1325         trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1326         trace.numSurfaces = 0;
1327         trace.surfaces = NULL;
1328         trace.numLights = 0;
1329         trace.lights = NULL;
1330         
1331         /* clear */
1332         numCon = 0;
1333         VectorClear( cheapColor );
1334         
1335         /* trace to all the lights, find the major light direction, and divide the
1336            total light between that along the direction and the remaining in the ambient */
1337         for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1338         {
1339                 float           addSize;
1340                 
1341                 
1342                 /* sample light */
1343                 if( !LightContributionToPoint( &trace ) )
1344                         continue;
1345                 
1346                 /* handle negative light */
1347                 if( trace.light->flags & LIGHT_NEGATIVE )
1348                         VectorScale( trace.color, -1.0f, trace.color );
1349                 
1350                 /* add a contribution */
1351                 VectorCopy( trace.color, contributions[ numCon ].color );
1352                 VectorCopy( trace.direction, contributions[ numCon ].dir );
1353                 contributions[ numCon ].style = trace.light->style;
1354                 numCon++;
1355                 
1356                 /* push average direction around */
1357                 addSize = VectorLength( trace.color );
1358                 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1359                 
1360                 /* stop after a while */
1361                 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1362                         break;
1363                 
1364                 /* ydnar: cheap mode */
1365                 VectorAdd( cheapColor, trace.color, cheapColor );
1366                 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1367                         break;
1368         }
1369         
1370         /* normalize to get primary light direction */
1371         VectorNormalize( gp->dir, gp->dir );
1372         
1373         /* now that we have identified the primary light direction,
1374            go back and separate all the light into directed and ambient */
1375         numStyles = 1;
1376         for( i = 0; i < numCon; i++ )
1377         {
1378                 /* get relative directed strength */
1379                 d = DotProduct( contributions[ i ].dir, gp->dir );
1380                 if( d < 0.0f )
1381                         d = 0.0f;
1382                 
1383                 /* find appropriate style */
1384                 for( j = 0; j < numStyles; j++ )
1385                 {
1386                         if( gp->styles[ j ] == contributions[ i ].style )
1387                                 break;
1388                 }
1389                 
1390                 /* style not found? */
1391                 if( j >= numStyles )
1392                 {
1393                         /* add a new style */
1394                         if( numStyles < MAX_LIGHTMAPS )
1395                         {
1396                                 gp->styles[ numStyles ] = contributions[ i ].style;
1397                                 bgp->styles[ numStyles ] = contributions[ i ].style;
1398                                 numStyles++;
1399                                 //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1400                         }
1401                         
1402                         /* fallback */
1403                         else
1404                                 j = 0;
1405                 }
1406                 
1407                 /* add the directed color */
1408                 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1409                 
1410                 /* ambient light will be at 1/4 the value of directed light */
1411                 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1412                 d = 0.25f * (1.0f - d);
1413                 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1414         }
1415         
1416         
1417         /* store off sample */
1418         for( i = 0; i < MAX_LIGHTMAPS; i++ )
1419         {
1420                 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1421                 if( !bouncing )
1422                         VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1423                 
1424                 /* set minimum light and copy off to bytes */
1425                 VectorCopy( gp->ambient[ i ], color );
1426                 for( j = 0; j < 3; j++ )
1427                         if( color[ j ] < minGridLight[ j ] )
1428                                 color[ j ] = minGridLight[ j ];
1429                 ColorToBytes( color, bgp->ambient[ i ], 1.0f );
1430                 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );
1431         }
1432         
1433         /* debug code */
1434         #if 0
1435                 //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1436                 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1437                         num,
1438                         gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1439                         gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1440         #endif
1441         
1442         /* store direction */
1443         NormalToLatLong( gp->dir, bgp->latLong );
1444 }
1445
1446
1447
1448 /*
1449 SetupGrid()
1450 calculates the size of the lightgrid and allocates memory
1451 */
1452
1453 void SetupGrid( void )
1454 {
1455         int                     i, j;
1456         vec3_t          maxs, oldGridSize;
1457         const char      *value;
1458         char            temp[ 64 ];
1459         
1460          
1461         /* don't do this if not grid lighting */
1462         if( noGridLighting )
1463                 return;
1464         
1465         /* ydnar: set grid size */
1466         value = ValueForKey( &entities[ 0 ], "gridsize" );
1467         if( value[ 0 ] != '\0' )
1468                 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1469         
1470         /* quantize it */
1471         VectorCopy( gridSize, oldGridSize );
1472         for( i = 0; i < 3; i++ )
1473                 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1474         
1475         /* ydnar: increase gridSize until grid count is smaller than max allowed */
1476         numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1477         j = 0;
1478         while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1479         {
1480                 /* get world bounds */
1481                 for( i = 0; i < 3; i++ )
1482                 {
1483                         gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1484                         maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1485                         gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1486                 }
1487         
1488                 /* set grid size */
1489                 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1490                 
1491                 /* increase grid size a bit */
1492                 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1493                         gridSize[ j++ % 3 ] += 16.0f;
1494         }
1495         
1496         /* print it */
1497         Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1498         
1499         /* different? */
1500         if( !VectorCompare( gridSize, oldGridSize ) )
1501         {
1502                 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1503                 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1504                 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1505         }
1506         
1507         /* 2nd variable. fixme: is this silly? */
1508         numBSPGridPoints = numRawGridPoints;
1509         
1510         /* allocate lightgrid */
1511         rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1512         memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1513         
1514         if( bspGridPoints != NULL )
1515                 free( bspGridPoints );
1516         bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1517         memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1518         
1519         /* clear lightgrid */
1520         for( i = 0; i < numRawGridPoints; i++ )
1521         {
1522                 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1523                 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1524                 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1525                 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1526                 {
1527                         rawGridPoints[ i ].styles[ j ] = LS_NONE;
1528                         bspGridPoints[ i ].styles[ j ] = LS_NONE;
1529                 }
1530         }
1531         
1532         /* note it */
1533         Sys_Printf( "%9d grid points\n", numRawGridPoints );
1534 }
1535
1536
1537
1538 /*
1539 LightWorld()
1540 does what it says...
1541 */
1542
1543 void LightWorld( void )
1544 {
1545         vec3_t          color;
1546         float           f;
1547         int                     b, bt;
1548         qboolean        minVertex, minGrid;
1549         const char      *value;
1550         
1551
1552         /* ydnar: smooth normals */
1553         if( shade )
1554         {
1555                 Sys_Printf( "--- SmoothNormals ---\n" );
1556                 SmoothNormals();
1557         }
1558         
1559         /* determine the number of grid points */
1560         Sys_Printf( "--- SetupGrid ---\n" );
1561         SetupGrid();
1562         
1563         /* find the optional minimum lighting values */
1564         GetVectorForKey( &entities[ 0 ], "_color", color );
1565         if( VectorLength( color ) == 0.0f )
1566                 VectorSet( color, 1.0, 1.0, 1.0 );
1567         
1568         /* ambient */
1569         f = FloatForKey( &entities[ 0 ], "_ambient" );
1570         if( f == 0.0f )
1571                 f = FloatForKey( &entities[ 0 ], "ambient" );
1572         VectorScale( color, f, ambientColor );
1573         
1574         /* minvertexlight */
1575         minVertex = qfalse;
1576         value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1577         if( value[ 0 ] != '\0' )
1578         {
1579                 minVertex = qtrue;
1580                 f = atof( value );
1581                 VectorScale( color, f, minVertexLight );
1582         }
1583         
1584         /* mingridlight */
1585         minGrid = qfalse;
1586         value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1587         if( value[ 0 ] != '\0' )
1588         {
1589                 minGrid = qtrue;
1590                 f = atof( value );
1591                 VectorScale( color, f, minGridLight );
1592         }
1593         
1594         /* minlight */
1595         value = ValueForKey( &entities[ 0 ], "_minlight" );
1596         if( value[ 0 ] != '\0' )
1597         {
1598                 f = atof( value );
1599                 VectorScale( color, f, minLight );
1600                 if( minVertex == qfalse )
1601                         VectorScale( color, f, minVertexLight );
1602                 if( minGrid == qfalse )
1603                         VectorScale( color, f, minGridLight );
1604         }
1605         
1606         /* create world lights */
1607         Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1608         CreateEntityLights();
1609         CreateSurfaceLights();
1610         Sys_Printf( "%9d point lights\n", numPointLights );
1611         Sys_Printf( "%9d spotlights\n", numSpotLights );
1612         Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1613         Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1614         
1615         /* calculate lightgrid */
1616         if( !noGridLighting )
1617         {
1618                 /* ydnar: set up light envelopes */
1619                 SetupEnvelopes( qtrue, fastgrid );
1620                 
1621                 Sys_Printf( "--- TraceGrid ---\n" );
1622                 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1623                 Sys_Printf( "%d x %d x %d = %d grid\n",
1624                         gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1625                 
1626                 /* ydnar: emit statistics on light culling */
1627                 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1628                 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1629         }
1630         
1631         /* slight optimization to remove a sqrt */
1632         subdivideThreshold *= subdivideThreshold;
1633         
1634         /* map the world luxels */
1635         Sys_Printf( "--- MapRawLightmap ---\n" );
1636         RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1637         Sys_Printf( "%9d luxels\n", numLuxels );
1638         Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1639         Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1640
1641         /* ydnar: set up light envelopes */
1642         SetupEnvelopes( qfalse, fast );
1643         
1644         /* light up my world */
1645         lightsPlaneCulled = 0;
1646         lightsEnvelopeCulled = 0;
1647         lightsBoundsCulled = 0;
1648         lightsClusterCulled = 0;
1649         
1650         Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1651         RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1652         Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1653         
1654         StitchSurfaceLightmaps();
1655         
1656         Sys_Printf( "--- IlluminateVertexes ---\n" );
1657         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1658         Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1659         
1660         /* ydnar: emit statistics on light culling */
1661         Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1662         Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1663         Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1664         Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1665         
1666         /* radiosity */
1667         b = 1;
1668         bt = bounce;
1669         while( bounce > 0 )
1670         {
1671                 /* store off the bsp between bounces */
1672                 StoreSurfaceLightmaps();
1673                 Sys_Printf( "Writing %s\n", source );
1674                 WriteBSPFile( source );
1675                 
1676                 /* note it */
1677                 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1678                 
1679                 /* flag bouncing */
1680                 bouncing = qtrue;
1681                 VectorClear( ambientColor );
1682                 
1683                 /* generate diffuse lights */
1684                 RadFreeLights();
1685                 RadCreateDiffuseLights();
1686                 
1687                 /* setup light envelopes */
1688                 SetupEnvelopes( qfalse, fastbounce );
1689                 if( numLights == 0 )
1690                 {
1691                         Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1692                         break;
1693                 }
1694                 
1695                 /* add to lightgrid */
1696                 if( bouncegrid )
1697                 {
1698                         gridEnvelopeCulled = 0;
1699                         gridBoundsCulled = 0;
1700                         
1701                         Sys_Printf( "--- BounceGrid ---\n" );
1702                         RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1703                         Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1704                         Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1705                 }
1706                 
1707                 /* light up my world */
1708                 lightsPlaneCulled = 0;
1709                 lightsEnvelopeCulled = 0;
1710                 lightsBoundsCulled = 0;
1711                 lightsClusterCulled = 0;
1712                 
1713                 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1714                 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1715                 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1716                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1717                 
1718                 StitchSurfaceLightmaps();
1719                 
1720                 Sys_Printf( "--- IlluminateVertexes ---\n" );
1721                 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1722                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1723                 
1724                 /* ydnar: emit statistics on light culling */
1725                 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1726                 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1727                 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1728                 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1729                 
1730                 /* interate */
1731                 bounce--;
1732                 b++;
1733         }
1734 }
1735
1736
1737
1738 /*
1739 LightMain()
1740 main routine for light processing
1741 */
1742
1743 int LightMain( int argc, char **argv )
1744 {
1745         int                     i;
1746         float           f;
1747         char            mapSource[ 1024 ];
1748         const char      *value;
1749         
1750         
1751         /* note it */
1752         Sys_Printf( "--- Light ---\n" );
1753         
1754         /* process commandline arguments */
1755         for( i = 1; i < (argc - 1); i++ )
1756         {
1757                 /* lightsource scaling */
1758                 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
1759                 {
1760                         f = atof( argv[ i + 1 ] );
1761                         pointScale *= f;
1762                         Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1763                         i++;
1764                 }
1765                 
1766                 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
1767                 {
1768                         f = atof( argv[ i + 1 ] );
1769                         areaScale *= f;
1770                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1771                         i++;
1772                 }
1773                 
1774                 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
1775                 {
1776                         f = atof( argv[ i + 1 ] );
1777                         skyScale *= f;
1778                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1779                         i++;
1780                 }
1781                 
1782                 else if( !strcmp( argv[ i ], "-bouncescale" ) )
1783                 {
1784                         f = atof( argv[ i + 1 ] );
1785                         bounceScale *= f;
1786                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
1787                         i++;
1788                 }
1789                 
1790                 else if( !strcmp( argv[ i ], "-scale" ) )
1791                 {
1792                         f = atof( argv[ i + 1 ] );
1793                         pointScale *= f;
1794                         areaScale *= f;
1795                         skyScale *= f;
1796                         bounceScale *= f;
1797                         Sys_Printf( "All light scaled by %f\n", f );
1798                         i++;
1799                 }
1800                 
1801                 /* ydnar switches */
1802                 else if( !strcmp( argv[ i ], "-bounce" ) )
1803                 {
1804                         bounce = atoi( argv[ i + 1 ] );
1805                         if( bounce < 0 )
1806                                 bounce = 0;
1807                         else if( bounce > 0 )
1808                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
1809                         i++;
1810                 }
1811                 
1812                 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
1813                 {
1814                         superSample = atoi( argv[ i + 1 ] );
1815                         if( superSample < 1 )
1816                                 superSample = 1;
1817                         else if( superSample > 1 )
1818                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
1819                         i++;
1820                 }
1821                 
1822                 else if( !strcmp( argv[ i ], "-samples" ) )
1823                 {
1824                         lightSamples = atoi( argv[ i + 1 ] );
1825                         if( lightSamples < 1 )
1826                                 lightSamples = 1;
1827                         else if( lightSamples > 1 )
1828                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
1829                         i++;
1830                 }
1831                 
1832                 else if( !strcmp( argv[ i ], "-filter" ) )
1833                 {
1834                         filter = qtrue;
1835                         Sys_Printf( "Lightmap filtering enabled\n" );
1836                 }
1837                 
1838                 else if( !strcmp( argv[ i ], "-shadeangle" ) )
1839                 {
1840                         shadeAngleDegrees = atof( argv[ i + 1 ] );
1841                         if( shadeAngleDegrees < 0.0f )
1842                                 shadeAngleDegrees = 0.0f;
1843                         else if( shadeAngleDegrees > 0.0f )
1844                         {
1845                                 shade = qtrue;
1846                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
1847                         }
1848                         i++;
1849                 }
1850                 
1851                 else if( !strcmp( argv[ i ], "-thresh" ) )
1852                 {
1853                         subdivideThreshold = atof( argv[ i + 1 ] );
1854                         if( subdivideThreshold < 0 )
1855                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
1856                         else
1857                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
1858                         i++;
1859                 }
1860                 
1861                 else if( !strcmp( argv[ i ], "-approx" ) )
1862                 {
1863                         approximateTolerance = atoi( argv[ i + 1 ] );
1864                         if( approximateTolerance < 0 )
1865                                 approximateTolerance = 0;
1866                         else if( approximateTolerance > 0 )
1867                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
1868                         i++;
1869                 }
1870                 
1871                 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
1872                 {
1873                         deluxemap = qtrue;
1874                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
1875                 }
1876                 
1877                 else if( !strcmp( argv[ i ], "-external" ) )
1878                 {
1879                         externalLightmaps = qtrue;
1880                         Sys_Printf( "Storing all lightmaps externally\n" );
1881                 }
1882
1883                 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
1884                 {
1885                         lmCustomSize = atoi( argv[ i + 1 ] );
1886                         
1887                         /* must be a power of 2 and greater than 2 */
1888                         if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
1889                         {
1890                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
1891                                 lmCustomSize = LIGHTMAP_WIDTH;
1892                         }
1893                         i++;
1894                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
1895                         
1896                         /* enable external lightmaps */
1897                         if( lmCustomSize != LIGHTMAP_WIDTH )
1898                         {
1899                                 externalLightmaps = qtrue;
1900                                 Sys_Printf( "Storing all lightmaps externally\n" );
1901                         }
1902                 }
1903                 
1904                 /* ydnar: add this to suppress warnings */
1905                 else if( !strcmp( argv[ i ],  "-custinfoparms") )
1906                 {
1907                         Sys_Printf( "Custom info parms enabled\n" );
1908                         useCustomInfoParms = qtrue;
1909                 }
1910                 
1911                 else if( !strcmp( argv[ i ], "-wolf" ) )
1912                 {
1913                         /* -game should already be set */
1914                         game->wolfLight = qtrue;
1915                         Sys_Printf( "Enabling Wolf lighting model\n" );
1916                 }
1917                 
1918                 else if( !strcmp( argv[ i ], "-sunonly" ) )
1919                 {
1920                         sunOnly = qtrue;
1921                         Sys_Printf( "Only computing sunlight\n" );
1922                 }
1923                 
1924                 else if( !strcmp( argv[ i ], "-bounceonly" ) )
1925                 {
1926                         bounceOnly = qtrue;
1927                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
1928                 }
1929                 
1930                 else if( !strcmp( argv[ i ], "-nocollapse" ) )
1931                 {
1932                         noCollapse = qtrue;
1933                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
1934                 }
1935                 
1936                 else if( !strcmp( argv[ i ], "-shade" ) )
1937                 {
1938                         shade = qtrue;
1939                         Sys_Printf( "Phong shading enabled\n" );
1940                 }
1941                 
1942                 else if( !strcmp( argv[ i ], "-bouncegrid") )
1943                 {
1944                         bouncegrid = qtrue;
1945                         if( bounce > 0 )
1946                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
1947                 }
1948                 
1949                 else if( !strcmp( argv[ i ], "-smooth" ) )
1950                 {
1951                         smooth = qtrue;
1952                         lightSamples = EXTRA_SCALE;
1953                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
1954                 }
1955                 
1956                 else if( !strcmp( argv[ i ], "-fast" ) )
1957                 {
1958                         fast = qtrue;
1959                         fastgrid = qtrue;
1960                         fastbounce = qtrue;
1961                         Sys_Printf( "Fast mode enabled\n" );
1962                 }
1963                 
1964                 else if( !strcmp( argv[ i ], "-faster" ) )
1965                 {
1966                         faster = qtrue;
1967                         fast = qtrue;
1968                         fastgrid = qtrue;
1969                         fastbounce = qtrue;
1970                         Sys_Printf( "Faster mode enabled\n" );
1971                 }
1972                 
1973                 else if( !strcmp( argv[ i ], "-fastgrid" ) )
1974                 {
1975                         fastgrid = qtrue;
1976                         Sys_Printf( "Fast grid lighting enabled\n" );
1977                 }
1978                 
1979                 else if( !strcmp( argv[ i ], "-fastbounce" ) )
1980                 {
1981                         fastbounce = qtrue;
1982                         Sys_Printf( "Fast bounce mode enabled\n" );
1983                 }
1984                 
1985                 else if( !strcmp( argv[ i ], "-cheap" ) )
1986                 {
1987                         cheap = qtrue;
1988                         cheapgrid = qtrue;
1989                         Sys_Printf( "Cheap mode enabled\n" );
1990                 }
1991
1992                 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
1993                 {
1994                         cheapgrid = qtrue;
1995                         Sys_Printf( "Cheap grid mode enabled\n" );
1996                 }
1997                 
1998                 else if( !strcmp( argv[ i ], "-normalmap" ) )
1999                 {
2000                         normalmap = qtrue;
2001                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2002                 }
2003                 
2004                 else if( !strcmp( argv[ i ], "-trisoup" ) )
2005                 {
2006                         trisoup = qtrue;
2007                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2008                 }
2009                 
2010                 else if( !strcmp( argv[ i ], "-debug" ) )
2011                 {
2012                         debug = qtrue;
2013                         Sys_Printf( "Lightmap debugging enabled\n" );
2014                 }
2015                 
2016                 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2017                 {
2018                         debugSurfaces = qtrue;
2019                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2020                 }
2021                 
2022                 else if( !strcmp( argv[ i ], "-debugunused" ) )
2023                 {
2024                         debugUnused = qtrue;
2025                         Sys_Printf( "Unused luxel debugging enabled\n" );
2026                 }
2027
2028                 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2029                 {
2030                         debugAxis = qtrue;
2031                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2032                 }
2033                 
2034                 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2035                 {
2036                         debugCluster = qtrue;
2037                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2038                 }
2039                 
2040                 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2041                 {
2042                         debugOrigin = qtrue;
2043                         Sys_Printf( "Luxel origin debugging enabled\n" );
2044                 }
2045                 
2046                 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2047                 {
2048                         deluxemap = qtrue;
2049                         debugDeluxemap = qtrue;
2050                         Sys_Printf( "Deluxemap debugging enabled\n" );
2051                 }
2052                 
2053                 else if( !strcmp( argv[ i ], "-export" ) )
2054                 {
2055                         exportLightmaps = qtrue;
2056                         Sys_Printf( "Exporting lightmaps\n" );
2057                 }
2058                 
2059                 else if( !strcmp(argv[ i ], "-notrace" )) 
2060                 {
2061                         noTrace = qtrue;
2062                         Sys_Printf( "Shadow occlusion disabled\n" );
2063                 }
2064                 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2065                 {
2066                         patchShadows = qtrue;
2067                         Sys_Printf( "Patch shadow casting enabled\n" );
2068                 }
2069                 else if( !strcmp( argv[ i ], "-extra" ) )
2070                 {
2071                         extra = qtrue;
2072                         superSample = EXTRA_SCALE;              /* ydnar */
2073                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2074                 }
2075                 else if( !strcmp( argv[ i ], "-extrawide" ) )
2076                 {
2077                         extra = qtrue;
2078                         extraWide = qtrue;
2079                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2080                         filter = qtrue;                                 /* ydnar */
2081                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2082                 }
2083                 else if( !strcmp( argv[ i ], "-samplesize" ) )
2084                 {
2085                         sampleSize = atoi( argv[ i + 1 ] );
2086                         if( sampleSize < 1 )
2087                                 sampleSize = 1;
2088                         i++;
2089                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2090                 }
2091                 else if( !strcmp( argv[ i ], "-novertex" ) )
2092                 {
2093                         noVertexLighting = qtrue;
2094                         Sys_Printf( "Disabling vertex lighting\n" );
2095                 }
2096                 else if( !strcmp( argv[ i ], "-nogrid" ) )
2097                 {
2098                         noGridLighting = qtrue;
2099                         Sys_Printf( "Disabling grid lighting\n" );
2100                 }
2101                 else if( !strcmp( argv[ i ], "-border" ) )
2102                 {
2103                         lightmapBorder = qtrue;
2104                         Sys_Printf( "Adding debug border to lightmaps\n" );
2105                 }
2106                 else if( !strcmp( argv[ i ], "-nosurf" ) )
2107                 {
2108                         noSurfaces = qtrue;
2109                         Sys_Printf( "Not tracing against surfaces\n" );
2110                 }
2111                 else if( !strcmp( argv[ i ], "-dump" ) )
2112                 {
2113                         dump = qtrue;
2114                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2115                 }
2116                 else if( !strcmp( argv[ i ], "-lomem" ) )
2117                 {
2118                         loMem = qtrue;
2119                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2120                 }
2121                 
2122                 else
2123                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
2124         }
2125         
2126         /* clean up map name */
2127         strcpy( source, ExpandArg( argv[ i ] ) );
2128         StripExtension( source );
2129         DefaultExtension( source, ".bsp" );
2130         strcpy( mapSource, ExpandArg( argv[ i ] ) );
2131         StripExtension( mapSource );
2132         DefaultExtension( mapSource, ".map" );
2133         
2134         /* ydnar: set default sample size */
2135         SetDefaultSampleSize( sampleSize );
2136         
2137         /* ydnar: handle shaders */
2138         BeginMapShaderFile( source );
2139         LoadShaderInfo();
2140         
2141         /* note loading */
2142         Sys_Printf( "Loading %s\n", source );
2143         
2144         /* ydnar: load surface file */
2145         LoadSurfaceExtraFile( source );
2146         
2147         /* load bsp file */
2148         LoadBSPFile( source );
2149         
2150         /* parse bsp entities */
2151         ParseEntities();
2152         
2153         /* load map file */
2154         value = ValueForKey( &entities[ 0 ], "_keepLights" );
2155         if( value[ 0 ] != '1' )
2156                 LoadMapFile( mapSource, qtrue );
2157         
2158         /* set the entity/model origins and init yDrawVerts */
2159         SetEntityOrigins();
2160         
2161         /* ydnar: set up optimization */
2162         SetupBrushes();
2163         SetupSurfaceLightmaps();
2164         
2165         /* initialize the surface facet tracing */
2166         SetupTraceNodes();
2167         
2168         /* light the world */
2169         LightWorld();
2170         
2171         /* ydnar: store off lightmaps */
2172         StoreSurfaceLightmaps();
2173         
2174         /* write out the bsp */
2175         UnparseEntities();
2176         Sys_Printf( "Writing %s\n", source );
2177         WriteBSPFile( source );
2178         
2179         /* ydnar: export lightmaps */
2180         if( exportLightmaps && !externalLightmaps )
2181                 ExportLightmaps();
2182         
2183         /* return to sender */
2184         return 0;
2185 }
2186