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