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