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