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