2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ----------------------------------------------------------------------------------
23 This code has been altered significantly from its original form, to support
24 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26 ------------------------------------------------------------------------------- */
41 CreateSunLight() - ydnar
42 this creates a sun light
45 static void CreateSunLight( sun_t *sun )
48 float photons, d, angle, elevation, da, de;
58 if( sun->numSamples < 1 )
62 photons = sun->photons / sun->numSamples;
64 /* create the right number of suns */
65 for( i = 0; i < sun->numSamples; i++ )
67 /* calculate sun direction */
69 VectorCopy( sun->direction, direction );
73 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
74 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
75 sun->direction[ 2 ] = sin( elevation );
77 xz_dist = sqrt( x*x + z*z )
78 latitude = atan2( xz_dist, y ) * RADIANS
79 longitude = atan2( x, z ) * RADIANS
82 d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
83 angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
84 elevation = atan2( sun->direction[ 2 ], d );
86 /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
89 da = (Random() * 2.0f - 1.0f) * sun->deviance;
90 de = (Random() * 2.0f - 1.0f) * sun->deviance;
92 while( (da * da + de * de) > (sun->deviance * sun->deviance) );
97 //% Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
99 /* create new vector */
100 direction[ 0 ] = cos( angle ) * cos( elevation );
101 direction[ 1 ] = sin( angle ) * cos( elevation );
102 direction[ 2 ] = sin( elevation );
107 light = safe_malloc( sizeof( *light ) );
108 memset( light, 0, sizeof( *light ) );
109 light->next = lights;
112 /* initialize the light */
113 light->flags = LIGHT_SUN_DEFAULT;
114 light->type = EMIT_SUN;
116 light->falloffTolerance = falloffTolerance;
117 light->filterRadius = sun->filterRadius / sun->numSamples;
119 /* set the light's position out to infinity */
120 VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin ); /* MAX_WORLD_COORD * 2.0f */
122 /* set the facing to be the inverse of the sun direction */
123 VectorScale( direction, -1.0, light->normal );
124 light->dist = DotProduct( light->origin, light->normal );
126 /* set color and photons */
127 VectorCopy( sun->color, light->color );
128 light->photons = photons * skyScale;
132 if( sun->next != NULL )
133 CreateSunLight( sun->next );
139 CreateSkyLights() - ydnar
140 simulates sky light with multiple suns
143 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius )
145 int c, i, j, k, numSuns;
152 if( value <= 0.0f || iterations < 2 )
155 /* calculate some stuff */
156 step = 2.0f / (iterations - 1);
159 /* basic sun setup */
160 VectorCopy( color, sun.color );
162 sun.filterRadius = filterRadius;
168 for( c = 0; c < 2; c++ )
170 for( k = 0, in[ 2 ] = start; k < iterations; k++, in[ 2 ] += step )
172 /* don't create sky light below the horizon */
173 if( in[ 2 ] <= 0.0f )
176 for( j = 0, in[ 1 ] = start; j < iterations; j++, in[ 1 ] += step )
178 for( i = 0, in[ 0 ] = start; i < iterations; i++, in[ 0 ] += step )
180 if( VectorNormalize( in, sun.direction ) )
182 if( c > 0 && numSuns > 0 )
184 sun.photons = value / numSuns;
185 CreateSunLight( &sun );
200 creates lights from light entities
203 void CreateEntityLights( void )
206 light_t *light, *light2;
212 float intensity, scale, deviance, filterRadius;
213 int spawnflags, flags, numSamples;
217 /* go throught entity list and find lights */
218 for( i = 0; i < numEntities; i++ )
222 name = ValueForKey( e, "classname" );
224 /* ydnar: check for lightJunior */
225 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
227 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
232 /* lights with target names (and therefore styles) are only parsed from BSP */
233 target = ValueForKey( e, "targetname" );
234 if( target[ 0 ] != '\0' && i >= numBSPEntities )
239 light = safe_malloc( sizeof( *light ) );
240 memset( light, 0, sizeof( *light ) );
241 light->next = lights;
244 /* handle spawnflags */
245 spawnflags = IntForKey( e, "spawnflags" );
247 /* ydnar: quake 3+ light behavior */
248 if( game->wolfLight == qfalse )
250 /* set default flags */
251 flags = LIGHT_Q3A_DEFAULT;
253 /* linear attenuation? */
256 flags |= LIGHT_ATTEN_LINEAR;
257 flags &= ~LIGHT_ATTEN_ANGLE;
260 /* no angle attenuate? */
262 flags &= ~LIGHT_ATTEN_ANGLE;
265 /* ydnar: wolf light behavior */
268 /* set default flags */
269 flags = LIGHT_WOLF_DEFAULT;
271 /* inverse distance squared attenuation? */
274 flags &= ~LIGHT_ATTEN_LINEAR;
275 flags |= LIGHT_ATTEN_ANGLE;
278 /* angle attenuate? */
280 flags |= LIGHT_ATTEN_ANGLE;
283 /* other flags (borrowed from wolf) */
285 /* wolf dark light? */
286 if( (spawnflags & 4) || (spawnflags & 8) )
290 if( spawnflags & 16 )
291 flags &= ~LIGHT_GRID;
297 flags &= ~LIGHT_SURFACES;
300 /* store the flags */
301 light->flags = flags;
303 /* ydnar: set fade key (from wolf) */
305 if( light->flags & LIGHT_ATTEN_LINEAR )
307 light->fade = FloatForKey( e, "fade" );
308 if( light->fade == 0.0f )
312 /* ydnar: set angle scaling (from vlight) */
313 light->angleScale = FloatForKey( e, "_anglescale" );
314 if( light->angleScale != 0.0f )
315 light->flags |= LIGHT_ATTEN_ANGLE;
318 GetVectorForKey( e, "origin", light->origin);
319 light->style = IntForKey( e, "_style" );
320 if( light->style == 0 )
321 light->style = IntForKey( e, "style" );
322 if( light->style < LS_NORMAL || light->style >= LS_NONE )
323 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
325 if( light->style != LS_NORMAL ) {
326 Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
329 /* set light intensity */
330 intensity = FloatForKey( e, "_light" );
331 if( intensity == 0.0f )
332 intensity = FloatForKey( e, "light" );
333 if( intensity == 0.0f)
336 /* ydnar: set light scale (sof2) */
337 scale = FloatForKey( e, "scale" );
342 /* ydnar: get deviance and samples */
343 deviance = FloatForKey( e, "_deviance" );
344 if( deviance == 0.0f )
345 deviance = FloatForKey( e, "_deviation" );
346 if( deviance == 0.0f )
347 deviance = FloatForKey( e, "_jitter" );
348 numSamples = IntForKey( e, "_samples" );
349 if( deviance < 0.0f || numSamples < 1 )
354 intensity /= numSamples;
356 /* ydnar: get filter radius */
357 filterRadius = FloatForKey( e, "_filterradius" );
358 if( filterRadius == 0.0f )
359 filterRadius = FloatForKey( e, "_filteradius" );
360 if( filterRadius == 0.0f )
361 filterRadius = FloatForKey( e, "_filter" );
362 if( filterRadius < 0.0f )
364 light->filterRadius = filterRadius;
366 /* set light color */
367 _color = ValueForKey( e, "_color" );
368 if( _color && _color[ 0 ] )
370 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
371 ColorNormalize( light->color, light->color );
374 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
376 intensity = intensity * pointScale;
377 light->photons = intensity;
379 light->type = EMIT_POINT;
381 /* set falloff threshold */
382 light->falloffTolerance = falloffTolerance / numSamples;
384 /* lights with a target will be spotlights */
385 target = ValueForKey( e, "target" );
395 e2 = FindTargetEntity( target );
398 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
399 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
403 /* not a point light */
407 /* make a spotlight */
408 GetVectorForKey( e2, "origin", dest );
409 VectorSubtract( dest, light->origin, light->normal );
410 dist = VectorNormalize( light->normal, light->normal );
411 radius = FloatForKey( e, "radius" );
416 light->radiusByDist = (radius + 16) / dist;
417 light->type = EMIT_SPOT;
419 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
420 light->flags &= ~LIGHT_ATTEN_LINEAR;
421 light->flags |= LIGHT_ATTEN_ANGLE;
424 /* ydnar: is this a sun? */
425 _sun = ValueForKey( e, "_sun" );
426 if( _sun[ 0 ] == '1' )
428 /* not a spot light */
431 /* unlink this light */
432 lights = light->next;
435 VectorScale( light->normal, -1.0f, sun.direction );
436 VectorCopy( light->color, sun.color );
437 sun.photons = (intensity / pointScale);
438 sun.deviance = deviance / 180.0f * Q_PI;
439 sun.numSamples = numSamples;
442 /* make a sun light */
443 CreateSunLight( &sun );
445 /* free original light */
449 /* skip the rest of this love story */
455 /* jitter the light */
456 for( j = 1; j < numSamples; j++ )
459 light2 = safe_malloc( sizeof( *light ) );
460 memcpy( light2, light, sizeof( *light ) );
461 light2->next = lights;
465 if( light->type == EMIT_SPOT )
471 light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
472 light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
473 light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
481 CreateSurfaceLights() - ydnar
482 this hijacks the radiosity code to generate surface lights for first pass
485 #define APPROX_BOUNCE 1.0f
487 void CreateSurfaceLights( void )
490 bspDrawSurface_t *ds;
500 /* get sun shader supressor */
501 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
503 /* walk the list of surfaces */
504 for( i = 0; i < numBSPDrawSurfaces; i++ )
506 /* get surface and other bits */
507 ds = &bspDrawSurfaces[ i ];
508 info = &surfaceInfos[ i ];
512 if( si->sun != NULL && nss[ 0 ] != '1' )
514 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
515 CreateSunLight( si->sun );
516 si->sun = NULL; /* FIXME: leak! */
520 if( si->skyLightValue > 0.0f )
522 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
523 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius );
524 si->skyLightValue = 0.0f; /* FIXME: hack! */
527 /* try to early out */
531 /* autosprite shaders become point lights */
534 /* create an average xyz */
535 VectorAdd( info->mins, info->maxs, origin );
536 VectorScale( origin, 0.5f, origin );
539 light = safe_malloc( sizeof( *light ) );
540 memset( light, 0, sizeof( *light ) );
541 light->next = lights;
545 light->flags = LIGHT_Q3A_DEFAULT;
546 light->type = EMIT_POINT;
547 light->photons = si->value * pointScale;
550 VectorCopy( origin, light->origin );
551 VectorCopy( si->color, light->color );
552 light->falloffTolerance = falloffTolerance;
553 light->style = light->style;
555 /* add to point light count and continue */
560 /* get subdivision amount */
561 if( si->lightSubdivide > 0 )
562 subdivide = si->lightSubdivide;
564 subdivide = defaultLightSubdivide;
567 switch( ds->surfaceType )
570 case MST_TRIANGLE_SOUP:
571 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
575 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
588 find the offset values for inline models
591 void SetEntityOrigins( void )
599 bspDrawSurface_t *ds;
602 /* ydnar: copy drawverts into private storage for nefarious purposes */
603 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
604 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
606 /* set the entity origins */
607 for( i = 0; i < numEntities; i++ )
609 /* get entity and model */
611 key = ValueForKey( e, "model" );
612 if( key[ 0 ] != '*' )
614 modelnum = atoi( key + 1 );
615 dm = &bspModels[ modelnum ];
617 /* get entity origin */
618 key = ValueForKey( e, "origin" );
619 if( key[ 0 ] == '\0' )
621 GetVectorForKey( e, "origin", origin );
623 /* set origin for all surfaces for this model */
624 for( j = 0; j < dm->numBSPSurfaces; j++ )
627 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
630 for( k = 0; k < ds->numVerts; k++ )
632 f = ds->firstVert + k;
633 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
642 PointToPolygonFormFactor()
643 calculates the area over a point/normal hemisphere a winding covers
644 ydnar: fixme: there has to be a faster way to calculate this
645 without the expensive per-vert sqrts and transcendental functions
646 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
647 between this and the approximation
650 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
652 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
654 vec3_t triVector, triNormal;
656 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
658 float dot, angle, facing;
661 /* this is expensive */
662 for( i = 0; i < w->numpoints; i++ )
664 VectorSubtract( w->p[ i ], point, dirs[ i ] );
665 VectorNormalize( dirs[ i ], dirs[ i ] );
668 /* duplicate first vertex to avoid mod operation */
669 VectorCopy( dirs[ 0 ], dirs[ i ] );
671 /* calculcate relative area */
673 for( i = 0; i < w->numpoints; i++ )
677 dot = DotProduct( dirs[ i ], dirs[ j ] );
679 /* roundoff can cause slight creep, which gives an IND from acos */
682 else if( dot < -1.0f )
688 CrossProduct( dirs[ i ], dirs[ j ], triVector );
689 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
692 facing = DotProduct( normal, triNormal );
693 total += facing * angle;
695 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
696 if( total > 6.3f || total < -6.3f )
700 /* now in the range of 0 to 1 over the entire incoming hemisphere */
701 //% total /= (2.0f * 3.141592657f);
702 total *= ONE_OVER_2PI;
709 LightContributionTosample()
710 determines the amount of light reaching a sample (luxel or vertex) from a given light
713 int LightContributionToSample( trace_t *trace )
722 light = trace->light;
725 VectorClear( trace->color );
727 /* ydnar: early out */
728 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
731 /* do some culling checks */
732 if( light->type != EMIT_SUN )
734 /* MrE: if the light is behind the surface */
735 if( trace->twoSided == qfalse )
736 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
739 /* ydnar: test pvs */
740 if( !ClusterVisible( trace->cluster, light->cluster ) )
744 /* ptpff approximation */
745 if( light->type == EMIT_AREA && faster )
747 /* get direction and distance */
748 VectorCopy( light->origin, trace->end );
749 dist = SetupTrace( trace );
750 if( dist >= light->envelope )
753 /* clamp the distance to prevent super hot spots */
757 /* angle attenuation */
758 angle = DotProduct( trace->normal, trace->direction );
760 /* twosided lighting */
761 if( trace->twoSided )
762 angle = fabs( angle );
765 angle *= -DotProduct( light->normal, trace->direction );
768 add = light->photons / (dist * dist) * angle;
771 /* exact point to polygon form factor */
772 else if( light->type == EMIT_AREA )
779 /* project sample point into light plane */
780 d = DotProduct( trace->origin, light->normal ) - light->dist;
781 //% if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
785 /* sample point behind plane? */
786 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
789 /* sample plane coincident? */
790 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
794 /* nudge the point so that it is clearly forward of the light */
795 /* so that surfaces meeting a light emiter don't get black edges */
796 if( d > -8.0f && d < 8.0f )
797 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
799 VectorCopy( trace->origin, pushedOrigin );
801 /* get direction and distance */
802 VectorCopy( light->origin, trace->end );
803 dist = SetupTrace( trace );
804 if( dist >= light->envelope )
807 /* calculate the contribution */
808 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
811 else if( factor < 0.0f )
813 /* twosided lighting */
814 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
818 /* push light origin to other side of the plane */
819 VectorMA( light->origin, -2.0f, light->normal, trace->end );
820 dist = SetupTrace( trace );
821 if( dist >= light->envelope )
828 /* ydnar: moved to here */
829 add = factor * light->add;
832 /* point/spot lights */
833 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
835 /* get direction and distance */
836 VectorCopy( light->origin, trace->end );
837 dist = SetupTrace( trace );
838 if( dist >= light->envelope )
841 /* clamp the distance to prevent super hot spots */
845 /* angle attenuation */
846 angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
847 if( light->angleScale != 0.0f )
849 angle /= light->angleScale;
854 /* twosided lighting */
855 if( trace->twoSided )
856 angle = fabs( angle );
859 if( light->flags & LIGHT_ATTEN_LINEAR )
861 add = angle * light->photons * linearScale - (dist * light->fade);
866 add = light->photons / (dist * dist) * angle;
868 /* handle spotlights */
869 if( light->type == EMIT_SPOT )
871 float distByNormal, radiusAtDist, sampleRadius;
872 vec3_t pointAtDist, distToSample;
875 /* do cone calculation */
876 distByNormal = -DotProduct( trace->displacement, light->normal );
877 if( distByNormal < 0.0f )
879 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
880 radiusAtDist = light->radiusByDist * distByNormal;
881 VectorSubtract( trace->origin, pointAtDist, distToSample );
882 sampleRadius = VectorLength( distToSample );
884 /* outside the cone */
885 if( sampleRadius >= radiusAtDist )
889 if( sampleRadius > (radiusAtDist - 32.0f) )
890 add *= ((radiusAtDist - sampleRadius) / 32.0f);
894 /* ydnar: sunlight */
895 else if( light->type == EMIT_SUN )
897 /* get origin and direction */
898 VectorAdd( trace->origin, light->origin, trace->end );
899 dist = SetupTrace( trace );
901 /* angle attenuation */
902 angle = (light->flags & LIGHT_ATTEN_ANGLE)
903 ? DotProduct( trace->normal, trace->direction )
906 /* twosided lighting */
907 if( trace->twoSided )
908 angle = fabs( angle );
911 add = light->photons * angle;
916 trace->testAll = qtrue;
917 VectorScale( light->color, add, trace->color );
920 if( trace->testOcclusion && !trace->forceSunlight )
924 if( !(trace->compileFlags & C_SKY) || trace->opaque )
926 VectorClear( trace->color );
931 /* return to sender */
935 /* ydnar: changed to a variable number */
936 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
940 trace->testAll = qfalse;
941 VectorScale( light->color, add, trace->color );
945 if( trace->passSolid || trace->opaque )
947 VectorClear( trace->color );
951 /* return to sender */
959 determines the amount of light reaching a sample (luxel or vertex)
962 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
968 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
969 VectorClear( colors[ lightmapNum ] );
971 /* ydnar: normalmap */
974 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
975 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
976 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
980 /* ydnar: don't bounce ambient all the time */
982 VectorCopy( ambientColor, colors[ 0 ] );
984 /* ydnar: trace to all the list of lights pre-stored in tw */
985 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
988 trace->light = trace->lights[ i ];
991 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
993 if( styles[ lightmapNum ] == trace->light->style ||
994 styles[ lightmapNum ] == LS_NONE )
998 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
999 if( lightmapNum >= MAX_LIGHTMAPS )
1003 LightContributionToSample( trace );
1004 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1007 /* handle negative light */
1008 if( trace->light->flags & LIGHT_NEGATIVE )
1009 VectorScale( trace->color, -1.0f, trace->color );
1012 styles[ lightmapNum ] = trace->light->style;
1015 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1019 colors[ 0 ][ 0 ] >= 255.0f &&
1020 colors[ 0 ][ 1 ] >= 255.0f &&
1021 colors[ 0 ][ 2 ] >= 255.0f )
1029 LightContributionToPoint()
1030 for a given light, how much light/color reaches a given point in space (with no facing)
1031 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1034 int LightContributionToPoint( trace_t *trace )
1041 light = trace->light;
1044 VectorClear( trace->color );
1046 /* ydnar: early out */
1047 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1050 /* is this a sun? */
1051 if( light->type != EMIT_SUN )
1058 if( !ClusterVisible( trace->cluster, light->cluster ) )
1062 /* ydnar: check origin against light's pvs envelope */
1063 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1064 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1065 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1071 /* set light origin */
1072 if( light->type == EMIT_SUN )
1073 VectorAdd( trace->origin, light->origin, trace->end );
1075 VectorCopy( light->origin, trace->end );
1078 dist = SetupTrace( trace );
1081 if( dist > light->envelope )
1083 gridEnvelopeCulled++;
1087 /* ptpff approximation */
1088 if( light->type == EMIT_AREA && faster )
1090 /* clamp the distance to prevent super hot spots */
1095 add = light->photons / (dist * dist);
1098 /* exact point to polygon form factor */
1099 else if( light->type == EMIT_AREA )
1102 vec3_t pushedOrigin;
1105 /* see if the point is behind the light */
1106 d = DotProduct( trace->origin, light->normal ) - light->dist;
1107 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1110 /* nudge the point so that it is clearly forward of the light */
1111 /* so that surfaces meeting a light emiter don't get black edges */
1112 if( d > -8.0f && d < 8.0f )
1113 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1115 VectorCopy( trace->origin, pushedOrigin );
1117 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1118 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1119 if( factor == 0.0f )
1121 else if( factor < 0.0f )
1123 if( light->flags & LIGHT_TWOSIDED )
1129 /* ydnar: moved to here */
1130 add = factor * light->add;
1133 /* point/spot lights */
1134 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1136 /* clamp the distance to prevent super hot spots */
1141 if( light->flags & LIGHT_ATTEN_LINEAR )
1143 add = light->photons * linearScale - (dist * light->fade);
1148 add = light->photons / (dist * dist);
1150 /* handle spotlights */
1151 if( light->type == EMIT_SPOT )
1153 float distByNormal, radiusAtDist, sampleRadius;
1154 vec3_t pointAtDist, distToSample;
1157 /* do cone calculation */
1158 distByNormal = -DotProduct( trace->displacement, light->normal );
1159 if( distByNormal < 0.0f )
1161 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1162 radiusAtDist = light->radiusByDist * distByNormal;
1163 VectorSubtract( trace->origin, pointAtDist, distToSample );
1164 sampleRadius = VectorLength( distToSample );
1166 /* outside the cone */
1167 if( sampleRadius >= radiusAtDist )
1171 if( sampleRadius > (radiusAtDist - 32.0f) )
1172 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1176 /* ydnar: sunlight */
1177 else if( light->type == EMIT_SUN )
1180 add = light->photons;
1185 trace->testAll = qtrue;
1186 VectorScale( light->color, add, trace->color );
1188 /* trace to point */
1189 if( trace->testOcclusion && !trace->forceSunlight )
1193 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1195 VectorClear( trace->color );
1200 /* return to sender */
1204 /* unknown light type */
1208 /* ydnar: changed to a variable number */
1209 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1213 trace->testAll = qfalse;
1214 VectorScale( light->color, add, trace->color );
1218 if( trace->passSolid )
1220 VectorClear( trace->color );
1224 /* we have a valid sample */
1232 grid samples are for quickly determining the lighting
1233 of dynamically placed entities in the world
1236 #define MAX_CONTRIBUTIONS 1024
1246 void TraceGrid( int num )
1248 int i, j, x, y, z, mod, step, numCon, numStyles;
1250 vec3_t baseOrigin, cheapColor, color;
1252 bspGridPoint_t *bgp;
1253 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1257 /* get grid points */
1258 gp = &rawGridPoints[ num ];
1259 bgp = &bspGridPoints[ num ];
1261 /* get grid origin */
1263 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1264 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1265 y = mod / gridBounds[ 0 ];
1266 mod -= y * gridBounds[ 0 ];
1269 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1270 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1271 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1273 /* set inhibit sphere */
1274 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1275 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1276 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1277 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1279 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1281 /* find point cluster */
1282 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1283 if( trace.cluster < 0 )
1285 /* try to nudge the origin around to find a valid point */
1286 VectorCopy( trace.origin, baseOrigin );
1287 for( step = 9; step <= 18; step += 9 )
1289 for( i = 0; i < 8; i++ )
1291 VectorCopy( baseOrigin, trace.origin );
1293 trace.origin[ 0 ] += step;
1295 trace.origin[ 0 ] -= step;
1298 trace.origin[ 1 ] += step;
1300 trace.origin[ 1 ] -= step;
1303 trace.origin[ 2 ] += step;
1305 trace.origin[ 2 ] -= step;
1307 /* ydnar: changed to find cluster num */
1308 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1309 if( trace.cluster >= 0 )
1317 /* can't find a valid point at all */
1323 trace.testOcclusion = !noTrace;
1324 trace.forceSunlight = qfalse;
1325 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1326 trace.numSurfaces = 0;
1327 trace.surfaces = NULL;
1328 trace.numLights = 0;
1329 trace.lights = NULL;
1333 VectorClear( cheapColor );
1335 /* trace to all the lights, find the major light direction, and divide the
1336 total light between that along the direction and the remaining in the ambient */
1337 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1343 if( !LightContributionToPoint( &trace ) )
1346 /* handle negative light */
1347 if( trace.light->flags & LIGHT_NEGATIVE )
1348 VectorScale( trace.color, -1.0f, trace.color );
1350 /* add a contribution */
1351 VectorCopy( trace.color, contributions[ numCon ].color );
1352 VectorCopy( trace.direction, contributions[ numCon ].dir );
1353 contributions[ numCon ].style = trace.light->style;
1356 /* push average direction around */
1357 addSize = VectorLength( trace.color );
1358 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1360 /* stop after a while */
1361 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1364 /* ydnar: cheap mode */
1365 VectorAdd( cheapColor, trace.color, cheapColor );
1366 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1370 /* normalize to get primary light direction */
1371 VectorNormalize( gp->dir, gp->dir );
1373 /* now that we have identified the primary light direction,
1374 go back and separate all the light into directed and ambient */
1376 for( i = 0; i < numCon; i++ )
1378 /* get relative directed strength */
1379 d = DotProduct( contributions[ i ].dir, gp->dir );
1383 /* find appropriate style */
1384 for( j = 0; j < numStyles; j++ )
1386 if( gp->styles[ j ] == contributions[ i ].style )
1390 /* style not found? */
1391 if( j >= numStyles )
1393 /* add a new style */
1394 if( numStyles < MAX_LIGHTMAPS )
1396 gp->styles[ numStyles ] = contributions[ i ].style;
1397 bgp->styles[ numStyles ] = contributions[ i ].style;
1399 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1407 /* add the directed color */
1408 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1410 /* ambient light will be at 1/4 the value of directed light */
1411 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1412 d = 0.25f * (1.0f - d);
1413 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1417 /* store off sample */
1418 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1420 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1422 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1424 /* set minimum light and copy off to bytes */
1425 VectorCopy( gp->ambient[ i ], color );
1426 for( j = 0; j < 3; j++ )
1427 if( color[ j ] < minGridLight[ j ] )
1428 color[ j ] = minGridLight[ j ];
1429 ColorToBytes( color, bgp->ambient[ i ], 1.0f );
1430 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );
1435 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1436 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1438 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1439 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1442 /* store direction */
1443 NormalToLatLong( gp->dir, bgp->latLong );
1450 calculates the size of the lightgrid and allocates memory
1453 void SetupGrid( void )
1456 vec3_t maxs, oldGridSize;
1461 /* don't do this if not grid lighting */
1462 if( noGridLighting )
1465 /* ydnar: set grid size */
1466 value = ValueForKey( &entities[ 0 ], "gridsize" );
1467 if( value[ 0 ] != '\0' )
1468 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1471 VectorCopy( gridSize, oldGridSize );
1472 for( i = 0; i < 3; i++ )
1473 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1475 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1476 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1478 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1480 /* get world bounds */
1481 for( i = 0; i < 3; i++ )
1483 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1484 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1485 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1489 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1491 /* increase grid size a bit */
1492 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1493 gridSize[ j++ % 3 ] += 16.0f;
1497 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1500 if( !VectorCompare( gridSize, oldGridSize ) )
1502 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1503 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1504 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1507 /* 2nd variable. fixme: is this silly? */
1508 numBSPGridPoints = numRawGridPoints;
1510 /* allocate lightgrid */
1511 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1512 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1514 if( bspGridPoints != NULL )
1515 free( bspGridPoints );
1516 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1517 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1519 /* clear lightgrid */
1520 for( i = 0; i < numRawGridPoints; i++ )
1522 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1523 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1524 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1525 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1527 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1528 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1533 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1540 does what it says...
1543 void LightWorld( void )
1548 qboolean minVertex, minGrid;
1552 /* ydnar: smooth normals */
1555 Sys_Printf( "--- SmoothNormals ---\n" );
1559 /* determine the number of grid points */
1560 Sys_Printf( "--- SetupGrid ---\n" );
1563 /* find the optional minimum lighting values */
1564 GetVectorForKey( &entities[ 0 ], "_color", color );
1565 if( VectorLength( color ) == 0.0f )
1566 VectorSet( color, 1.0, 1.0, 1.0 );
1569 f = FloatForKey( &entities[ 0 ], "_ambient" );
1571 f = FloatForKey( &entities[ 0 ], "ambient" );
1572 VectorScale( color, f, ambientColor );
1574 /* minvertexlight */
1576 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1577 if( value[ 0 ] != '\0' )
1581 VectorScale( color, f, minVertexLight );
1586 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1587 if( value[ 0 ] != '\0' )
1591 VectorScale( color, f, minGridLight );
1595 value = ValueForKey( &entities[ 0 ], "_minlight" );
1596 if( value[ 0 ] != '\0' )
1599 VectorScale( color, f, minLight );
1600 if( minVertex == qfalse )
1601 VectorScale( color, f, minVertexLight );
1602 if( minGrid == qfalse )
1603 VectorScale( color, f, minGridLight );
1606 /* create world lights */
1607 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1608 CreateEntityLights();
1609 CreateSurfaceLights();
1610 Sys_Printf( "%9d point lights\n", numPointLights );
1611 Sys_Printf( "%9d spotlights\n", numSpotLights );
1612 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1613 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1615 /* calculate lightgrid */
1616 if( !noGridLighting )
1618 /* ydnar: set up light envelopes */
1619 SetupEnvelopes( qtrue, fastgrid );
1621 Sys_Printf( "--- TraceGrid ---\n" );
1622 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1623 Sys_Printf( "%d x %d x %d = %d grid\n",
1624 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1626 /* ydnar: emit statistics on light culling */
1627 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1628 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1631 /* slight optimization to remove a sqrt */
1632 subdivideThreshold *= subdivideThreshold;
1634 /* map the world luxels */
1635 Sys_Printf( "--- MapRawLightmap ---\n" );
1636 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1637 Sys_Printf( "%9d luxels\n", numLuxels );
1638 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1639 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1641 /* ydnar: set up light envelopes */
1642 SetupEnvelopes( qfalse, fast );
1644 /* light up my world */
1645 lightsPlaneCulled = 0;
1646 lightsEnvelopeCulled = 0;
1647 lightsBoundsCulled = 0;
1648 lightsClusterCulled = 0;
1650 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1651 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1652 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1654 StitchSurfaceLightmaps();
1656 Sys_Printf( "--- IlluminateVertexes ---\n" );
1657 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1658 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1660 /* ydnar: emit statistics on light culling */
1661 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1662 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1663 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1664 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1671 /* store off the bsp between bounces */
1672 StoreSurfaceLightmaps();
1673 Sys_Printf( "Writing %s\n", source );
1674 WriteBSPFile( source );
1677 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1681 VectorClear( ambientColor );
1683 /* generate diffuse lights */
1685 RadCreateDiffuseLights();
1687 /* setup light envelopes */
1688 SetupEnvelopes( qfalse, fastbounce );
1689 if( numLights == 0 )
1691 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1695 /* add to lightgrid */
1698 gridEnvelopeCulled = 0;
1699 gridBoundsCulled = 0;
1701 Sys_Printf( "--- BounceGrid ---\n" );
1702 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1703 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1704 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1707 /* light up my world */
1708 lightsPlaneCulled = 0;
1709 lightsEnvelopeCulled = 0;
1710 lightsBoundsCulled = 0;
1711 lightsClusterCulled = 0;
1713 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1714 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1715 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1716 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1718 StitchSurfaceLightmaps();
1720 Sys_Printf( "--- IlluminateVertexes ---\n" );
1721 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1722 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1724 /* ydnar: emit statistics on light culling */
1725 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1726 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1727 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1728 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1740 main routine for light processing
1743 int LightMain( int argc, char **argv )
1747 char mapSource[ 1024 ];
1752 Sys_Printf( "--- Light ---\n" );
1754 /* process commandline arguments */
1755 for( i = 1; i < (argc - 1); i++ )
1757 /* lightsource scaling */
1758 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
1760 f = atof( argv[ i + 1 ] );
1762 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1766 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
1768 f = atof( argv[ i + 1 ] );
1770 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1774 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
1776 f = atof( argv[ i + 1 ] );
1778 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1782 else if( !strcmp( argv[ i ], "-bouncescale" ) )
1784 f = atof( argv[ i + 1 ] );
1786 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
1790 else if( !strcmp( argv[ i ], "-scale" ) )
1792 f = atof( argv[ i + 1 ] );
1797 Sys_Printf( "All light scaled by %f\n", f );
1801 /* ydnar switches */
1802 else if( !strcmp( argv[ i ], "-bounce" ) )
1804 bounce = atoi( argv[ i + 1 ] );
1807 else if( bounce > 0 )
1808 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
1812 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
1814 superSample = atoi( argv[ i + 1 ] );
1815 if( superSample < 1 )
1817 else if( superSample > 1 )
1818 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
1822 else if( !strcmp( argv[ i ], "-samples" ) )
1824 lightSamples = atoi( argv[ i + 1 ] );
1825 if( lightSamples < 1 )
1827 else if( lightSamples > 1 )
1828 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
1832 else if( !strcmp( argv[ i ], "-filter" ) )
1835 Sys_Printf( "Lightmap filtering enabled\n" );
1838 else if( !strcmp( argv[ i ], "-shadeangle" ) )
1840 shadeAngleDegrees = atof( argv[ i + 1 ] );
1841 if( shadeAngleDegrees < 0.0f )
1842 shadeAngleDegrees = 0.0f;
1843 else if( shadeAngleDegrees > 0.0f )
1846 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
1851 else if( !strcmp( argv[ i ], "-thresh" ) )
1853 subdivideThreshold = atof( argv[ i + 1 ] );
1854 if( subdivideThreshold < 0 )
1855 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
1857 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
1861 else if( !strcmp( argv[ i ], "-approx" ) )
1863 approximateTolerance = atoi( argv[ i + 1 ] );
1864 if( approximateTolerance < 0 )
1865 approximateTolerance = 0;
1866 else if( approximateTolerance > 0 )
1867 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
1871 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
1874 Sys_Printf( "Generating deluxemaps for average light direction\n" );
1877 else if( !strcmp( argv[ i ], "-external" ) )
1879 externalLightmaps = qtrue;
1880 Sys_Printf( "Storing all lightmaps externally\n" );
1883 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
1885 lmCustomSize = atoi( argv[ i + 1 ] );
1887 /* must be a power of 2 and greater than 2 */
1888 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
1890 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
1891 lmCustomSize = LIGHTMAP_WIDTH;
1894 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
1896 /* enable external lightmaps */
1897 if( lmCustomSize != LIGHTMAP_WIDTH )
1899 externalLightmaps = qtrue;
1900 Sys_Printf( "Storing all lightmaps externally\n" );
1904 /* ydnar: add this to suppress warnings */
1905 else if( !strcmp( argv[ i ], "-custinfoparms") )
1907 Sys_Printf( "Custom info parms enabled\n" );
1908 useCustomInfoParms = qtrue;
1911 else if( !strcmp( argv[ i ], "-wolf" ) )
1913 /* -game should already be set */
1914 game->wolfLight = qtrue;
1915 Sys_Printf( "Enabling Wolf lighting model\n" );
1918 else if( !strcmp( argv[ i ], "-sunonly" ) )
1921 Sys_Printf( "Only computing sunlight\n" );
1924 else if( !strcmp( argv[ i ], "-bounceonly" ) )
1927 Sys_Printf( "Storing bounced light (radiosity) only\n" );
1930 else if( !strcmp( argv[ i ], "-nocollapse" ) )
1933 Sys_Printf( "Identical lightmap collapsing disabled\n" );
1936 else if( !strcmp( argv[ i ], "-shade" ) )
1939 Sys_Printf( "Phong shading enabled\n" );
1942 else if( !strcmp( argv[ i ], "-bouncegrid") )
1946 Sys_Printf( "Grid lighting with radiosity enabled\n" );
1949 else if( !strcmp( argv[ i ], "-smooth" ) )
1952 lightSamples = EXTRA_SCALE;
1953 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
1956 else if( !strcmp( argv[ i ], "-fast" ) )
1961 Sys_Printf( "Fast mode enabled\n" );
1964 else if( !strcmp( argv[ i ], "-faster" ) )
1970 Sys_Printf( "Faster mode enabled\n" );
1973 else if( !strcmp( argv[ i ], "-fastgrid" ) )
1976 Sys_Printf( "Fast grid lighting enabled\n" );
1979 else if( !strcmp( argv[ i ], "-fastbounce" ) )
1982 Sys_Printf( "Fast bounce mode enabled\n" );
1985 else if( !strcmp( argv[ i ], "-cheap" ) )
1989 Sys_Printf( "Cheap mode enabled\n" );
1992 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
1995 Sys_Printf( "Cheap grid mode enabled\n" );
1998 else if( !strcmp( argv[ i ], "-normalmap" ) )
2001 Sys_Printf( "Storing normal map instead of lightmap\n" );
2004 else if( !strcmp( argv[ i ], "-trisoup" ) )
2007 Sys_Printf( "Converting brush faces to triangle soup\n" );
2010 else if( !strcmp( argv[ i ], "-debug" ) )
2013 Sys_Printf( "Lightmap debugging enabled\n" );
2016 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2018 debugSurfaces = qtrue;
2019 Sys_Printf( "Lightmap surface debugging enabled\n" );
2022 else if( !strcmp( argv[ i ], "-debugunused" ) )
2024 debugUnused = qtrue;
2025 Sys_Printf( "Unused luxel debugging enabled\n" );
2028 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2031 Sys_Printf( "Lightmap axis debugging enabled\n" );
2034 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2036 debugCluster = qtrue;
2037 Sys_Printf( "Luxel cluster debugging enabled\n" );
2040 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2042 debugOrigin = qtrue;
2043 Sys_Printf( "Luxel origin debugging enabled\n" );
2046 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2049 debugDeluxemap = qtrue;
2050 Sys_Printf( "Deluxemap debugging enabled\n" );
2053 else if( !strcmp( argv[ i ], "-export" ) )
2055 exportLightmaps = qtrue;
2056 Sys_Printf( "Exporting lightmaps\n" );
2059 else if( !strcmp(argv[ i ], "-notrace" ))
2062 Sys_Printf( "Shadow occlusion disabled\n" );
2064 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2066 patchShadows = qtrue;
2067 Sys_Printf( "Patch shadow casting enabled\n" );
2069 else if( !strcmp( argv[ i ], "-extra" ) )
2072 superSample = EXTRA_SCALE; /* ydnar */
2073 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2075 else if( !strcmp( argv[ i ], "-extrawide" ) )
2079 superSample = EXTRAWIDE_SCALE; /* ydnar */
2080 filter = qtrue; /* ydnar */
2081 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2083 else if( !strcmp( argv[ i ], "-samplesize" ) )
2085 sampleSize = atoi( argv[ i + 1 ] );
2086 if( sampleSize < 1 )
2089 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2091 else if( !strcmp( argv[ i ], "-novertex" ) )
2093 noVertexLighting = qtrue;
2094 Sys_Printf( "Disabling vertex lighting\n" );
2096 else if( !strcmp( argv[ i ], "-nogrid" ) )
2098 noGridLighting = qtrue;
2099 Sys_Printf( "Disabling grid lighting\n" );
2101 else if( !strcmp( argv[ i ], "-border" ) )
2103 lightmapBorder = qtrue;
2104 Sys_Printf( "Adding debug border to lightmaps\n" );
2106 else if( !strcmp( argv[ i ], "-nosurf" ) )
2109 Sys_Printf( "Not tracing against surfaces\n" );
2111 else if( !strcmp( argv[ i ], "-dump" ) )
2114 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2116 else if( !strcmp( argv[ i ], "-lomem" ) )
2119 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2123 Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
2126 /* clean up map name */
2127 strcpy( source, ExpandArg( argv[ i ] ) );
2128 StripExtension( source );
2129 DefaultExtension( source, ".bsp" );
2130 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2131 StripExtension( mapSource );
2132 DefaultExtension( mapSource, ".map" );
2134 /* ydnar: set default sample size */
2135 SetDefaultSampleSize( sampleSize );
2137 /* ydnar: handle shaders */
2138 BeginMapShaderFile( source );
2142 Sys_Printf( "Loading %s\n", source );
2144 /* ydnar: load surface file */
2145 LoadSurfaceExtraFile( source );
2148 LoadBSPFile( source );
2150 /* parse bsp entities */
2154 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2155 if( value[ 0 ] != '1' )
2156 LoadMapFile( mapSource, qtrue );
2158 /* set the entity/model origins and init yDrawVerts */
2161 /* ydnar: set up optimization */
2163 SetupSurfaceLightmaps();
2165 /* initialize the surface facet tracing */
2168 /* light the world */
2171 /* ydnar: store off lightmaps */
2172 StoreSurfaceLightmaps();
2174 /* write out the bsp */
2176 Sys_Printf( "Writing %s\n", source );
2177 WriteBSPFile( source );
2179 /* ydnar: export lightmaps */
2180 if( exportLightmaps && !externalLightmaps )
2183 /* return to sender */