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