]> 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                 VectorFastNormalize( 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 ( VectorFastNormalize( 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[ 0 ] );
1878                 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1879                 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1880                 for ( j = 1; j < MAX_LIGHTMAPS; j++ )
1881                 {
1882                         VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1883                         rawGridPoints[ i ].styles[ j ] = LS_NONE;
1884                         bspGridPoints[ i ].styles[ j ] = LS_NONE;
1885                 }
1886         }
1887
1888         /* note it */
1889         Sys_Printf( "%9d grid points\n", numRawGridPoints );
1890 }
1891
1892
1893
1894 /*
1895    LightWorld()
1896    does what it says...
1897  */
1898
1899 void LightWorld( const char *BSPFilePath, qboolean fastAllocate, qboolean noBounceStore ){
1900         vec3_t color;
1901         float f;
1902         int b, bt;
1903         qboolean minVertex, minGrid;
1904         const char  *value;
1905
1906         /* ydnar: smooth normals */
1907         if ( shade ) {
1908                 Sys_Printf( "--- SmoothNormals ---\n" );
1909                 SmoothNormals();
1910         }
1911
1912         /* determine the number of grid points */
1913         Sys_Printf( "--- SetupGrid ---\n" );
1914         SetupGrid();
1915
1916         /* find the optional minimum lighting values */
1917         GetVectorForKey( &entities[ 0 ], "_color", color );
1918         if ( VectorLength( color ) == 0.0f ) {
1919                 VectorSet( color, 1.0, 1.0, 1.0 );
1920         }
1921
1922         if ( colorsRGB ) {
1923                 color[0] = Image_LinearFloatFromsRGBFloat( color[0] );
1924                 color[1] = Image_LinearFloatFromsRGBFloat( color[1] );
1925                 color[2] = Image_LinearFloatFromsRGBFloat( color[2] );
1926         }
1927
1928         /* ambient */
1929         f = FloatForKey( &entities[ 0 ], "_ambient" );
1930         if ( f == 0.0f ) {
1931                 f = FloatForKey( &entities[ 0 ], "ambient" );
1932         }
1933         VectorScale( color, f, ambientColor );
1934
1935         /* minvertexlight */
1936         minVertex = qfalse;
1937         value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1938         if ( value[ 0 ] != '\0' ) {
1939                 minVertex = qtrue;
1940                 f = atof( value );
1941                 VectorScale( color, f, minVertexLight );
1942         }
1943
1944         /* mingridlight */
1945         minGrid = qfalse;
1946         value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1947         if ( value[ 0 ] != '\0' ) {
1948                 minGrid = qtrue;
1949                 f = atof( value );
1950                 VectorScale( color, f, minGridLight );
1951         }
1952
1953         /* minlight */
1954         value = ValueForKey( &entities[ 0 ], "_minlight" );
1955         if ( value[ 0 ] != '\0' ) {
1956                 f = atof( value );
1957                 VectorScale( color, f, minLight );
1958                 if ( minVertex == qfalse ) {
1959                         VectorScale( color, f, minVertexLight );
1960                 }
1961                 if ( minGrid == qfalse ) {
1962                         VectorScale( color, f, minGridLight );
1963                 }
1964         }
1965
1966         /* create world lights */
1967         Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1968         CreateEntityLights();
1969         CreateSurfaceLights();
1970         Sys_Printf( "%9d point lights\n", numPointLights );
1971         Sys_Printf( "%9d spotlights\n", numSpotLights );
1972         Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1973         Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1974
1975         /* calculate lightgrid */
1976         if ( !noGridLighting ) {
1977                 /* ydnar: set up light envelopes */
1978                 SetupEnvelopes( qtrue, fastgrid );
1979
1980                 Sys_Printf( "--- TraceGrid ---\n" );
1981                 inGrid = qtrue;
1982                 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1983                 inGrid = qfalse;
1984                 Sys_Printf( "%d x %d x %d = %d grid\n",
1985                                         gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1986
1987                 /* ydnar: emit statistics on light culling */
1988                 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1989                 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1990         }
1991
1992         /* slight optimization to remove a sqrt */
1993         subdivideThreshold *= subdivideThreshold;
1994
1995         /* map the world luxels */
1996         Sys_Printf( "--- MapRawLightmap ---\n" );
1997         RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1998         Sys_Printf( "%9d luxels\n", numLuxels );
1999         Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
2000         Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
2001
2002         /* dirty them up */
2003         if ( dirty ) {
2004                 Sys_Printf( "--- DirtyRawLightmap ---\n" );
2005                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
2006         }
2007
2008         /* floodlight pass */
2009         FloodlightRawLightmaps();
2010
2011         /* ydnar: set up light envelopes */
2012         SetupEnvelopes( qfalse, fast );
2013
2014         /* light up my world */
2015         lightsPlaneCulled = 0;
2016         lightsEnvelopeCulled = 0;
2017         lightsBoundsCulled = 0;
2018         lightsClusterCulled = 0;
2019
2020         Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2021         RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2022         Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2023
2024         StitchSurfaceLightmaps();
2025
2026         Sys_Printf( "--- IlluminateVertexes ---\n" );
2027         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2028         Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2029
2030         /* ydnar: emit statistics on light culling */
2031         Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2032         Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2033         Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2034         Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2035
2036         /* radiosity */
2037         b = 1;
2038         bt = bounce;
2039
2040         while ( bounce > 0 )
2041         {
2042                 qboolean storeForReal = !noBounceStore;
2043
2044                 /* store off the bsp between bounces */
2045                 StoreSurfaceLightmaps( fastAllocate, storeForReal );
2046                 UnparseEntities();
2047
2048                 if ( storeForReal ) {
2049                 Sys_Printf( "Writing %s\n", BSPFilePath );
2050                 WriteBSPFile( BSPFilePath );
2051                 }
2052
2053                 /* note it */
2054                 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
2055
2056                 /* flag bouncing */
2057                 bouncing = qtrue;
2058                 VectorClear( ambientColor );
2059                 floodlighty = qfalse;
2060
2061                 /* generate diffuse lights */
2062                 RadFreeLights();
2063                 RadCreateDiffuseLights();
2064
2065                 /* setup light envelopes */
2066                 SetupEnvelopes( qfalse, fastbounce );
2067                 if ( numLights == 0 ) {
2068                         Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
2069                         if ( noBounceStore ) {
2070                                 break;
2071                         }
2072                         return;
2073                 }
2074
2075                 /* add to lightgrid */
2076                 if ( bouncegrid ) {
2077                         gridEnvelopeCulled = 0;
2078                         gridBoundsCulled = 0;
2079
2080                         Sys_Printf( "--- BounceGrid ---\n" );
2081                         inGrid = qtrue;
2082                         RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2083                         inGrid = qfalse;
2084                         Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2085                         Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2086                 }
2087
2088                 /* light up my world */
2089                 lightsPlaneCulled = 0;
2090                 lightsEnvelopeCulled = 0;
2091                 lightsBoundsCulled = 0;
2092                 lightsClusterCulled = 0;
2093
2094                 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2095                 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2096                 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2097                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2098
2099                 StitchSurfaceLightmaps();
2100
2101                 Sys_Printf( "--- IlluminateVertexes ---\n" );
2102                 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2103                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2104
2105                 /* ydnar: emit statistics on light culling */
2106                 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2107                 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2108                 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2109                 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2110
2111                 /* interate */
2112                 bounce--;
2113                 b++;
2114         }
2115
2116         /* ydnar: store off lightmaps */
2117         StoreSurfaceLightmaps( fastAllocate, qtrue );
2118 }
2119
2120
2121
2122 /*
2123    LoadSurfaceFlags()
2124    added by spoon to get back the changed surfaceflags
2125    from tex file
2126 */
2127
2128 void LoadSurfaceFlags( char *filename ) {
2129         int i;
2130
2131         for( i = 0; i < numBSPShaders; i++ ) {
2132                 shaderInfo_t *si;
2133
2134                 si = ShaderInfoForShader( bspShaders[i].shader );
2135
2136                 bspShaders[ i ].surfaceFlags = si->surfaceFlags;
2137         }
2138 }
2139
2140
2141
2142 /*
2143    LightMain()
2144    main routine for light processing
2145  */
2146
2147 int LightMain( int argc, char **argv ){
2148         int i;
2149         float f;
2150         char BSPFilePath[ 1024 ];
2151         char surfaceFilePath[ 1024 ];
2152         BSPFilePath[0] = 0;
2153         surfaceFilePath[0] = 0;
2154         const char  *value;
2155         int lightmapMergeSize = 0;
2156         qboolean lightSamplesInsist = qfalse;
2157         qboolean fastAllocate = qtrue;
2158         qboolean noBounceStore = qfalse;
2159
2160         /* note it */
2161         Sys_Printf( "--- Light ---\n" );
2162         Sys_Printf( "--- ProcessGameSpecific ---\n" );
2163
2164         /* set standard game flags */
2165         wolfLight = game->wolfLight;
2166         if ( wolfLight == qtrue ) {
2167                 Sys_Printf( " lightning model: wolf\n" );
2168         }
2169         else{
2170                 Sys_Printf( " lightning model: quake3\n" );
2171         }
2172
2173         lmCustomSize = game->lightmapSize;
2174         Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2175
2176         lightmapGamma = game->lightmapGamma;
2177         Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2178
2179         lightmapsRGB = game->lightmapsRGB;
2180         if ( lightmapsRGB ) {
2181                 Sys_Printf( " lightmap colorspace: sRGB\n" );
2182         }
2183         else{
2184                 Sys_Printf( " lightmap colorspace: linear\n" );
2185         }
2186
2187         texturesRGB = game->texturesRGB;
2188         if ( texturesRGB ) {
2189                 Sys_Printf( " texture colorspace: sRGB\n" );
2190         }
2191         else{
2192                 Sys_Printf( " texture colorspace: linear\n" );
2193         }
2194
2195         colorsRGB = game->colorsRGB;
2196         if ( colorsRGB ) {
2197                 Sys_Printf( " _color colorspace: sRGB\n" );
2198         }
2199         else{
2200                 Sys_Printf( " _color colorspace: linear\n" );
2201         }
2202
2203         lightmapCompensate = game->lightmapCompensate;
2204         Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2205
2206         lightmapExposure = game->lightmapExposure;
2207         Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2208
2209         gridScale = game->gridScale;
2210         Sys_Printf( " lightgrid scale: %f\n", gridScale );
2211
2212         gridAmbientScale = game->gridAmbientScale;
2213         Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2214
2215         lightAngleHL = game->lightAngleHL;
2216         if ( lightAngleHL ) {
2217                 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2218         }
2219
2220         noStyles = game->noStyles;
2221         if ( noStyles == qtrue ) {
2222                 Sys_Printf( " shader lightstyles hack: disabled\n" );
2223         }
2224         else{
2225                 Sys_Printf( " shader lightstyles hack: enabled\n" );
2226         }
2227
2228         patchShadows = game->patchShadows;
2229         if ( patchShadows == qtrue ) {
2230                 Sys_Printf( " patch shadows: enabled\n" );
2231         }
2232         else{
2233                 Sys_Printf( " patch shadows: disabled\n" );
2234         }
2235
2236         deluxemap = game->deluxeMap;
2237         deluxemode = game->deluxeMode;
2238         if ( deluxemap == qtrue ) {
2239                 if ( deluxemode ) {
2240                         Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2241                 }
2242                 else{
2243                         Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2244                 }
2245         }
2246         else{
2247                 Sys_Printf( " deluxemapping: disabled\n" );
2248         }
2249
2250         Sys_Printf( "--- ProcessCommandLine ---\n" );
2251
2252         /* process commandline arguments */
2253         for ( i = 1; i < ( argc - 1 ); i++ )
2254         {
2255                 /* lightsource scaling */
2256                 if ( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) ) {
2257                         f = atof( argv[ i + 1 ] );
2258                         pointScale *= f;
2259                         spotScale *= f;
2260                         Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2261                         Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2262                         i++;
2263                 }
2264
2265                 else if ( !strcmp( argv[ i ], "-spherical" ) || !strcmp( argv[ i ], "-sphericalscale" ) ) {
2266                         f = atof( argv[ i + 1 ] );
2267                         pointScale *= f;
2268                         Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2269                         i++;
2270                 }
2271
2272                 else if ( !strcmp( argv[ i ], "-spot" ) || !strcmp( argv[ i ], "-spotscale" ) ) {
2273                         f = atof( argv[ i + 1 ] );
2274                         spotScale *= f;
2275                         Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2276                         i++;
2277                 }
2278
2279                 else if ( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) ) {
2280                         f = atof( argv[ i + 1 ] );
2281                         areaScale *= f;
2282                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2283                         i++;
2284                 }
2285
2286                 else if ( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) ) {
2287                         f = atof( argv[ i + 1 ] );
2288                         skyScale *= f;
2289                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2290                         i++;
2291                 }
2292
2293                 else if ( !strcmp( argv[ i ], "-vertexscale" ) ) {
2294                         f = atof( argv[ i + 1 ] );
2295                         vertexglobalscale *= f;
2296                         Sys_Printf( "Vertexlight scaled by %f to %f\n", f, vertexglobalscale );
2297                         i++;
2298                 }
2299
2300                 else if ( !strcmp( argv[ i ], "-backsplash" ) && i < ( argc - 3 ) ) {
2301                         f = atof( argv[ i + 1 ] );
2302                         g_backsplashFractionScale = f;
2303                         Sys_Printf( "Area lights backsplash fraction scaled by %f\n", f, g_backsplashFractionScale );
2304                         f = atof( argv[ i + 2 ] );
2305                         if ( f >= -900.0f ){
2306                                 g_backsplashDistance = f;
2307                                 Sys_Printf( "Area lights backsplash distance set globally to %f\n", f, g_backsplashDistance );
2308                         }
2309                         i+=2;
2310                 }
2311
2312                 else if ( !strcmp( argv[ i ], "-nolm" ) ) {
2313                         nolm = qtrue;
2314                         Sys_Printf( "No lightmaps yo\n" );
2315                 }
2316
2317                 else if ( !strcmp( argv[ i ], "-bouncecolorratio" ) ) {
2318                         f = atof( argv[ i + 1 ] );
2319                         bounceColorRatio *= f;
2320                         if ( bounceColorRatio > 1 ) {
2321                                 bounceColorRatio = 1;
2322                         }
2323                         if ( bounceColorRatio < 0 ) {
2324                                 bounceColorRatio = 0;
2325                         }
2326                         Sys_Printf( "Bounce color ratio set to %f\n", bounceColorRatio );
2327                         i++;
2328                 }
2329
2330                 else if ( !strcmp( argv[ i ], "-bouncescale" ) ) {
2331                         f = atof( argv[ i + 1 ] );
2332                         bounceScale *= f;
2333                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2334                         i++;
2335                 }
2336
2337                 else if ( !strcmp( argv[ i ], "-scale" ) ) {
2338                         f = atof( argv[ i + 1 ] );
2339                         pointScale *= f;
2340                         spotScale *= f;
2341                         areaScale *= f;
2342                         skyScale *= f;
2343                         bounceScale *= f;
2344                         Sys_Printf( "All light scaled by %f\n", f );
2345                         i++;
2346                 }
2347
2348                 else if ( !strcmp( argv[ i ], "-gridscale" ) ) {
2349                         f = atof( argv[ i + 1 ] );
2350                         Sys_Printf( "Grid lightning scaled by %f\n", f );
2351                         gridScale *= f;
2352                         i++;
2353                 }
2354
2355                 else if ( !strcmp( argv[ i ], "-gridambientscale" ) ) {
2356                         f = atof( argv[ i + 1 ] );
2357                         Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2358                         gridAmbientScale *= f;
2359                         i++;
2360                 }
2361
2362                 else if ( !strcmp( argv[ i ], "-griddirectionality" ) ) {
2363                         f = atof( argv[ i + 1 ] );
2364                         if ( f > 1 ) {
2365                                 f = 1;
2366                         }
2367                         if ( f < gridAmbientDirectionality ) {
2368                                 gridAmbientDirectionality = f;
2369                         }
2370                         Sys_Printf( "Grid directionality is %f\n", f );
2371                         gridDirectionality = f;
2372                         i++;
2373                 }
2374
2375                 else if ( !strcmp( argv[ i ], "-gridambientdirectionality" ) ) {
2376                         f = atof( argv[ i + 1 ] );
2377                         if ( f < -1 ) {
2378                                 f = -1;
2379                         }
2380                         if ( f > gridDirectionality ) {
2381                                 gridDirectionality = f;
2382                         }
2383                         Sys_Printf( "Grid ambient directionality is %f\n", f );
2384                         gridAmbientDirectionality = f;
2385                         i++;
2386                 }
2387
2388                 else if ( !strcmp( argv[ i ], "-gamma" ) ) {
2389                         f = atof( argv[ i + 1 ] );
2390                         lightmapGamma = f;
2391                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2392                         i++;
2393                 }
2394
2395                 else if ( !strcmp( argv[ i ], "-sRGBlight" ) ) {
2396                         lightmapsRGB = qtrue;
2397                         Sys_Printf( "Lighting is in sRGB\n" );
2398                 }
2399
2400                 else if ( !strcmp( argv[ i ], "-nosRGBlight" ) ) {
2401                         lightmapsRGB = qfalse;
2402                         Sys_Printf( "Lighting is linear\n" );
2403                 }
2404
2405                 else if ( !strcmp( argv[ i ], "-sRGBtex" ) ) {
2406                         texturesRGB = qtrue;
2407                         Sys_Printf( "Textures are in sRGB\n" );
2408                 }
2409
2410                 else if ( !strcmp( argv[ i ], "-nosRGBtex" ) ) {
2411                         texturesRGB = qfalse;
2412                         Sys_Printf( "Textures are linear\n" );
2413                 }
2414
2415                 else if ( !strcmp( argv[ i ], "-sRGBcolor" ) ) {
2416                         colorsRGB = qtrue;
2417                         Sys_Printf( "Colors are in sRGB\n" );
2418                 }
2419
2420                 else if ( !strcmp( argv[ i ], "-nosRGBcolor" ) ) {
2421                         colorsRGB = qfalse;
2422                         Sys_Printf( "Colors are linear\n" );
2423                 }
2424
2425                 else if ( !strcmp( argv[ i ], "-sRGB" ) ) {
2426                         lightmapsRGB = qtrue;
2427                         Sys_Printf( "Lighting is in sRGB\n" );
2428                         texturesRGB = qtrue;
2429                         Sys_Printf( "Textures are in sRGB\n" );
2430                         colorsRGB = qtrue;
2431                         Sys_Printf( "Colors are in sRGB\n" );
2432                 }
2433
2434                 else if ( !strcmp( argv[ i ], "-nosRGB" ) ) {
2435                         lightmapsRGB = qfalse;
2436                         Sys_Printf( "Lighting is linear\n" );
2437                         texturesRGB = qfalse;
2438                         Sys_Printf( "Textures are linear\n" );
2439                         colorsRGB = qfalse;
2440                         Sys_Printf( "Colors are linear\n" );
2441                 }
2442
2443                 else if ( !strcmp( argv[ i ], "-exposure" ) ) {
2444                         f = atof( argv[ i + 1 ] );
2445                         lightmapExposure = f;
2446                         Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2447                         i++;
2448                 }
2449
2450                 else if ( !strcmp( argv[ i ], "-compensate" ) ) {
2451                         f = atof( argv[ i + 1 ] );
2452                         if ( f <= 0.0f ) {
2453                                 f = 1.0f;
2454                         }
2455                         lightmapCompensate = f;
2456                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2457                         i++;
2458                 }
2459
2460                 /* Lighting brightness */
2461                 else if( !strcmp( argv[ i ], "-brightness" ) ){
2462                         f = atof( argv[ i + 1 ] );
2463                         lightmapBrightness = f;
2464                         Sys_Printf( "Lighting brightness set to %f\n", lightmapBrightness );
2465                         i++;
2466                 }
2467
2468                 /* Lighting contrast */
2469                 else if( !strcmp( argv[ i ], "-contrast" ) ){
2470                         f = atof( argv[ i + 1 ] );
2471                         lightmapContrast = f;
2472                         if( lightmapContrast > 255 ){
2473                                 lightmapContrast = 255;
2474                         }
2475                         else if( lightmapContrast < -255 ){
2476                                 lightmapContrast = -255;
2477                         }
2478                         Sys_Printf( "Lighting contrast set to %f\n", lightmapContrast );
2479                         i++;
2480                         /* change to factor in range of 0 to 129.5 */
2481                         lightmapContrast = ( 259 * ( lightmapContrast + 255 ) ) / ( 255 * ( 259 - lightmapContrast ) );
2482                 }
2483
2484                 /* ydnar switches */
2485                 else if ( !strcmp( argv[ i ], "-bounce" ) ) {
2486                         bounce = atoi( argv[ i + 1 ] );
2487                         if ( bounce < 0 ) {
2488                                 bounce = 0;
2489                         }
2490                         else if ( bounce > 0 ) {
2491                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2492                         }
2493                         i++;
2494                 }
2495
2496                 else if ( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) ) {
2497                         superSample = atoi( argv[ i + 1 ] );
2498                         if ( superSample < 1 ) {
2499                                 superSample = 1;
2500                         }
2501                         else if ( superSample > 1 ) {
2502                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", ( superSample * superSample ) );
2503                         }
2504                         i++;
2505                 }
2506
2507                 else if ( !strcmp( argv[ i ], "-randomsamples" ) ) {
2508                         lightRandomSamples = qtrue;
2509                         Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2510                 }
2511
2512                 else if ( !strcmp( argv[ i ], "-samples" ) ) {
2513                         if ( *argv[i + 1] == '+' ) {
2514                                 lightSamplesInsist = qtrue;
2515                         }
2516                         else{
2517                                 lightSamplesInsist = qfalse;
2518                         }
2519                         lightSamples = atoi( argv[ i + 1 ] );
2520                         if ( lightSamples < 1 ) {
2521                                 lightSamples = 1;
2522                         }
2523                         else if ( lightSamples > 1 ) {
2524                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2525                         }
2526                         i++;
2527                 }
2528
2529                 else if ( !strcmp( argv[ i ], "-samplessearchboxsize" ) ) {
2530                         lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2531                         if ( lightSamplesSearchBoxSize <= 0 ) {
2532                                 lightSamplesSearchBoxSize = 1;
2533                         }
2534                         if ( lightSamplesSearchBoxSize > 4 ) {
2535                                 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2536                         }
2537                         else if ( lightSamplesSearchBoxSize != 1 ) {
2538                                 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2539                         }
2540                         i++;
2541                 }
2542
2543                 else if ( !strcmp( argv[ i ], "-filter" ) ) {
2544                         filter = qtrue;
2545                         Sys_Printf( "Lightmap filtering enabled\n" );
2546                 }
2547
2548                 else if ( !strcmp( argv[ i ], "-dark" ) ) {
2549                         dark = qtrue;
2550                         Sys_Printf( "Dark lightmap seams enabled\n" );
2551                 }
2552
2553                 else if ( !strcmp( argv[ i ], "-shadeangle" ) ) {
2554                         shadeAngleDegrees = atof( argv[ i + 1 ] );
2555                         if ( shadeAngleDegrees < 0.0f ) {
2556                                 shadeAngleDegrees = 0.0f;
2557                         }
2558                         else if ( shadeAngleDegrees > 0.0f ) {
2559                                 shade = qtrue;
2560                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2561                         }
2562                         i++;
2563                 }
2564
2565                 else if ( !strcmp( argv[ i ], "-thresh" ) ) {
2566                         subdivideThreshold = atof( argv[ i + 1 ] );
2567                         if ( subdivideThreshold < 0 ) {
2568                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2569                         }
2570                         else{
2571                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2572                         }
2573                         i++;
2574                 }
2575
2576                 else if ( !strcmp( argv[ i ], "-approx" ) ) {
2577                         approximateTolerance = atoi( argv[ i + 1 ] );
2578                         if ( approximateTolerance < 0 ) {
2579                                 approximateTolerance = 0;
2580                         }
2581                         else if ( approximateTolerance > 0 ) {
2582                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2583                         }
2584                         i++;
2585                 }
2586
2587                 else if ( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) ) {
2588                         deluxemap = qtrue;
2589                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
2590                 }
2591                 else if ( !strcmp( argv[ i ], "-deluxemode" ) ) {
2592                         deluxemode = atoi( argv[ i + 1 ] );
2593                         if ( deluxemode == 0 || deluxemode > 1 || deluxemode < 0 ) {
2594                                 Sys_Printf( "Generating modelspace deluxemaps\n" );
2595                                 deluxemode = 0;
2596                         }
2597                         else{
2598                                 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2599                         }
2600                         i++;
2601                 }
2602                 else if ( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) ) {
2603                         deluxemap = qfalse;
2604                         Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2605                 }
2606                 else if ( !strcmp( argv[ i ], "-external" ) ) {
2607                         externalLightmaps = qtrue;
2608                         Sys_Printf( "Storing all lightmaps externally\n" );
2609                 }
2610
2611                 else if ( !strcmp( argv[ i ], "-externalnames" ) ) {
2612                         externalLightmaps = qtrue;
2613                         externalLightmapNames = qtrue;
2614                         Sys_Printf( "Writing lightstyle shader using external lightmap names\n" );
2615                 }
2616
2617                 else if ( !strcmp( argv[ i ], "-lightmapsize" ) ) {
2618                         lmCustomSize = atoi( argv[ i + 1 ] );
2619
2620                         /* must be a power of 2 and greater than 2 */
2621                         if ( ( ( lmCustomSize - 1 ) & lmCustomSize ) || lmCustomSize < 2 ) {
2622                                 Sys_FPrintf( SYS_WRN, "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2623                                 lmCustomSize = game->lightmapSize;
2624                         }
2625                         i++;
2626                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2627
2628                         /* enable external lightmaps */
2629                         if ( lmCustomSize != game->lightmapSize ) {
2630                                 externalLightmaps = qtrue;
2631                                 Sys_Printf( "Storing all lightmaps externally\n" );
2632                         }
2633                 }
2634
2635                 else if ( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) ) {
2636                         lmLimitSize = atoi( argv[ i + 1 ] );
2637
2638                         i++;
2639                         Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2640                 }
2641
2642                 else if ( !strcmp( argv[ i ], "-lightmapdir" ) ) {
2643                         lmCustomDir = argv[i + 1];
2644                         argv[ i ] = NULL;
2645                         i++;
2646                         argv[ i ] = NULL;
2647                         Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2648                         externalLightmaps = qtrue;
2649                         Sys_Printf( "Storing all lightmaps externally\n" );
2650                 }
2651
2652                 /* ydnar: add this to suppress warnings */
2653                 else if ( !strcmp( argv[ i ],  "-custinfoparms" ) ) {
2654                         Sys_Printf( "Custom info parms enabled\n" );
2655                         useCustomInfoParms = qtrue;
2656                 }
2657
2658                 else if ( !strcmp( argv[ i ], "-wolf" ) ) {
2659                         /* -game should already be set */
2660                         wolfLight = qtrue;
2661                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2662                 }
2663
2664                 else if ( !strcmp( argv[ i ], "-q3" ) ) {
2665                         /* -game should already be set */
2666                         wolfLight = qfalse;
2667                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2668                 }
2669
2670                 else if ( !strcmp( argv[ i ], "-extradist" ) ) {
2671                         extraDist = atof( argv[ i + 1 ] );
2672                         if ( extraDist < 0 ) {
2673                                 extraDist = 0;
2674                         }
2675                         i++;
2676                         Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2677                 }
2678
2679                 else if ( !strcmp( argv[ i ], "-sunonly" ) ) {
2680                         sunOnly = qtrue;
2681                         Sys_Printf( "Only computing sunlight\n" );
2682                 }
2683
2684                 else if ( !strcmp( argv[ i ], "-bounceonly" ) ) {
2685                         bounceOnly = qtrue;
2686                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2687                 }
2688
2689                 else if ( !strcmp( argv[ i ], "-nobouncestore" ) ) {
2690                         noBounceStore = qtrue;
2691                         Sys_Printf( "Do not store BSP, lightmap and shader files between bounces\n" );
2692                 }
2693
2694                 else if ( !strcmp( argv[ i ], "-nocollapse" ) ) {
2695                         noCollapse = qtrue;
2696                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2697                 }
2698
2699                 else if ( !strcmp( argv[ i ], "-nolightmapsearch" ) ) {
2700                         lightmapSearchBlockSize = 1;
2701                         Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2702                 }
2703
2704                 else if ( !strcmp( argv[ i ], "-lightmapsearchpower" ) ) {
2705                         lightmapMergeSize = ( game->lightmapSize << atoi( argv[i + 1] ) );
2706                         ++i;
2707                         Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi( argv[i] ), lightmapMergeSize );
2708                 }
2709
2710                 else if ( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) ) {
2711                         lightmapSearchBlockSize = atoi( argv[i + 1] );
2712                         ++i;
2713                         Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2714                 }
2715
2716                 else if ( !strcmp( argv[ i ], "-shade" ) ) {
2717                         shade = qtrue;
2718                         Sys_Printf( "Phong shading enabled\n" );
2719                 }
2720
2721                 else if ( !strcmp( argv[ i ], "-bouncegrid" ) ) {
2722                         bouncegrid = qtrue;
2723                         if ( bounce > 0 ) {
2724                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2725                         }
2726                 }
2727
2728                 else if ( !strcmp( argv[ i ], "-smooth" ) ) {
2729                         lightSamples = EXTRA_SCALE;
2730                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2731                 }
2732
2733                 else if ( !strcmp( argv[ i ], "-nofastpoint" ) ) {
2734                         fastpoint = qfalse;
2735                         Sys_Printf( "Automatic fast mode for point lights disabled\n" );
2736                 }
2737
2738                 else if ( !strcmp( argv[ i ], "-fast" ) ) {
2739                         fast = qtrue;
2740                         fastgrid = qtrue;
2741                         fastbounce = qtrue;
2742                         Sys_Printf( "Fast mode enabled for all area lights\n" );
2743                 }
2744
2745                 else if ( !strcmp( argv[ i ], "-faster" ) ) {
2746                         faster = qtrue;
2747                         fast = qtrue;
2748                         fastgrid = qtrue;
2749                         fastbounce = qtrue;
2750                         Sys_Printf( "Faster mode enabled\n" );
2751                 }
2752
2753                 else if ( !strcmp( argv[ i ], "-fastallocate" ) || !strcmp( argv[ i ], "-fastlightmapsearch" ) ) {
2754                         fastAllocate = qtrue;
2755
2756                         if ( !strcmp( argv[ i ], "-fastlightmapsearch" ) ) {
2757                                 Sys_Printf( "The -fastlightmapsearch argument is deprecated, use \"-fastallocate\" instead\n" );
2758                         }
2759                         else {
2760                                 Sys_Printf( "Fast lightmap allocation mode enabled\n" );
2761                         }
2762                 }
2763
2764                 else if ( !strcmp( argv[ i ], "-slowallocate" ) ) {
2765                         fastAllocate = qfalse;
2766                         Sys_Printf( "Slow lightmap allocation mode enabled (default)\n" );
2767                 }
2768
2769                 else if ( !strcmp( argv[ i ], "-slowallocate" ) ) {
2770                         fastAllocate = qfalse;
2771                         Sys_Printf( "Slow allocation mode enabled\n" );
2772                 }
2773
2774                 else if ( !strcmp( argv[ i ], "-fastgrid" ) ) {
2775                         fastgrid = qtrue;
2776                         Sys_Printf( "Fast grid lighting enabled\n" );
2777                 }
2778
2779                 else if ( !strcmp( argv[ i ], "-fastbounce" ) ) {
2780                         fastbounce = qtrue;
2781                         Sys_Printf( "Fast bounce mode enabled\n" );
2782                 }
2783
2784                 else if ( !strcmp( argv[ i ], "-cheap" ) ) {
2785                         cheap = qtrue;
2786                         cheapgrid = qtrue;
2787                         Sys_Printf( "Cheap mode enabled\n" );
2788                 }
2789
2790                 else if ( !strcmp( argv[ i ], "-cheapgrid" ) ) {
2791                         cheapgrid = qtrue;
2792                         Sys_Printf( "Cheap grid mode enabled\n" );
2793                 }
2794
2795                 else if ( !strcmp( argv[ i ], "-normalmap" ) ) {
2796                         normalmap = qtrue;
2797                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2798                 }
2799
2800                 else if ( !strcmp( argv[ i ], "-trisoup" ) ) {
2801                         trisoup = qtrue;
2802                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2803                 }
2804
2805                 else if ( !strcmp( argv[ i ], "-debug" ) ) {
2806                         debug = qtrue;
2807                         Sys_Printf( "Lightmap debugging enabled\n" );
2808                 }
2809
2810                 else if ( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) ) {
2811                         debugSurfaces = qtrue;
2812                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2813                 }
2814
2815                 else if ( !strcmp( argv[ i ], "-debugunused" ) ) {
2816                         debugUnused = qtrue;
2817                         Sys_Printf( "Unused luxel debugging enabled\n" );
2818                 }
2819
2820                 else if ( !strcmp( argv[ i ], "-debugaxis" ) ) {
2821                         debugAxis = qtrue;
2822                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2823                 }
2824
2825                 else if ( !strcmp( argv[ i ], "-debugcluster" ) ) {
2826                         debugCluster = qtrue;
2827                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2828                 }
2829
2830                 else if ( !strcmp( argv[ i ], "-debugorigin" ) ) {
2831                         debugOrigin = qtrue;
2832                         Sys_Printf( "Luxel origin debugging enabled\n" );
2833                 }
2834
2835                 else if ( !strcmp( argv[ i ], "-debugdeluxe" ) ) {
2836                         deluxemap = qtrue;
2837                         debugDeluxemap = qtrue;
2838                         Sys_Printf( "Deluxemap debugging enabled\n" );
2839                 }
2840
2841                 else if ( !strcmp( argv[ i ], "-export" ) ) {
2842                         exportLightmaps = qtrue;
2843                         Sys_Printf( "Exporting lightmaps\n" );
2844                 }
2845
2846                 else if ( !strcmp( argv[ i ], "-notrace" ) ) {
2847                         noTrace = qtrue;
2848                         Sys_Printf( "Shadow occlusion disabled\n" );
2849                 }
2850                 else if ( !strcmp( argv[ i ], "-patchshadows" ) ) {
2851                         patchShadows = qtrue;
2852                         Sys_Printf( "Patch shadow casting enabled\n" );
2853                 }
2854                 else if ( !strcmp( argv[ i ], "-extra" ) ) {
2855                         superSample = EXTRA_SCALE;      /* ydnar */
2856                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2857                 }
2858                 else if ( !strcmp( argv[ i ], "-extrawide" ) ) {
2859                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2860                         filter = qtrue;                 /* ydnar */
2861                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n" );
2862                 }
2863                 else if ( !strcmp( argv[ i ], "-samplesize" ) ) {
2864                         sampleSize = atoi( argv[ i + 1 ] );
2865                         if ( sampleSize < 1 ) {
2866                                 sampleSize = 1;
2867                         }
2868                         i++;
2869                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2870                 }
2871                 else if ( !strcmp( argv[ i ], "-minsamplesize" ) ) {
2872                         minSampleSize = atoi( argv[ i + 1 ] );
2873                         if ( minSampleSize < 1 ) {
2874                                 minSampleSize = 1;
2875                         }
2876                         i++;
2877                         Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2878                 }
2879                 else if ( !strcmp( argv[ i ],  "-samplescale" ) ) {
2880                         sampleScale = atoi( argv[ i + 1 ] );
2881                         i++;
2882                         Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale );
2883                 }
2884                 else if ( !strcmp( argv[ i ],  "-debugsamplesize" ) ) {
2885                         debugSampleSize = 1;
2886                         Sys_Printf( "debugging Lightmaps SampleSize\n" );
2887                 }
2888                 else if ( !strcmp( argv[ i ], "-novertex" ) ) {
2889                         noVertexLighting = 1;
2890                         if ( ( atof( argv[ i + 1 ] ) != 0 ) && ( atof( argv[ i + 1 ] )) < 1 ) {
2891                                 noVertexLighting = ( atof( argv[ i + 1 ] ) );
2892                                 i++;
2893                                 Sys_Printf( "Setting vertex lighting globally to %f\n", noVertexLighting );
2894                         }
2895                         else{
2896                                 Sys_Printf( "Disabling vertex lighting\n" );
2897                         }
2898                 }
2899                 else if ( !strcmp( argv[ i ], "-nogrid" ) ) {
2900                         noGridLighting = qtrue;
2901                         Sys_Printf( "Disabling grid lighting\n" );
2902                 }
2903                 else if ( !strcmp( argv[ i ], "-border" ) ) {
2904                         lightmapBorder = qtrue;
2905                         Sys_Printf( "Adding debug border to lightmaps\n" );
2906                 }
2907                 else if ( !strcmp( argv[ i ], "-nosurf" ) ) {
2908                         noSurfaces = qtrue;
2909                         Sys_Printf( "Not tracing against surfaces\n" );
2910                 }
2911                 else if ( !strcmp( argv[ i ], "-dump" ) ) {
2912                         dump = qtrue;
2913                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2914                 }
2915                 else if ( !strcmp( argv[ i ], "-lomem" ) ) {
2916                         loMem = qtrue;
2917                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2918                 }
2919                 else if ( !strcmp( argv[ i ], "-lightsubdiv" ) ) {
2920                         defaultLightSubdivide = atoi( argv[ i + 1 ] );
2921                         if ( defaultLightSubdivide < 1 ) {
2922                                 defaultLightSubdivide = 1;
2923                         }
2924                         i++;
2925                         Sys_Printf( "Default light subdivision set to %d\n", defaultLightSubdivide );
2926                 }
2927                 else if ( !strcmp( argv[ i ], "-lightanglehl" ) ) {
2928                         if ( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL ) {
2929                                 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2930                                 if ( lightAngleHL ) {
2931                                         Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2932                                 }
2933                                 else{
2934                                         Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2935                                 }
2936                                 i++;
2937                         }
2938                 }
2939                 else if ( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) ) {
2940                         noStyles = qtrue;
2941                         Sys_Printf( "Disabling lightstyles\n" );
2942                 }
2943                 else if ( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) ) {
2944                         noStyles = qfalse;
2945                         Sys_Printf( "Enabling lightstyles\n" );
2946                 }
2947                 else if ( !strcmp( argv[ i ], "-cpma" ) ) {
2948                         cpmaHack = qtrue;
2949                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2950                 }
2951                 else if ( !strcmp( argv[ i ], "-floodlight" ) ) {
2952                         floodlighty = qtrue;
2953                         Sys_Printf( "FloodLighting enabled\n" );
2954                 }
2955                 else if ( !strcmp( argv[ i ], "-debugnormals" ) ) {
2956                         debugnormals = qtrue;
2957                         Sys_Printf( "DebugNormals enabled\n" );
2958                 }
2959                 else if ( !strcmp( argv[ i ], "-lowquality" ) ) {
2960                         floodlight_lowquality = qtrue;
2961                         Sys_Printf( "Low Quality FloodLighting enabled\n" );
2962                 }
2963
2964                 /* r7: dirtmapping */
2965                 else if ( !strcmp( argv[ i ], "-dirty" ) ) {
2966                         dirty = qtrue;
2967                         Sys_Printf( "Dirtmapping enabled\n" );
2968                 }
2969                 else if ( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) ) {
2970                         dirtDebug = qtrue;
2971                         Sys_Printf( "Dirtmap debugging enabled\n" );
2972                 }
2973                 else if ( !strcmp( argv[ i ], "-dirtmode" ) ) {
2974                         dirtMode = atoi( argv[ i + 1 ] );
2975                         if ( dirtMode != 0 && dirtMode != 1 ) {
2976                                 dirtMode = 0;
2977                         }
2978                         if ( dirtMode == 1 ) {
2979                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2980                         }
2981                         else{
2982                                 Sys_Printf( "Enabling ordered dirtmapping\n" );
2983                         }
2984                         i++;
2985                 }
2986                 else if ( !strcmp( argv[ i ], "-dirtdepth" ) ) {
2987                         dirtDepth = atof( argv[ i + 1 ] );
2988                         if ( dirtDepth <= 0.0f ) {
2989                                 dirtDepth = 128.0f;
2990                         }
2991                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2992                         i++;
2993                 }
2994                 else if ( !strcmp( argv[ i ], "-dirtscale" ) ) {
2995                         dirtScale = atof( argv[ i + 1 ] );
2996                         if ( dirtScale <= 0.0f ) {
2997                                 dirtScale = 1.0f;
2998                         }
2999                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
3000                         i++;
3001                 }
3002                 else if ( !strcmp( argv[ i ], "-dirtgain" ) ) {
3003                         dirtGain = atof( argv[ i + 1 ] );
3004                         if ( dirtGain <= 0.0f ) {
3005                                 dirtGain = 1.0f;
3006                         }
3007                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
3008                         i++;
3009                 }
3010                 else if ( !strcmp( argv[ i ], "-trianglecheck" ) ) {
3011                         lightmapTriangleCheck = qtrue;
3012                 }
3013                 else if ( !strcmp( argv[ i ], "-extravisnudge" ) ) {
3014                         lightmapExtraVisClusterNudge = qtrue;
3015                 }
3016                 else if ( !strcmp( argv[ i ], "-fill" ) ) {
3017                         lightmapFill = qtrue;
3018                         Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
3019                 }
3020                 else if ( !strcmp( argv[ i ], "-bspfile" ) )
3021                 {
3022                         strcpy( BSPFilePath, argv[i + 1] );
3023                         argv[ i ] = NULL;
3024                         i++;
3025                         argv[ i ] = NULL;
3026                         Sys_Printf( "Use %s as bsp file\n", BSPFilePath );
3027                 }
3028                 else if ( !strcmp( argv[ i ], "-srffile" ) )
3029                 {
3030                         strcpy( surfaceFilePath, argv[i + 1] );
3031                         argv[ i ] = NULL;
3032                         i++;
3033                         argv[ i ] = NULL;
3034                         Sys_Printf( "Use %s as surface file\n", surfaceFilePath );
3035                 }
3036                 /* unhandled args */
3037                 else
3038                 {
3039                         Sys_FPrintf( SYS_WRN, "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
3040                 }
3041
3042         }
3043
3044         /* fix up falloff tolerance for sRGB */
3045         if ( lightmapsRGB ) {
3046                 falloffTolerance = Image_LinearFloatFromsRGBFloat( falloffTolerance * ( 1.0 / 255.0 ) ) * 255.0;
3047         }
3048
3049         /* fix up samples count */
3050         if ( lightRandomSamples ) {
3051                 if ( !lightSamplesInsist ) {
3052                         /* approximately match -samples in quality */
3053                         switch ( lightSamples )
3054                         {
3055                         /* somewhat okay */
3056                         case 1:
3057                         case 2:
3058                                 lightSamples = 16;
3059                                 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
3060                                 break;
3061
3062                         /* good */
3063                         case 3:
3064                                 lightSamples = 64;
3065                                 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
3066                                 break;
3067
3068                         /* perfect */
3069                         case 4:
3070                                 lightSamples = 256;
3071                                 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
3072                                 break;
3073
3074                         default: break;
3075                         }
3076                 }
3077         }
3078
3079         /* fix up lightmap search power */
3080         if ( lightmapMergeSize ) {
3081                 lightmapSearchBlockSize = ( lightmapMergeSize / lmCustomSize ) * ( lightmapMergeSize / lmCustomSize );
3082                 if ( lightmapSearchBlockSize < 1 ) {
3083                         lightmapSearchBlockSize = 1;
3084                 }
3085
3086                 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
3087         }
3088
3089         /* arg checking */
3090         if ( i != ( argc - 1 ) ) {
3091                 Error( "usage: q3map -light [options] <bspfile>" );
3092         }
3093
3094         strcpy( source, ExpandArg( argv[ i ] ) );
3095         StripExtension( source );
3096         DefaultExtension( source, ".map" );
3097
3098         if (!BSPFilePath[0]) {
3099                 strcpy( BSPFilePath, ExpandArg( argv[ i ] ) );
3100                 StripExtension( BSPFilePath );
3101                 DefaultExtension( BSPFilePath, ".bsp" );
3102         }
3103
3104         if (!surfaceFilePath[0]) {
3105                 strcpy( surfaceFilePath, ExpandArg( argv[ i ] ) );
3106                 StripExtension( surfaceFilePath );
3107                 DefaultExtension( surfaceFilePath, ".srf" );
3108         }
3109
3110         /* ydnar: set default sample size */
3111         SetDefaultSampleSize( sampleSize );
3112
3113         /* ydnar: handle shaders */
3114         BeginMapShaderFile( BSPFilePath );
3115         LoadShaderInfo();
3116
3117         /* note loading */
3118         Sys_Printf( "Loading %s\n", source );
3119
3120         /* ydnar: load surface file */
3121         LoadSurfaceExtraFile( surfaceFilePath );
3122
3123         /* load bsp file */
3124         LoadBSPFile( BSPFilePath );
3125
3126         /* parse bsp entities */
3127         ParseEntities();
3128
3129         /* inject command line parameters */
3130         InjectCommandLine( argv, 0, argc - 1 );
3131
3132         /* load map file */
3133         value = ValueForKey( &entities[ 0 ], "_keepLights" );
3134         if ( value[ 0 ] != '1' ) {
3135                 LoadMapFile( source, qtrue, qfalse );
3136         }
3137
3138         /* set the entity/model origins and init yDrawVerts */
3139         SetEntityOrigins();
3140
3141         /* ydnar: set up optimization */
3142         SetupBrushes();
3143         SetupDirt();
3144         SetupFloodLight();
3145         SetupSurfaceLightmaps();
3146
3147         /* initialize the surface facet tracing */
3148         SetupTraceNodes();
3149
3150         /* light the world */
3151         LightWorld( BSPFilePath, fastAllocate, noBounceStore );
3152
3153         /* write out the bsp */
3154         UnparseEntities();
3155         Sys_Printf( "Writing %s\n", BSPFilePath );
3156         WriteBSPFile( BSPFilePath );
3157
3158         /* ydnar: export lightmaps */
3159         if ( exportLightmaps && !externalLightmaps ) {
3160                 ExportLightmaps();
3161         }
3162
3163         /* return to sender */
3164         return 0;
3165 }