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