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