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