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