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