]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light.c
fix warning: unused variable 'foo'
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light.c
1 /* -------------------------------------------------------------------------------
2
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6    This file is part of GtkRadiant.
7
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22    ----------------------------------------------------------------------------------
23
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27    ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42    CreateSunLight() - ydnar
43    this creates a sun light
44  */
45
46 static void CreateSunLight( sun_t *sun ){
47         int i;
48         float photons, d, angle, elevation, da, de;
49         vec3_t direction;
50         light_t     *light;
51
52
53         /* dummy check */
54         if ( sun == NULL ) {
55                 return;
56         }
57
58         /* fixup */
59         if ( sun->numSamples < 1 ) {
60                 sun->numSamples = 1;
61         }
62
63         /* set photons */
64         photons = sun->photons / sun->numSamples;
65
66         /* create the right number of suns */
67         for ( i = 0; i < sun->numSamples; i++ )
68         {
69                 /* calculate sun direction */
70                 if ( i == 0 ) {
71                         VectorCopy( sun->direction, direction );
72                 }
73                 else
74                 {
75                         /*
76                             sun->direction[ 0 ] = cos( angle ) * cos( elevation );
77                             sun->direction[ 1 ] = sin( angle ) * cos( elevation );
78                             sun->direction[ 2 ] = sin( elevation );
79
80                             xz_dist   = sqrt( x*x + z*z )
81                             latitude  = atan2( xz_dist, y ) * RADIANS
82                             longitude = atan2( x,       z ) * RADIANS
83                          */
84
85                         d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
86                         angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
87                         elevation = atan2( sun->direction[ 2 ], d );
88
89                         /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
90                         do
91                         {
92                                 da = ( Random() * 2.0f - 1.0f ) * sun->deviance;
93                                 de = ( Random() * 2.0f - 1.0f ) * sun->deviance;
94                         }
95                         while ( ( da * da + de * de ) > ( sun->deviance * sun->deviance ) );
96                         angle += da;
97                         elevation += de;
98
99                         /* debug code */
100                         //%     Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
101
102                         /* create new vector */
103                         direction[ 0 ] = cos( angle ) * cos( elevation );
104                         direction[ 1 ] = sin( angle ) * cos( elevation );
105                         direction[ 2 ] = sin( elevation );
106                 }
107
108                 /* create a light */
109                 numSunLights++;
110                 light = safe_malloc( sizeof( *light ) );
111                 memset( light, 0, sizeof( *light ) );
112                 light->next = lights;
113                 lights = light;
114
115                 /* initialize the light */
116                 light->flags = LIGHT_SUN_DEFAULT;
117                 light->type = EMIT_SUN;
118                 light->fade = 1.0f;
119                 light->falloffTolerance = falloffTolerance;
120                 light->filterRadius = sun->filterRadius / sun->numSamples;
121                 light->style = noStyles ? LS_NORMAL : sun->style;
122
123                 /* set the light's position out to infinity */
124                 VectorMA( vec3_origin, ( MAX_WORLD_COORD * 8.0f ), direction, light->origin );    /* MAX_WORLD_COORD * 2.0f */
125
126                 /* set the facing to be the inverse of the sun direction */
127                 VectorScale( direction, -1.0, light->normal );
128                 light->dist = DotProduct( light->origin, light->normal );
129
130                 /* set color and photons */
131                 VectorCopy( sun->color, light->color );
132                 light->photons = photons * skyScale;
133         }
134
135         /* another sun? */
136         if ( sun->next != NULL ) {
137                 CreateSunLight( sun->next );
138         }
139 }
140
141
142
143 /*
144    CreateSkyLights() - ydnar
145    simulates sky light with multiple suns
146  */
147
148 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius, int style ){
149         int i, j, numSuns;
150         int angleSteps, elevationSteps;
151         float angle, elevation;
152         float angleStep, elevationStep;
153         float step, start;
154         sun_t sun;
155
156
157         /* dummy check */
158         if ( value <= 0.0f || iterations < 2 ) {
159                 return;
160         }
161
162         /* calculate some stuff */
163         step = 2.0f / ( iterations - 1 );
164         start = -1.0f;
165
166         /* basic sun setup */
167         VectorCopy( color, sun.color );
168         sun.deviance = 0.0f;
169         sun.filterRadius = filterRadius;
170         sun.numSamples = 1;
171         sun.style = noStyles ? LS_NORMAL : style;
172         sun.next = NULL;
173
174         /* setup */
175         elevationSteps = iterations - 1;
176         angleSteps = elevationSteps * 4;
177         angle = 0.0f;
178         elevationStep = DEG2RAD( 90.0f / iterations );  /* skip elevation 0 */
179         angleStep = DEG2RAD( 360.0f / angleSteps );
180
181         /* calc individual sun brightness */
182         numSuns = angleSteps * elevationSteps + 1;
183         sun.photons = value / numSuns;
184
185         /* iterate elevation */
186         elevation = elevationStep * 0.5f;
187         angle = 0.0f;
188         for ( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
189         {
190                 /* iterate angle */
191                 for ( j = 0; j < angleSteps; j++ )
192                 {
193                         /* create sun */
194                         sun.direction[ 0 ] = cos( angle ) * cos( elevation );
195                         sun.direction[ 1 ] = sin( angle ) * cos( elevation );
196                         sun.direction[ 2 ] = sin( elevation );
197                         CreateSunLight( &sun );
198
199                         /* move */
200                         angle += angleStep;
201                 }
202
203                 /* move */
204                 elevation += elevationStep;
205                 angle += angleStep / elevationSteps;
206         }
207
208         /* create vertical sun */
209         VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
210         CreateSunLight( &sun );
211
212         /* short circuit */
213         return;
214 }
215
216
217
218 /*
219    CreateEntityLights()
220    creates lights from light entities
221  */
222
223 void CreateEntityLights( void ){
224         int i, j;
225         light_t         *light, *light2;
226         entity_t        *e, *e2;
227         const char      *name;
228         const char      *target;
229         vec3_t dest;
230         const char      *_color;
231         float intensity, scale, deviance, filterRadius;
232         int spawnflags, flags, numSamples;
233         qboolean junior;
234
235
236         /* go throught entity list and find lights */
237         for ( i = 0; i < numEntities; i++ )
238         {
239                 /* get entity */
240                 e = &entities[ i ];
241                 name = ValueForKey( e, "classname" );
242
243                 /* ydnar: check for lightJunior */
244                 if ( Q_strncasecmp( name, "lightJunior", 11 ) == 0 ) {
245                         junior = qtrue;
246                 }
247                 else if ( Q_strncasecmp( name, "light", 5 ) == 0 ) {
248                         junior = qfalse;
249                 }
250                 else{
251                         continue;
252                 }
253
254                 /* lights with target names (and therefore styles) are only parsed from BSP */
255                 target = ValueForKey( e, "targetname" );
256                 if ( target[ 0 ] != '\0' && i >= numBSPEntities ) {
257                         continue;
258                 }
259
260                 /* create a light */
261                 numPointLights++;
262                 light = safe_malloc( sizeof( *light ) );
263                 memset( light, 0, sizeof( *light ) );
264                 light->next = lights;
265                 lights = light;
266
267                 /* handle spawnflags */
268                 spawnflags = IntForKey( e, "spawnflags" );
269
270                 /* ydnar: quake 3+ light behavior */
271                 if ( wolfLight == qfalse ) {
272                         /* set default flags */
273                         flags = LIGHT_Q3A_DEFAULT;
274
275                         /* linear attenuation? */
276                         if ( spawnflags & 1 ) {
277                                 flags |= LIGHT_ATTEN_LINEAR;
278                                 flags &= ~LIGHT_ATTEN_ANGLE;
279                         }
280
281                         /* no angle attenuate? */
282                         if ( spawnflags & 2 ) {
283                                 flags &= ~LIGHT_ATTEN_ANGLE;
284                         }
285                 }
286
287                 /* ydnar: wolf light behavior */
288                 else
289                 {
290                         /* set default flags */
291                         flags = LIGHT_WOLF_DEFAULT;
292
293                         /* inverse distance squared attenuation? */
294                         if ( spawnflags & 1 ) {
295                                 flags &= ~LIGHT_ATTEN_LINEAR;
296                                 flags |= LIGHT_ATTEN_ANGLE;
297                         }
298
299                         /* angle attenuate? */
300                         if ( spawnflags & 2 ) {
301                                 flags |= LIGHT_ATTEN_ANGLE;
302                         }
303                 }
304
305                 /* other flags (borrowed from wolf) */
306
307                 /* wolf dark light? */
308                 if ( ( spawnflags & 4 ) || ( spawnflags & 8 ) ) {
309                         flags |= LIGHT_DARK;
310                 }
311
312                 /* nogrid? */
313                 if ( spawnflags & 16 ) {
314                         flags &= ~LIGHT_GRID;
315                 }
316
317                 /* junior? */
318                 if ( junior ) {
319                         flags |= LIGHT_GRID;
320                         flags &= ~LIGHT_SURFACES;
321                 }
322
323                 /* store the flags */
324                 light->flags = flags;
325
326                 /* ydnar: set fade key (from wolf) */
327                 light->fade = 1.0f;
328                 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
329                         light->fade = FloatForKey( e, "fade" );
330                         if ( light->fade == 0.0f ) {
331                                 light->fade = 1.0f;
332                         }
333                 }
334
335                 /* ydnar: set angle scaling (from vlight) */
336                 light->angleScale = FloatForKey( e, "_anglescale" );
337                 if ( light->angleScale != 0.0f ) {
338                         light->flags |= LIGHT_ATTEN_ANGLE;
339                 }
340
341                 /* set origin */
342                 GetVectorForKey( e, "origin", light->origin );
343                 light->style = IntForKey( e, "_style" );
344                 if ( light->style == LS_NORMAL ) {
345                         light->style = IntForKey( e, "style" );
346                 }
347                 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
348                         Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
349                 }
350
351                 if ( light->style != LS_NORMAL ) {
352                         Sys_FPrintf( SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
353                 }
354
355                 /* set light intensity */
356                 intensity = FloatForKey( e, "_light" );
357                 if ( intensity == 0.0f ) {
358                         intensity = FloatForKey( e, "light" );
359                 }
360                 if ( intensity == 0.0f ) {
361                         intensity = 300.0f;
362                 }
363
364                 /* ydnar: set light scale (sof2) */
365                 scale = FloatForKey( e, "scale" );
366                 if ( scale == 0.0f ) {
367                         scale = 1.0f;
368                 }
369                 intensity *= scale;
370
371                 /* ydnar: get deviance and samples */
372                 deviance = FloatForKey( e, "_deviance" );
373                 if ( deviance == 0.0f ) {
374                         deviance = FloatForKey( e, "_deviation" );
375                 }
376                 if ( deviance == 0.0f ) {
377                         deviance = FloatForKey( e, "_jitter" );
378                 }
379                 numSamples = IntForKey( e, "_samples" );
380                 if ( deviance < 0.0f || numSamples < 1 ) {
381                         deviance = 0.0f;
382                         numSamples = 1;
383                 }
384                 intensity /= numSamples;
385
386                 /* ydnar: get filter radius */
387                 filterRadius = FloatForKey( e, "_filterradius" );
388                 if ( filterRadius == 0.0f ) {
389                         filterRadius = FloatForKey( e, "_filteradius" );
390                 }
391                 if ( filterRadius == 0.0f ) {
392                         filterRadius = FloatForKey( e, "_filter" );
393                 }
394                 if ( filterRadius < 0.0f ) {
395                         filterRadius = 0.0f;
396                 }
397                 light->filterRadius = filterRadius;
398
399                 /* set light color */
400                 _color = ValueForKey( e, "_color" );
401                 if ( _color && _color[ 0 ] ) {
402                         sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
403                         ColorNormalize( light->color, light->color );
404                 }
405                 else{
406                         light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
407                 }
408
409                 intensity = intensity * pointScale;
410                 light->photons = intensity;
411
412                 light->type = EMIT_POINT;
413
414                 /* set falloff threshold */
415                 light->falloffTolerance = falloffTolerance / numSamples;
416
417                 /* lights with a target will be spotlights */
418                 target = ValueForKey( e, "target" );
419                 if ( target[ 0 ] ) {
420                         float radius;
421                         float dist;
422                         sun_t sun;
423                         const char  *_sun;
424
425
426                         /* get target */
427                         e2 = FindTargetEntity( target );
428                         if ( e2 == NULL ) {
429                                 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
430                                                         (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
431                         }
432                         else
433                         {
434                                 /* not a point light */
435                                 numPointLights--;
436                                 numSpotLights++;
437
438                                 /* make a spotlight */
439                                 GetVectorForKey( e2, "origin", dest );
440                                 VectorSubtract( dest, light->origin, light->normal );
441                                 dist = VectorNormalize( light->normal, light->normal );
442                                 radius = FloatForKey( e, "radius" );
443                                 if ( !radius ) {
444                                         radius = 64;
445                                 }
446                                 if ( !dist ) {
447                                         dist = 64;
448                                 }
449                                 light->radiusByDist = ( radius + 16 ) / dist;
450                                 light->type = EMIT_SPOT;
451
452                                 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
453                                 light->flags &= ~LIGHT_ATTEN_LINEAR;
454                                 light->flags |= LIGHT_ATTEN_ANGLE;
455                                 light->fade = 1.0f;
456
457                                 /* ydnar: is this a sun? */
458                                 _sun = ValueForKey( e, "_sun" );
459                                 if ( _sun[ 0 ] == '1' ) {
460                                         /* not a spot light */
461                                         numSpotLights--;
462
463                                         /* unlink this light */
464                                         lights = light->next;
465
466                                         /* make a sun */
467                                         VectorScale( light->normal, -1.0f, sun.direction );
468                                         VectorCopy( light->color, sun.color );
469                                         sun.photons = ( intensity / pointScale );
470                                         sun.deviance = deviance / 180.0f * Q_PI;
471                                         sun.numSamples = numSamples;
472                                         sun.style = noStyles ? LS_NORMAL : light->style;
473                                         sun.next = NULL;
474
475                                         /* make a sun light */
476                                         CreateSunLight( &sun );
477
478                                         /* free original light */
479                                         free( light );
480                                         light = NULL;
481
482                                         /* skip the rest of this love story */
483                                         continue;
484                                 }
485                         }
486                 }
487
488                 /* jitter the light */
489                 for ( j = 1; j < numSamples; j++ )
490                 {
491                         /* create a light */
492                         light2 = safe_malloc( sizeof( *light ) );
493                         memcpy( light2, light, sizeof( *light ) );
494                         light2->next = lights;
495                         lights = light2;
496
497                         /* add to counts */
498                         if ( light->type == EMIT_SPOT ) {
499                                 numSpotLights++;
500                         }
501                         else{
502                                 numPointLights++;
503                         }
504
505                         /* jitter it */
506                         light2->origin[ 0 ] = light->origin[ 0 ] + ( Random() * 2.0f - 1.0f ) * deviance;
507                         light2->origin[ 1 ] = light->origin[ 1 ] + ( Random() * 2.0f - 1.0f ) * deviance;
508                         light2->origin[ 2 ] = light->origin[ 2 ] + ( Random() * 2.0f - 1.0f ) * deviance;
509                 }
510         }
511 }
512
513
514
515 /*
516    CreateSurfaceLights() - ydnar
517    this hijacks the radiosity code to generate surface lights for first pass
518  */
519
520 #define APPROX_BOUNCE   1.0f
521
522 void CreateSurfaceLights( void ){
523         int i;
524         bspDrawSurface_t    *ds;
525         surfaceInfo_t       *info;
526         shaderInfo_t        *si;
527         light_t             *light;
528         float subdivide;
529         vec3_t origin;
530         clipWork_t cw;
531         const char          *nss;
532
533
534         /* get sun shader supressor */
535         nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
536
537         /* walk the list of surfaces */
538         for ( i = 0; i < numBSPDrawSurfaces; i++ )
539         {
540                 /* get surface and other bits */
541                 ds = &bspDrawSurfaces[ i ];
542                 info = &surfaceInfos[ i ];
543                 si = info->si;
544
545                 /* sunlight? */
546                 if ( si->sun != NULL && nss[ 0 ] != '1' ) {
547                         Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
548                         CreateSunLight( si->sun );
549                         si->sun = NULL; /* FIXME: leak! */
550                 }
551
552                 /* sky light? */
553                 if ( si->skyLightValue > 0.0f ) {
554                         Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
555                         CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
556                         si->skyLightValue = 0.0f;   /* FIXME: hack! */
557                 }
558
559                 /* try to early out */
560                 if ( si->value <= 0 ) {
561                         continue;
562                 }
563
564                 /* autosprite shaders become point lights */
565                 if ( si->autosprite ) {
566                         /* create an average xyz */
567                         VectorAdd( info->mins, info->maxs, origin );
568                         VectorScale( origin, 0.5f, origin );
569
570                         /* create a light */
571                         light = safe_malloc( sizeof( *light ) );
572                         memset( light, 0, sizeof( *light ) );
573                         light->next = lights;
574                         lights = light;
575
576                         /* set it up */
577                         light->flags = LIGHT_Q3A_DEFAULT;
578                         light->type = EMIT_POINT;
579                         light->photons = si->value * pointScale;
580                         light->fade = 1.0f;
581                         light->si = si;
582                         VectorCopy( origin, light->origin );
583                         VectorCopy( si->color, light->color );
584                         light->falloffTolerance = falloffTolerance;
585                         light->style = si->lightStyle;
586
587                         /* add to point light count and continue */
588                         numPointLights++;
589                         continue;
590                 }
591
592                 /* get subdivision amount */
593                 if ( si->lightSubdivide > 0 ) {
594                         subdivide = si->lightSubdivide;
595                 }
596                 else{
597                         subdivide = defaultLightSubdivide;
598                 }
599
600                 /* switch on type */
601                 switch ( ds->surfaceType )
602                 {
603                 case MST_PLANAR:
604                 case MST_TRIANGLE_SOUP:
605                         RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
606                         break;
607
608                 case MST_PATCH:
609                         RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
610                         break;
611
612                 default:
613                         break;
614                 }
615         }
616 }
617
618
619
620 /*
621    SetEntityOrigins()
622    find the offset values for inline models
623  */
624
625 void SetEntityOrigins( void ){
626         int i, j, k, f;
627         entity_t            *e;
628         vec3_t origin;
629         const char          *key;
630         int modelnum;
631         bspModel_t          *dm;
632         bspDrawSurface_t    *ds;
633
634
635         /* ydnar: copy drawverts into private storage for nefarious purposes */
636         yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
637         memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
638
639         /* set the entity origins */
640         for ( i = 0; i < numEntities; i++ )
641         {
642                 /* get entity and model */
643                 e = &entities[ i ];
644                 key = ValueForKey( e, "model" );
645                 if ( key[ 0 ] != '*' ) {
646                         continue;
647                 }
648                 modelnum = atoi( key + 1 );
649                 dm = &bspModels[ modelnum ];
650
651                 /* get entity origin */
652                 key = ValueForKey( e, "origin" );
653                 if ( key[ 0 ] == '\0' ) {
654                         continue;
655                 }
656                 GetVectorForKey( e, "origin", origin );
657
658                 /* set origin for all surfaces for this model */
659                 for ( j = 0; j < dm->numBSPSurfaces; j++ )
660                 {
661                         /* get drawsurf */
662                         ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
663
664                         /* set its verts */
665                         for ( k = 0; k < ds->numVerts; k++ )
666                         {
667                                 f = ds->firstVert + k;
668                                 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
669                         }
670                 }
671         }
672 }
673
674
675
676 /*
677    PointToPolygonFormFactor()
678    calculates the area over a point/normal hemisphere a winding covers
679    ydnar: fixme: there has to be a faster way to calculate this
680    without the expensive per-vert sqrts and transcendental functions
681    ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
682    between this and the approximation
683  */
684
685 #define ONE_OVER_2PI    0.159154942f    //% (1.0f / (2.0f * 3.141592657f))
686
687 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ){
688         vec3_t triVector, triNormal;
689         int i, j;
690         vec3_t dirs[ MAX_POINTS_ON_WINDING ];
691         float total;
692         float dot, angle, facing;
693
694
695         /* this is expensive */
696         for ( i = 0; i < w->numpoints; i++ )
697         {
698                 VectorSubtract( w->p[ i ], point, dirs[ i ] );
699                 VectorNormalize( dirs[ i ], dirs[ i ] );
700         }
701
702         /* duplicate first vertex to avoid mod operation */
703         VectorCopy( dirs[ 0 ], dirs[ i ] );
704
705         /* calculcate relative area */
706         total = 0.0f;
707         for ( i = 0; i < w->numpoints; i++ )
708         {
709                 /* get a triangle */
710                 j = i + 1;
711                 dot = DotProduct( dirs[ i ], dirs[ j ] );
712
713                 /* roundoff can cause slight creep, which gives an IND from acos */
714                 if ( dot > 1.0f ) {
715                         dot = 1.0f;
716                 }
717                 else if ( dot < -1.0f ) {
718                         dot = -1.0f;
719                 }
720
721                 /* get the angle */
722                 angle = acos( dot );
723
724                 CrossProduct( dirs[ i ], dirs[ j ], triVector );
725                 if ( VectorNormalize( triVector, triNormal ) < 0.0001f ) {
726                         continue;
727                 }
728
729                 facing = DotProduct( normal, triNormal );
730                 total += facing * angle;
731
732                 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
733                 if ( total > 6.3f || total < -6.3f ) {
734                         return 0.0f;
735                 }
736         }
737
738         /* now in the range of 0 to 1 over the entire incoming hemisphere */
739         //%     total /= (2.0f * 3.141592657f);
740         total *= ONE_OVER_2PI;
741         return total;
742 }
743
744
745
746 /*
747    LightContributionTosample()
748    determines the amount of light reaching a sample (luxel or vertex) from a given light
749  */
750
751 int LightContributionToSample( trace_t *trace ){
752         light_t         *light;
753         float angle;
754         float add;
755         float dist;
756
757
758         /* get light */
759         light = trace->light;
760
761         /* clear color */
762         VectorClear( trace->color );
763
764         /* ydnar: early out */
765         if ( !( light->flags & LIGHT_SURFACES ) || light->envelope <= 0.0f ) {
766                 return 0;
767         }
768
769         /* do some culling checks */
770         if ( light->type != EMIT_SUN ) {
771                 /* MrE: if the light is behind the surface */
772                 if ( trace->twoSided == qfalse ) {
773                         if ( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f ) {
774                                 return 0;
775                         }
776                 }
777
778                 /* ydnar: test pvs */
779                 if ( !ClusterVisible( trace->cluster, light->cluster ) ) {
780                         return 0;
781                 }
782         }
783
784         /* exact point to polygon form factor */
785         if ( light->type == EMIT_AREA ) {
786                 float factor;
787                 float d;
788                 vec3_t pushedOrigin;
789
790
791                 /* project sample point into light plane */
792                 d = DotProduct( trace->origin, light->normal ) - light->dist;
793                 if ( d < 3.0f ) {
794                         /* sample point behind plane? */
795                         if ( !( light->flags & LIGHT_TWOSIDED ) && d < -1.0f ) {
796                                 return 0;
797                         }
798
799                         /* sample plane coincident? */
800                         if ( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f ) {
801                                 return 0;
802                         }
803                 }
804
805                 /* nudge the point so that it is clearly forward of the light */
806                 /* so that surfaces meeting a light emiter don't get black edges */
807                 if ( d > -8.0f && d < 8.0f ) {
808                         VectorMA( trace->origin, ( 8.0f - d ), light->normal, pushedOrigin );
809                 }
810                 else{
811                         VectorCopy( trace->origin, pushedOrigin );
812                 }
813
814                 /* get direction and distance */
815                 VectorCopy( light->origin, trace->end );
816                 dist = SetupTrace( trace );
817                 if ( dist >= light->envelope ) {
818                         return 0;
819                 }
820
821                 /* ptpff approximation */
822                 if ( faster ) {
823                         /* angle attenuation */
824                         angle = DotProduct( trace->normal, trace->direction );
825
826                         /* twosided lighting */
827                         if ( trace->twoSided ) {
828                                 angle = fabs( angle );
829                         }
830
831                         /* attenuate */
832                         angle *= -DotProduct( light->normal, trace->direction );
833                         if ( angle == 0.0f ) {
834                                 return 0;
835                         }
836                         else if ( angle < 0.0f &&
837                                           ( trace->twoSided || ( light->flags & LIGHT_TWOSIDED ) ) ) {
838                                 angle = -angle;
839                         }
840                         add = light->photons / ( dist * dist ) * angle;
841                 }
842                 else
843                 {
844                         /* calculate the contribution */
845                         factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
846                         if ( factor == 0.0f ) {
847                                 return 0;
848                         }
849                         else if ( factor < 0.0f ) {
850                                 /* twosided lighting */
851                                 if ( trace->twoSided || ( light->flags & LIGHT_TWOSIDED ) ) {
852                                         factor = -factor;
853
854                                         /* push light origin to other side of the plane */
855                                         VectorMA( light->origin, -2.0f, light->normal, trace->end );
856                                         dist = SetupTrace( trace );
857                                         if ( dist >= light->envelope ) {
858                                                 return 0;
859                                         }
860                                 }
861                                 else{
862                                         return 0;
863                                 }
864                         }
865
866                         /* ydnar: moved to here */
867                         add = factor * light->add;
868                 }
869         }
870
871         /* point/spot lights */
872         else if ( light->type == EMIT_POINT || light->type == EMIT_SPOT ) {
873                 /* get direction and distance */
874                 VectorCopy( light->origin, trace->end );
875                 dist = SetupTrace( trace );
876                 if ( dist >= light->envelope ) {
877                         return 0;
878                 }
879
880                 /* clamp the distance to prevent super hot spots */
881                 if ( dist < 16.0f ) {
882                         dist = 16.0f;
883                 }
884
885                 /* angle attenuation */
886                 angle = ( light->flags & LIGHT_ATTEN_ANGLE ) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
887                 if ( light->angleScale != 0.0f ) {
888                         angle /= light->angleScale;
889                         if ( angle > 1.0f ) {
890                                 angle = 1.0f;
891                         }
892                 }
893
894                 /* twosided lighting */
895                 if ( trace->twoSided ) {
896                         angle = fabs( angle );
897                 }
898
899                 /* attenuate */
900                 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
901                         add = angle * light->photons * linearScale - ( dist * light->fade );
902                         if ( add < 0.0f ) {
903                                 add = 0.0f;
904                         }
905                 }
906                 else{
907                         add = light->photons / ( dist * dist ) * angle;
908                 }
909
910                 /* handle spotlights */
911                 if ( light->type == EMIT_SPOT ) {
912                         float distByNormal, radiusAtDist, sampleRadius;
913                         vec3_t pointAtDist, distToSample;
914
915
916                         /* do cone calculation */
917                         distByNormal = -DotProduct( trace->displacement, light->normal );
918                         if ( distByNormal < 0.0f ) {
919                                 return 0;
920                         }
921                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
922                         radiusAtDist = light->radiusByDist * distByNormal;
923                         VectorSubtract( trace->origin, pointAtDist, distToSample );
924                         sampleRadius = VectorLength( distToSample );
925
926                         /* outside the cone */
927                         if ( sampleRadius >= radiusAtDist ) {
928                                 return 0;
929                         }
930
931                         /* attenuate */
932                         if ( sampleRadius > ( radiusAtDist - 32.0f ) ) {
933                                 add *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
934                         }
935                 }
936         }
937
938         /* ydnar: sunlight */
939         else if ( light->type == EMIT_SUN ) {
940                 /* get origin and direction */
941                 VectorAdd( trace->origin, light->origin, trace->end );
942                 dist = SetupTrace( trace );
943
944                 /* angle attenuation */
945                 angle = ( light->flags & LIGHT_ATTEN_ANGLE )
946                                 ? DotProduct( trace->normal, trace->direction )
947                                 : 1.0f;
948
949                 /* twosided lighting */
950                 if ( trace->twoSided ) {
951                         angle = fabs( angle );
952                 }
953
954                 /* attenuate */
955                 add = light->photons * angle;
956                 if ( add <= 0.0f ) {
957                         return 0;
958                 }
959
960                 /* setup trace */
961                 trace->testAll = qtrue;
962                 VectorScale( light->color, add, trace->color );
963
964                 /* trace to point */
965                 if ( trace->testOcclusion && !trace->forceSunlight ) {
966                         /* trace */
967                         TraceLine( trace );
968                         if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) {
969                                 VectorClear( trace->color );
970                                 return -1;
971                         }
972                 }
973
974                 /* return to sender */
975                 return 1;
976         }
977
978         /* ydnar: changed to a variable number */
979         if ( add <= 0.0f || ( add <= light->falloffTolerance && ( light->flags & LIGHT_FAST_ACTUAL ) ) ) {
980                 return 0;
981         }
982
983         /* setup trace */
984         trace->testAll = qfalse;
985         VectorScale( light->color, add, trace->color );
986
987         /* raytrace */
988         TraceLine( trace );
989         if ( trace->passSolid || trace->opaque ) {
990                 VectorClear( trace->color );
991                 return -1;
992         }
993
994         /* return to sender */
995         return 1;
996 }
997
998
999
1000 /*
1001    LightingAtSample()
1002    determines the amount of light reaching a sample (luxel or vertex)
1003  */
1004
1005 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] ){
1006         int i, lightmapNum;
1007
1008
1009         /* clear colors */
1010         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1011                 VectorClear( colors[ lightmapNum ] );
1012
1013         /* ydnar: normalmap */
1014         if ( normalmap ) {
1015                 colors[ 0 ][ 0 ] = ( trace->normal[ 0 ] + 1.0f ) * 127.5f;
1016                 colors[ 0 ][ 1 ] = ( trace->normal[ 1 ] + 1.0f ) * 127.5f;
1017                 colors[ 0 ][ 2 ] = ( trace->normal[ 2 ] + 1.0f ) * 127.5f;
1018                 return;
1019         }
1020
1021         /* ydnar: don't bounce ambient all the time */
1022         if ( !bouncing ) {
1023                 VectorCopy( ambientColor, colors[ 0 ] );
1024         }
1025
1026         /* ydnar: trace to all the list of lights pre-stored in tw */
1027         for ( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1028         {
1029                 /* set light */
1030                 trace->light = trace->lights[ i ];
1031
1032                 /* style check */
1033                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1034                 {
1035                         if ( styles[ lightmapNum ] == trace->light->style ||
1036                                  styles[ lightmapNum ] == LS_NONE ) {
1037                                 break;
1038                         }
1039                 }
1040
1041                 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1042                 if ( lightmapNum >= MAX_LIGHTMAPS ) {
1043                         continue;
1044                 }
1045
1046                 /* sample light */
1047                 LightContributionToSample( trace );
1048                 if ( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f ) {
1049                         continue;
1050                 }
1051
1052                 /* handle negative light */
1053                 if ( trace->light->flags & LIGHT_NEGATIVE ) {
1054                         VectorScale( trace->color, -1.0f, trace->color );
1055                 }
1056
1057                 /* set style */
1058                 styles[ lightmapNum ] = trace->light->style;
1059
1060                 /* add it */
1061                 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1062
1063                 /* cheap mode */
1064                 if ( cheap &&
1065                          colors[ 0 ][ 0 ] >= 255.0f &&
1066                          colors[ 0 ][ 1 ] >= 255.0f &&
1067                          colors[ 0 ][ 2 ] >= 255.0f ) {
1068                         break;
1069                 }
1070         }
1071 }
1072
1073
1074
1075 /*
1076    LightContributionToPoint()
1077    for a given light, how much light/color reaches a given point in space (with no facing)
1078    note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1079  */
1080
1081 int LightContributionToPoint( trace_t *trace ){
1082         light_t     *light;
1083         float add, dist;
1084
1085
1086         /* get light */
1087         light = trace->light;
1088
1089         /* clear color */
1090         VectorClear( trace->color );
1091
1092         /* ydnar: early out */
1093         if ( !( light->flags & LIGHT_GRID ) || light->envelope <= 0.0f ) {
1094                 return qfalse;
1095         }
1096
1097         /* is this a sun? */
1098         if ( light->type != EMIT_SUN ) {
1099                 /* sun only? */
1100                 if ( sunOnly ) {
1101                         return qfalse;
1102                 }
1103
1104                 /* test pvs */
1105                 if ( !ClusterVisible( trace->cluster, light->cluster ) ) {
1106                         return qfalse;
1107                 }
1108         }
1109
1110         /* ydnar: check origin against light's pvs envelope */
1111         if ( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1112                  trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1113                  trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] ) {
1114                 gridBoundsCulled++;
1115                 return qfalse;
1116         }
1117
1118         /* set light origin */
1119         if ( light->type == EMIT_SUN ) {
1120                 VectorAdd( trace->origin, light->origin, trace->end );
1121         }
1122         else{
1123                 VectorCopy( light->origin, trace->end );
1124         }
1125
1126         /* set direction */
1127         dist = SetupTrace( trace );
1128
1129         /* test envelope */
1130         if ( dist > light->envelope ) {
1131                 gridEnvelopeCulled++;
1132                 return qfalse;
1133         }
1134
1135         /* ptpff approximation */
1136         if ( light->type == EMIT_AREA && faster ) {
1137                 /* clamp the distance to prevent super hot spots */
1138                 if ( dist < 16.0f ) {
1139                         dist = 16.0f;
1140                 }
1141
1142                 /* attenuate */
1143                 add = light->photons / ( dist * dist );
1144         }
1145
1146         /* exact point to polygon form factor */
1147         else if ( light->type == EMIT_AREA ) {
1148                 float factor, d;
1149                 vec3_t pushedOrigin;
1150
1151
1152                 /* see if the point is behind the light */
1153                 d = DotProduct( trace->origin, light->normal ) - light->dist;
1154                 if ( !( light->flags & LIGHT_TWOSIDED ) && d < -1.0f ) {
1155                         return qfalse;
1156                 }
1157
1158                 /* nudge the point so that it is clearly forward of the light */
1159                 /* so that surfaces meeting a light emiter don't get black edges */
1160                 if ( d > -8.0f && d < 8.0f ) {
1161                         VectorMA( trace->origin, ( 8.0f - d ), light->normal, pushedOrigin );
1162                 }
1163                 else{
1164                         VectorCopy( trace->origin, pushedOrigin );
1165                 }
1166
1167                 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1168                 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1169                 if ( factor == 0.0f ) {
1170                         return qfalse;
1171                 }
1172                 else if ( factor < 0.0f ) {
1173                         if ( light->flags & LIGHT_TWOSIDED ) {
1174                                 factor = -factor;
1175                         }
1176                         else{
1177                                 return qfalse;
1178                         }
1179                 }
1180
1181                 /* ydnar: moved to here */
1182                 add = factor * light->add;
1183         }
1184
1185         /* point/spot lights */
1186         else if ( light->type == EMIT_POINT || light->type == EMIT_SPOT ) {
1187                 /* clamp the distance to prevent super hot spots */
1188                 if ( dist < 16.0f ) {
1189                         dist = 16.0f;
1190                 }
1191
1192                 /* attenuate */
1193                 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
1194                         add = light->photons * linearScale - ( dist * light->fade );
1195                         if ( add < 0.0f ) {
1196                                 add = 0.0f;
1197                         }
1198                 }
1199                 else{
1200                         add = light->photons / ( dist * dist );
1201                 }
1202
1203                 /* handle spotlights */
1204                 if ( light->type == EMIT_SPOT ) {
1205                         float distByNormal, radiusAtDist, sampleRadius;
1206                         vec3_t pointAtDist, distToSample;
1207
1208
1209                         /* do cone calculation */
1210                         distByNormal = -DotProduct( trace->displacement, light->normal );
1211                         if ( distByNormal < 0.0f ) {
1212                                 return qfalse;
1213                         }
1214                         VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1215                         radiusAtDist = light->radiusByDist * distByNormal;
1216                         VectorSubtract( trace->origin, pointAtDist, distToSample );
1217                         sampleRadius = VectorLength( distToSample );
1218
1219                         /* outside the cone */
1220                         if ( sampleRadius >= radiusAtDist ) {
1221                                 return qfalse;
1222                         }
1223
1224                         /* attenuate */
1225                         if ( sampleRadius > ( radiusAtDist - 32.0f ) ) {
1226                                 add *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
1227                         }
1228                 }
1229         }
1230
1231         /* ydnar: sunlight */
1232         else if ( light->type == EMIT_SUN ) {
1233                 /* attenuate */
1234                 add = light->photons;
1235                 if ( add <= 0.0f ) {
1236                         return qfalse;
1237                 }
1238
1239                 /* setup trace */
1240                 trace->testAll = qtrue;
1241                 VectorScale( light->color, add, trace->color );
1242
1243                 /* trace to point */
1244                 if ( trace->testOcclusion && !trace->forceSunlight ) {
1245                         /* trace */
1246                         TraceLine( trace );
1247                         if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) {
1248                                 VectorClear( trace->color );
1249                                 return -1;
1250                         }
1251                 }
1252
1253                 /* return to sender */
1254                 return qtrue;
1255         }
1256
1257         /* unknown light type */
1258         else{
1259                 return qfalse;
1260         }
1261
1262         /* ydnar: changed to a variable number */
1263         if ( add <= 0.0f || ( add <= light->falloffTolerance && ( light->flags & LIGHT_FAST_ACTUAL ) ) ) {
1264                 return qfalse;
1265         }
1266
1267         /* setup trace */
1268         trace->testAll = qfalse;
1269         VectorScale( light->color, add, trace->color );
1270
1271         /* trace */
1272         TraceLine( trace );
1273         if ( trace->passSolid ) {
1274                 VectorClear( trace->color );
1275                 return qfalse;
1276         }
1277
1278         /* we have a valid sample */
1279         return qtrue;
1280 }
1281
1282
1283
1284 /*
1285    TraceGrid()
1286    grid samples are for quickly determining the lighting
1287    of dynamically placed entities in the world
1288  */
1289
1290 #define MAX_CONTRIBUTIONS   1024
1291
1292 typedef struct
1293 {
1294         vec3_t dir;
1295         vec3_t color;
1296         int style;
1297 }
1298 contribution_t;
1299
1300 void TraceGrid( int num ){
1301         int i, j, x, y, z, mod, step, numCon, numStyles;
1302         float d;
1303         vec3_t baseOrigin, cheapColor, color;
1304         rawGridPoint_t          *gp;
1305         bspGridPoint_t          *bgp;
1306         contribution_t contributions[ MAX_CONTRIBUTIONS ];
1307         trace_t trace;
1308
1309
1310         /* get grid points */
1311         gp = &rawGridPoints[ num ];
1312         bgp = &bspGridPoints[ num ];
1313
1314         /* get grid origin */
1315         mod = num;
1316         z = mod / ( gridBounds[ 0 ] * gridBounds[ 1 ] );
1317         mod -= z * ( gridBounds[ 0 ] * gridBounds[ 1 ] );
1318         y = mod / gridBounds[ 0 ];
1319         mod -= y * gridBounds[ 0 ];
1320         x = mod;
1321
1322         trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1323         trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1324         trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1325
1326         /* set inhibit sphere */
1327         if ( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] ) {
1328                 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1329         }
1330         else if ( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] ) {
1331                 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1332         }
1333         else{
1334                 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1335         }
1336
1337         /* find point cluster */
1338         trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1339         if ( trace.cluster < 0 ) {
1340                 /* try to nudge the origin around to find a valid point */
1341                 VectorCopy( trace.origin, baseOrigin );
1342                 for ( step = 9; step <= 18; step += 9 )
1343                 {
1344                         for ( i = 0; i < 8; i++ )
1345                         {
1346                                 VectorCopy( baseOrigin, trace.origin );
1347                                 if ( i & 1 ) {
1348                                         trace.origin[ 0 ] += step;
1349                                 }
1350                                 else{
1351                                         trace.origin[ 0 ] -= step;
1352                                 }
1353
1354                                 if ( i & 2 ) {
1355                                         trace.origin[ 1 ] += step;
1356                                 }
1357                                 else{
1358                                         trace.origin[ 1 ] -= step;
1359                                 }
1360
1361                                 if ( i & 4 ) {
1362                                         trace.origin[ 2 ] += step;
1363                                 }
1364                                 else{
1365                                         trace.origin[ 2 ] -= step;
1366                                 }
1367
1368                                 /* ydnar: changed to find cluster num */
1369                                 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1370                                 if ( trace.cluster >= 0 ) {
1371                                         break;
1372                                 }
1373                         }
1374
1375                         if ( i != 8 ) {
1376                                 break;
1377                         }
1378                 }
1379
1380                 /* can't find a valid point at all */
1381                 if ( step > 18 ) {
1382                         return;
1383                 }
1384         }
1385
1386         /* setup trace */
1387         trace.testOcclusion = !noTrace;
1388         trace.forceSunlight = qfalse;
1389         trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1390         trace.numSurfaces = 0;
1391         trace.surfaces = NULL;
1392         trace.numLights = 0;
1393         trace.lights = NULL;
1394
1395         /* clear */
1396         numCon = 0;
1397         VectorClear( cheapColor );
1398
1399         /* trace to all the lights, find the major light direction, and divide the
1400            total light between that along the direction and the remaining in the ambient */
1401         for ( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1402         {
1403                 float addSize;
1404
1405
1406                 /* sample light */
1407                 if ( !LightContributionToPoint( &trace ) ) {
1408                         continue;
1409                 }
1410
1411                 /* handle negative light */
1412                 if ( trace.light->flags & LIGHT_NEGATIVE ) {
1413                         VectorScale( trace.color, -1.0f, trace.color );
1414                 }
1415
1416                 /* add a contribution */
1417                 VectorCopy( trace.color, contributions[ numCon ].color );
1418                 VectorCopy( trace.direction, contributions[ numCon ].dir );
1419                 contributions[ numCon ].style = trace.light->style;
1420                 numCon++;
1421
1422                 /* push average direction around */
1423                 addSize = VectorLength( trace.color );
1424                 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1425
1426                 /* stop after a while */
1427                 if ( numCon >= ( MAX_CONTRIBUTIONS - 1 ) ) {
1428                         break;
1429                 }
1430
1431                 /* ydnar: cheap mode */
1432                 VectorAdd( cheapColor, trace.color, cheapColor );
1433                 if ( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f ) {
1434                         break;
1435                 }
1436         }
1437
1438         /* normalize to get primary light direction */
1439         VectorNormalize( gp->dir, gp->dir );
1440
1441         /* now that we have identified the primary light direction,
1442            go back and separate all the light into directed and ambient */
1443         numStyles = 1;
1444         for ( i = 0; i < numCon; i++ )
1445         {
1446                 /* get relative directed strength */
1447                 d = DotProduct( contributions[ i ].dir, gp->dir );
1448                 if ( d < 0.0f ) {
1449                         d = 0.0f;
1450                 }
1451
1452                 /* find appropriate style */
1453                 for ( j = 0; j < numStyles; j++ )
1454                 {
1455                         if ( gp->styles[ j ] == contributions[ i ].style ) {
1456                                 break;
1457                         }
1458                 }
1459
1460                 /* style not found? */
1461                 if ( j >= numStyles ) {
1462                         /* add a new style */
1463                         if ( numStyles < MAX_LIGHTMAPS ) {
1464                                 gp->styles[ numStyles ] = contributions[ i ].style;
1465                                 bgp->styles[ numStyles ] = contributions[ i ].style;
1466                                 numStyles++;
1467                                 //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1468                         }
1469
1470                         /* fallback */
1471                         else{
1472                                 j = 0;
1473                         }
1474                 }
1475
1476                 /* add the directed color */
1477                 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1478
1479                 /* ambient light will be at 1/4 the value of directed light */
1480                 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1481                 d = 0.25f * ( 1.0f - d );
1482                 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1483         }
1484
1485
1486         /* store off sample */
1487         for ( i = 0; i < MAX_LIGHTMAPS; i++ )
1488         {
1489                 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1490                 if ( !bouncing ) {
1491                         VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1492                 }
1493
1494                 /* set minimum light and copy off to bytes */
1495                 VectorCopy( gp->ambient[ i ], color );
1496                 for ( j = 0; j < 3; j++ )
1497                         if ( color[ j ] < minGridLight[ j ] ) {
1498                                 color[ j ] = minGridLight[ j ];
1499                         }
1500                 ColorToBytes( color, bgp->ambient[ i ], 1.0f );
1501                 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );
1502         }
1503
1504         /* debug code */
1505         #if 0
1506         //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1507         Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1508                                  num,
1509                                  gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1510                                  gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1511         #endif
1512
1513         /* store direction */
1514         if ( !bouncing ) {
1515                 NormalToLatLong( gp->dir, bgp->latLong );
1516         }
1517 }
1518
1519
1520
1521 /*
1522    SetupGrid()
1523    calculates the size of the lightgrid and allocates memory
1524  */
1525
1526 void SetupGrid( void ){
1527         int i, j;
1528         vec3_t maxs, oldGridSize;
1529         const char  *value;
1530         char temp[ 64 ];
1531
1532
1533         /* don't do this if not grid lighting */
1534         if ( noGridLighting ) {
1535                 return;
1536         }
1537
1538         /* ydnar: set grid size */
1539         value = ValueForKey( &entities[ 0 ], "gridsize" );
1540         if ( value[ 0 ] != '\0' ) {
1541                 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1542         }
1543
1544         /* quantize it */
1545         VectorCopy( gridSize, oldGridSize );
1546         for ( i = 0; i < 3; i++ )
1547                 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1548
1549         /* ydnar: increase gridSize until grid count is smaller than max allowed */
1550         numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1551         j = 0;
1552         while ( numRawGridPoints > MAX_MAP_LIGHTGRID )
1553         {
1554                 /* get world bounds */
1555                 for ( i = 0; i < 3; i++ )
1556                 {
1557                         gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1558                         maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1559                         gridBounds[ i ] = ( maxs[ i ] - gridMins[ i ] ) / gridSize[ i ] + 1;
1560                 }
1561
1562                 /* set grid size */
1563                 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1564
1565                 /* increase grid size a bit */
1566                 if ( numRawGridPoints > MAX_MAP_LIGHTGRID ) {
1567                         gridSize[ j++ % 3 ] += 16.0f;
1568                 }
1569         }
1570
1571         /* print it */
1572         Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1573
1574         /* different? */
1575         if ( !VectorCompare( gridSize, oldGridSize ) ) {
1576                 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1577                 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1578                 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1579         }
1580
1581         /* 2nd variable. fixme: is this silly? */
1582         numBSPGridPoints = numRawGridPoints;
1583
1584         /* allocate lightgrid */
1585         rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1586         memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1587
1588         if ( bspGridPoints != NULL ) {
1589                 free( bspGridPoints );
1590         }
1591         bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1592         memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1593
1594         /* clear lightgrid */
1595         for ( i = 0; i < numRawGridPoints; i++ )
1596         {
1597                 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1598                 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1599                 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1600                 for ( j = 1; j < MAX_LIGHTMAPS; j++ )
1601                 {
1602                         rawGridPoints[ i ].styles[ j ] = LS_NONE;
1603                         bspGridPoints[ i ].styles[ j ] = LS_NONE;
1604                 }
1605         }
1606
1607         /* note it */
1608         Sys_Printf( "%9d grid points\n", numRawGridPoints );
1609 }
1610
1611
1612
1613 /*
1614    LightWorld()
1615    does what it says...
1616  */
1617
1618 void LightWorld( void ){
1619         vec3_t color;
1620         float f;
1621         int b, bt;
1622         qboolean minVertex, minGrid;
1623         const char  *value;
1624
1625
1626         /* ydnar: smooth normals */
1627         if ( shade ) {
1628                 Sys_Printf( "--- SmoothNormals ---\n" );
1629                 SmoothNormals();
1630         }
1631
1632         /* determine the number of grid points */
1633         Sys_Printf( "--- SetupGrid ---\n" );
1634         SetupGrid();
1635
1636         /* find the optional minimum lighting values */
1637         GetVectorForKey( &entities[ 0 ], "_color", color );
1638         if ( VectorLength( color ) == 0.0f ) {
1639                 VectorSet( color, 1.0, 1.0, 1.0 );
1640         }
1641
1642         /* ambient */
1643         f = FloatForKey( &entities[ 0 ], "_ambient" );
1644         if ( f == 0.0f ) {
1645                 f = FloatForKey( &entities[ 0 ], "ambient" );
1646         }
1647         VectorScale( color, f, ambientColor );
1648
1649         /* minvertexlight */
1650         minVertex = qfalse;
1651         value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1652         if ( value[ 0 ] != '\0' ) {
1653                 minVertex = qtrue;
1654                 f = atof( value );
1655                 VectorScale( color, f, minVertexLight );
1656         }
1657
1658         /* mingridlight */
1659         minGrid = qfalse;
1660         value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1661         if ( value[ 0 ] != '\0' ) {
1662                 minGrid = qtrue;
1663                 f = atof( value );
1664                 VectorScale( color, f, minGridLight );
1665         }
1666
1667         /* minlight */
1668         value = ValueForKey( &entities[ 0 ], "_minlight" );
1669         if ( value[ 0 ] != '\0' ) {
1670                 f = atof( value );
1671                 VectorScale( color, f, minLight );
1672                 if ( minVertex == qfalse ) {
1673                         VectorScale( color, f, minVertexLight );
1674                 }
1675                 if ( minGrid == qfalse ) {
1676                         VectorScale( color, f, minGridLight );
1677                 }
1678         }
1679
1680         /* create world lights */
1681         Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1682         CreateEntityLights();
1683         CreateSurfaceLights();
1684         Sys_Printf( "%9d point lights\n", numPointLights );
1685         Sys_Printf( "%9d spotlights\n", numSpotLights );
1686         Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1687         Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1688
1689         /* calculate lightgrid */
1690         if ( !noGridLighting ) {
1691                 /* ydnar: set up light envelopes */
1692                 SetupEnvelopes( qtrue, fastgrid );
1693
1694                 Sys_Printf( "--- TraceGrid ---\n" );
1695                 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1696                 Sys_Printf( "%d x %d x %d = %d grid\n",
1697                                         gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1698
1699                 /* ydnar: emit statistics on light culling */
1700                 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1701                 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1702         }
1703
1704         /* slight optimization to remove a sqrt */
1705         subdivideThreshold *= subdivideThreshold;
1706
1707         /* map the world luxels */
1708         Sys_Printf( "--- MapRawLightmap ---\n" );
1709         RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1710         Sys_Printf( "%9d luxels\n", numLuxels );
1711         Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1712         Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1713
1714         /* dirty them up */
1715         if ( dirty ) {
1716                 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1717
1718
1719
1720
1721                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1722         }
1723
1724
1725         /* ydnar: set up light envelopes */
1726         SetupEnvelopes( qfalse, fast );
1727
1728         /* light up my world */
1729         lightsPlaneCulled = 0;
1730         lightsEnvelopeCulled = 0;
1731         lightsBoundsCulled = 0;
1732         lightsClusterCulled = 0;
1733
1734         Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1735         RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1736         Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1737
1738         StitchSurfaceLightmaps();
1739
1740         Sys_Printf( "--- IlluminateVertexes ---\n" );
1741         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1742         Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1743
1744         /* ydnar: emit statistics on light culling */
1745         Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1746         Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1747         Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1748         Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1749
1750         /* radiosity */
1751         b = 1;
1752         bt = bounce;
1753         while ( bounce > 0 )
1754         {
1755                 /* store off the bsp between bounces */
1756                 StoreSurfaceLightmaps();
1757                 Sys_Printf( "Writing %s\n", source );
1758                 WriteBSPFile( source );
1759
1760                 /* note it */
1761                 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1762
1763                 /* flag bouncing */
1764                 bouncing = qtrue;
1765                 VectorClear( ambientColor );
1766
1767                 /* generate diffuse lights */
1768                 RadFreeLights();
1769                 RadCreateDiffuseLights();
1770
1771                 /* setup light envelopes */
1772                 SetupEnvelopes( qfalse, fastbounce );
1773                 if ( numLights == 0 ) {
1774                         Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1775                         break;
1776                 }
1777
1778                 /* add to lightgrid */
1779                 if ( bouncegrid ) {
1780                         gridEnvelopeCulled = 0;
1781                         gridBoundsCulled = 0;
1782
1783                         Sys_Printf( "--- BounceGrid ---\n" );
1784                         RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1785                         Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1786                         Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1787                 }
1788
1789                 /* light up my world */
1790                 lightsPlaneCulled = 0;
1791                 lightsEnvelopeCulled = 0;
1792                 lightsBoundsCulled = 0;
1793                 lightsClusterCulled = 0;
1794
1795                 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1796                 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1797                 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1798                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1799
1800                 StitchSurfaceLightmaps();
1801
1802                 Sys_Printf( "--- IlluminateVertexes ---\n" );
1803                 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1804                 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1805
1806                 /* ydnar: emit statistics on light culling */
1807                 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1808                 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1809                 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1810                 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1811
1812                 /* interate */
1813                 bounce--;
1814                 b++;
1815         }
1816 }
1817
1818
1819
1820 /*
1821    LightMain()
1822    main routine for light processing
1823  */
1824
1825 int LightMain( int argc, char **argv ){
1826         int i;
1827         float f;
1828         char mapSource[ 1024 ];
1829         const char  *value;
1830
1831
1832         /* note it */
1833         Sys_Printf( "--- Light ---\n" );
1834
1835         /* set standard game flags */
1836         wolfLight = game->wolfLight;
1837         lmCustomSize = game->lightmapSize;
1838         lightmapGamma = game->lightmapGamma;
1839         lightmapCompensate = game->lightmapCompensate;
1840
1841         /* process commandline arguments */
1842         for ( i = 1; i < ( argc - 1 ); i++ )
1843         {
1844                 /* lightsource scaling */
1845                 if ( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) ) {
1846                         f = atof( argv[ i + 1 ] );
1847                         pointScale *= f;
1848                         Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1849                         i++;
1850                 }
1851
1852                 else if ( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) ) {
1853                         f = atof( argv[ i + 1 ] );
1854                         areaScale *= f;
1855                         Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1856                         i++;
1857                 }
1858
1859                 else if ( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) ) {
1860                         f = atof( argv[ i + 1 ] );
1861                         skyScale *= f;
1862                         Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1863                         i++;
1864                 }
1865
1866                 else if ( !strcmp( argv[ i ], "-bouncescale" ) ) {
1867                         f = atof( argv[ i + 1 ] );
1868                         bounceScale *= f;
1869                         Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
1870                         i++;
1871                 }
1872
1873                 else if ( !strcmp( argv[ i ], "-scale" ) ) {
1874                         f = atof( argv[ i + 1 ] );
1875                         pointScale *= f;
1876                         areaScale *= f;
1877                         skyScale *= f;
1878                         bounceScale *= f;
1879                         Sys_Printf( "All light scaled by %f\n", f );
1880                         i++;
1881                 }
1882
1883                 else if ( !strcmp( argv[ i ], "-gamma" ) ) {
1884                         f = atof( argv[ i + 1 ] );
1885                         lightmapGamma = f;
1886                         Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
1887                         i++;
1888                 }
1889
1890                 else if ( !strcmp( argv[ i ], "-compensate" ) ) {
1891                         f = atof( argv[ i + 1 ] );
1892                         if ( f <= 0.0f ) {
1893                                 f = 1.0f;
1894                         }
1895                         lightmapCompensate = f;
1896                         Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
1897                         i++;
1898                 }
1899
1900                 /* ydnar switches */
1901                 else if ( !strcmp( argv[ i ], "-bounce" ) ) {
1902                         bounce = atoi( argv[ i + 1 ] );
1903                         if ( bounce < 0 ) {
1904                                 bounce = 0;
1905                         }
1906                         else if ( bounce > 0 ) {
1907                                 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
1908                         }
1909                         i++;
1910                 }
1911
1912                 else if ( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) ) {
1913                         superSample = atoi( argv[ i + 1 ] );
1914                         if ( superSample < 1 ) {
1915                                 superSample = 1;
1916                         }
1917                         else if ( superSample > 1 ) {
1918                                 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", ( superSample * superSample ) );
1919                         }
1920                         i++;
1921                 }
1922
1923                 else if ( !strcmp( argv[ i ], "-samples" ) ) {
1924                         lightSamples = atoi( argv[ i + 1 ] );
1925                         if ( lightSamples < 1 ) {
1926                                 lightSamples = 1;
1927                         }
1928                         else if ( lightSamples > 1 ) {
1929                                 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
1930                         }
1931                         i++;
1932                 }
1933
1934                 else if ( !strcmp( argv[ i ], "-filter" ) ) {
1935                         filter = qtrue;
1936                         Sys_Printf( "Lightmap filtering enabled\n" );
1937                 }
1938
1939                 else if ( !strcmp( argv[ i ], "-dark" ) ) {
1940                         dark = qtrue;
1941                         Sys_Printf( "Dark lightmap seams enabled\n" );
1942                 }
1943
1944
1945
1946
1947
1948
1949
1950                 else if ( !strcmp( argv[ i ], "-shadeangle" ) ) {
1951                         shadeAngleDegrees = atof( argv[ i + 1 ] );
1952                         if ( shadeAngleDegrees < 0.0f ) {
1953                                 shadeAngleDegrees = 0.0f;
1954                         }
1955                         else if ( shadeAngleDegrees > 0.0f ) {
1956                                 shade = qtrue;
1957                                 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
1958                         }
1959                         i++;
1960                 }
1961
1962                 else if ( !strcmp( argv[ i ], "-thresh" ) ) {
1963                         subdivideThreshold = atof( argv[ i + 1 ] );
1964                         if ( subdivideThreshold < 0 ) {
1965                                 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
1966                         }
1967                         else{
1968                                 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
1969                         }
1970                         i++;
1971                 }
1972
1973                 else if ( !strcmp( argv[ i ], "-approx" ) ) {
1974                         approximateTolerance = atoi( argv[ i + 1 ] );
1975                         if ( approximateTolerance < 0 ) {
1976                                 approximateTolerance = 0;
1977                         }
1978                         else if ( approximateTolerance > 0 ) {
1979                                 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
1980                         }
1981                         i++;
1982                 }
1983
1984                 else if ( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) ) {
1985                         deluxemap = qtrue;
1986                         Sys_Printf( "Generating deluxemaps for average light direction\n" );
1987                 }
1988
1989                 else if ( !strcmp( argv[ i ], "-external" ) ) {
1990                         externalLightmaps = qtrue;
1991                         Sys_Printf( "Storing all lightmaps externally\n" );
1992                 }
1993
1994                 else if ( !strcmp( argv[ i ], "-lightmapsize" ) ) {
1995                         lmCustomSize = atoi( argv[ i + 1 ] );
1996
1997                         /* must be a power of 2 and greater than 2 */
1998                         if ( ( ( lmCustomSize - 1 ) & lmCustomSize ) || lmCustomSize < 2 ) {
1999                                 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2000                                 lmCustomSize = game->lightmapSize;
2001                         }
2002                         i++;
2003                         Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2004
2005                         /* enable external lightmaps */
2006                         if ( lmCustomSize != game->lightmapSize ) {
2007                                 externalLightmaps = qtrue;
2008                                 Sys_Printf( "Storing all lightmaps externally\n" );
2009                         }
2010                 }
2011
2012                 /* ydnar: add this to suppress warnings */
2013                 else if ( !strcmp( argv[ i ],  "-custinfoparms" ) ) {
2014                         Sys_Printf( "Custom info parms enabled\n" );
2015                         useCustomInfoParms = qtrue;
2016                 }
2017
2018                 else if ( !strcmp( argv[ i ], "-wolf" ) ) {
2019                         /* -game should already be set */
2020                         wolfLight = qtrue;
2021                         Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2022                 }
2023
2024                 else if ( !strcmp( argv[ i ], "-q3" ) ) {
2025                         /* -game should already be set */
2026                         wolfLight = qfalse;
2027                         Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2028                 }
2029
2030                 else if ( !strcmp( argv[ i ], "-sunonly" ) ) {
2031                         sunOnly = qtrue;
2032                         Sys_Printf( "Only computing sunlight\n" );
2033                 }
2034
2035                 else if ( !strcmp( argv[ i ], "-bounceonly" ) ) {
2036                         bounceOnly = qtrue;
2037                         Sys_Printf( "Storing bounced light (radiosity) only\n" );
2038                 }
2039
2040                 else if ( !strcmp( argv[ i ], "-nocollapse" ) ) {
2041                         noCollapse = qtrue;
2042                         Sys_Printf( "Identical lightmap collapsing disabled\n" );
2043                 }
2044
2045                 else if ( !strcmp( argv[ i ], "-shade" ) ) {
2046                         shade = qtrue;
2047                         Sys_Printf( "Phong shading enabled\n" );
2048                 }
2049
2050                 else if ( !strcmp( argv[ i ], "-bouncegrid" ) ) {
2051                         bouncegrid = qtrue;
2052                         if ( bounce > 0 ) {
2053                                 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2054                         }
2055                 }
2056
2057                 else if ( !strcmp( argv[ i ], "-smooth" ) ) {
2058                         lightSamples = EXTRA_SCALE;
2059                         Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2060                 }
2061
2062                 else if ( !strcmp( argv[ i ], "-fast" ) ) {
2063                         fast = qtrue;
2064                         fastgrid = qtrue;
2065                         fastbounce = qtrue;
2066                         Sys_Printf( "Fast mode enabled\n" );
2067                 }
2068
2069                 else if ( !strcmp( argv[ i ], "-faster" ) ) {
2070                         faster = qtrue;
2071                         fast = qtrue;
2072                         fastgrid = qtrue;
2073                         fastbounce = qtrue;
2074                         Sys_Printf( "Faster mode enabled\n" );
2075                 }
2076
2077                 else if ( !strcmp( argv[ i ], "-fastgrid" ) ) {
2078                         fastgrid = qtrue;
2079                         Sys_Printf( "Fast grid lighting enabled\n" );
2080                 }
2081
2082                 else if ( !strcmp( argv[ i ], "-fastbounce" ) ) {
2083                         fastbounce = qtrue;
2084                         Sys_Printf( "Fast bounce mode enabled\n" );
2085                 }
2086
2087                 else if ( !strcmp( argv[ i ], "-cheap" ) ) {
2088                         cheap = qtrue;
2089                         cheapgrid = qtrue;
2090                         Sys_Printf( "Cheap mode enabled\n" );
2091                 }
2092
2093                 else if ( !strcmp( argv[ i ], "-cheapgrid" ) ) {
2094                         cheapgrid = qtrue;
2095                         Sys_Printf( "Cheap grid mode enabled\n" );
2096                 }
2097
2098                 else if ( !strcmp( argv[ i ], "-normalmap" ) ) {
2099                         normalmap = qtrue;
2100                         Sys_Printf( "Storing normal map instead of lightmap\n" );
2101                 }
2102
2103                 else if ( !strcmp( argv[ i ], "-trisoup" ) ) {
2104                         trisoup = qtrue;
2105                         Sys_Printf( "Converting brush faces to triangle soup\n" );
2106                 }
2107
2108                 else if ( !strcmp( argv[ i ], "-debug" ) ) {
2109                         debug = qtrue;
2110                         Sys_Printf( "Lightmap debugging enabled\n" );
2111                 }
2112
2113                 else if ( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) ) {
2114                         debugSurfaces = qtrue;
2115                         Sys_Printf( "Lightmap surface debugging enabled\n" );
2116                 }
2117
2118                 else if ( !strcmp( argv[ i ], "-debugunused" ) ) {
2119                         debugUnused = qtrue;
2120                         Sys_Printf( "Unused luxel debugging enabled\n" );
2121                 }
2122
2123                 else if ( !strcmp( argv[ i ], "-debugaxis" ) ) {
2124                         debugAxis = qtrue;
2125                         Sys_Printf( "Lightmap axis debugging enabled\n" );
2126                 }
2127
2128                 else if ( !strcmp( argv[ i ], "-debugcluster" ) ) {
2129                         debugCluster = qtrue;
2130                         Sys_Printf( "Luxel cluster debugging enabled\n" );
2131                 }
2132
2133                 else if ( !strcmp( argv[ i ], "-debugorigin" ) ) {
2134                         debugOrigin = qtrue;
2135                         Sys_Printf( "Luxel origin debugging enabled\n" );
2136                 }
2137
2138                 else if ( !strcmp( argv[ i ], "-debugdeluxe" ) ) {
2139                         deluxemap = qtrue;
2140                         debugDeluxemap = qtrue;
2141                         Sys_Printf( "Deluxemap debugging enabled\n" );
2142                 }
2143
2144                 else if ( !strcmp( argv[ i ], "-export" ) ) {
2145                         exportLightmaps = qtrue;
2146                         Sys_Printf( "Exporting lightmaps\n" );
2147                 }
2148
2149                 else if ( !strcmp( argv[ i ], "-notrace" ) ) {
2150                         noTrace = qtrue;
2151                         Sys_Printf( "Shadow occlusion disabled\n" );
2152                 }
2153                 else if ( !strcmp( argv[ i ], "-patchshadows" ) ) {
2154                         patchShadows = qtrue;
2155                         Sys_Printf( "Patch shadow casting enabled\n" );
2156                 }
2157                 else if ( !strcmp( argv[ i ], "-extra" ) ) {
2158                         superSample = EXTRA_SCALE;      /* ydnar */
2159                         Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2160                 }
2161                 else if ( !strcmp( argv[ i ], "-extrawide" ) ) {
2162                         superSample = EXTRAWIDE_SCALE;  /* ydnar */
2163                         filter = qtrue;                 /* ydnar */
2164                         Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n" );
2165                 }
2166                 else if ( !strcmp( argv[ i ], "-samplesize" ) ) {
2167                         sampleSize = atoi( argv[ i + 1 ] );
2168                         if ( sampleSize < 1 ) {
2169                                 sampleSize = 1;
2170                         }
2171                         i++;
2172                         Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2173                 }
2174                 else if ( !strcmp( argv[ i ], "-novertex" ) ) {
2175                         noVertexLighting = qtrue;
2176                         Sys_Printf( "Disabling vertex lighting\n" );
2177                 }
2178                 else if ( !strcmp( argv[ i ], "-nogrid" ) ) {
2179                         noGridLighting = qtrue;
2180                         Sys_Printf( "Disabling grid lighting\n" );
2181                 }
2182                 else if ( !strcmp( argv[ i ], "-border" ) ) {
2183                         lightmapBorder = qtrue;
2184                         Sys_Printf( "Adding debug border to lightmaps\n" );
2185                 }
2186                 else if ( !strcmp( argv[ i ], "-nosurf" ) ) {
2187                         noSurfaces = qtrue;
2188                         Sys_Printf( "Not tracing against surfaces\n" );
2189                 }
2190                 else if ( !strcmp( argv[ i ], "-dump" ) ) {
2191                         dump = qtrue;
2192                         Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2193                 }
2194                 else if ( !strcmp( argv[ i ], "-lomem" ) ) {
2195                         loMem = qtrue;
2196                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2197                 }
2198                 else if ( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) ) {
2199                         noStyles = qtrue;
2200                         Sys_Printf( "Disabling lightstyles\n" );
2201                 }
2202                 else if ( !strcmp( argv[ i ], "-cpma" ) ) {
2203                         cpmaHack = qtrue;
2204                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2205                 }
2206
2207                 /* r7: dirtmapping */
2208                 else if ( !strcmp( argv[ i ], "-dirty" ) ) {
2209                         dirty = qtrue;
2210                         Sys_Printf( "Dirtmapping enabled\n" );
2211                 }
2212                 else if ( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) ) {
2213                         dirtDebug = qtrue;
2214                         Sys_Printf( "Dirtmap debugging enabled\n" );
2215                 }
2216                 else if ( !strcmp( argv[ i ], "-dirtmode" ) ) {
2217                         dirtMode = atoi( argv[ i + 1 ] );
2218                         if ( dirtMode != 0 && dirtMode != 1 ) {
2219                                 dirtMode = 0;
2220                         }
2221                         if ( dirtMode == 1 ) {
2222                                 Sys_Printf( "Enabling randomized dirtmapping\n" );
2223                         }
2224                         else{
2225                                 Sys_Printf( "Enabling ordered dir mapping\n" );
2226                         }
2227                 }
2228                 else if ( !strcmp( argv[ i ], "-dirtdepth" ) ) {
2229                         dirtDepth = atof( argv[ i + 1 ] );
2230                         if ( dirtDepth <= 0.0f ) {
2231                                 dirtDepth = 128.0f;
2232                         }
2233                         Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2234                 }
2235                 else if ( !strcmp( argv[ i ], "-dirtscale" ) ) {
2236                         dirtScale = atof( argv[ i + 1 ] );
2237                         if ( dirtScale <= 0.0f ) {
2238                                 dirtScale = 1.0f;
2239                         }
2240                         Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2241                 }
2242                 else if ( !strcmp( argv[ i ], "-dirtgain" ) ) {
2243                         dirtGain = atof( argv[ i + 1 ] );
2244                         if ( dirtGain <= 0.0f ) {
2245                                 dirtGain = 1.0f;
2246                         }
2247                         Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2248                 }
2249
2250                 /* unhandled args */
2251                 else{
2252                         Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2253                 }
2254
2255         }
2256
2257         /* clean up map name */
2258         strcpy( source, ExpandArg( argv[ i ] ) );
2259         StripExtension( source );
2260         DefaultExtension( source, ".bsp" );
2261         strcpy( mapSource, ExpandArg( argv[ i ] ) );
2262         StripExtension( mapSource );
2263         DefaultExtension( mapSource, ".map" );
2264
2265         /* ydnar: set default sample size */
2266         SetDefaultSampleSize( sampleSize );
2267
2268         /* ydnar: handle shaders */
2269         BeginMapShaderFile( source );
2270         LoadShaderInfo();
2271
2272         /* note loading */
2273         Sys_Printf( "Loading %s\n", source );
2274
2275         /* ydnar: load surface file */
2276         LoadSurfaceExtraFile( source );
2277
2278         /* load bsp file */
2279         LoadBSPFile( source );
2280
2281         /* parse bsp entities */
2282         ParseEntities();
2283
2284         /* load map file */
2285         value = ValueForKey( &entities[ 0 ], "_keepLights" );
2286         if ( value[ 0 ] != '1' ) {
2287                 LoadMapFile( mapSource, qtrue );
2288         }
2289
2290         /* set the entity/model origins and init yDrawVerts */
2291         SetEntityOrigins();
2292
2293         /* ydnar: set up optimization */
2294         SetupBrushes();
2295         SetupDirt();
2296         SetupSurfaceLightmaps();
2297
2298         /* initialize the surface facet tracing */
2299         SetupTraceNodes();
2300
2301         /* light the world */
2302         LightWorld();
2303
2304         /* ydnar: store off lightmaps */
2305         StoreSurfaceLightmaps();
2306
2307         /* write out the bsp */
2308         UnparseEntities();
2309         Sys_Printf( "Writing %s\n", source );
2310         WriteBSPFile( source );
2311
2312         /* ydnar: export lightmaps */
2313         if ( exportLightmaps && !externalLightmaps ) {
2314                 ExportLightmaps();
2315         }
2316
2317         /* return to sender */
2318         return 0;
2319 }