1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
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.
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.
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
22 ----------------------------------------------------------------------------------
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."
27 ------------------------------------------------------------------------------- */
42 CreateSunLight() - ydnar
43 this creates a sun light
46 static void CreateSunLight( sun_t *sun )
49 float photons, d, angle, elevation, da, de;
59 if( sun->numSamples < 1 )
63 photons = sun->photons / sun->numSamples;
65 /* create the right number of suns */
66 for( i = 0; i < sun->numSamples; i++ )
68 /* calculate sun direction */
70 VectorCopy( sun->direction, direction );
74 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
75 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
76 sun->direction[ 2 ] = sin( elevation );
78 xz_dist = sqrt( x*x + z*z )
79 latitude = atan2( xz_dist, y ) * RADIANS
80 longitude = atan2( x, z ) * RADIANS
83 d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
84 angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
85 elevation = atan2( sun->direction[ 2 ], d );
87 /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
90 da = (Random() * 2.0f - 1.0f) * sun->deviance;
91 de = (Random() * 2.0f - 1.0f) * sun->deviance;
93 while( (da * da + de * de) > (sun->deviance * sun->deviance) );
98 //% Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
100 /* create new vector */
101 direction[ 0 ] = cos( angle ) * cos( elevation );
102 direction[ 1 ] = sin( angle ) * cos( elevation );
103 direction[ 2 ] = sin( elevation );
108 light = safe_malloc( sizeof( *light ) );
109 memset( light, 0, sizeof( *light ) );
110 light->next = lights;
113 /* initialize the light */
114 light->flags = LIGHT_SUN_DEFAULT;
115 light->type = EMIT_SUN;
117 light->falloffTolerance = falloffTolerance;
118 light->filterRadius = sun->filterRadius / sun->numSamples;
119 light->style = noStyles ? LS_NORMAL : sun->style;
121 /* set the light's position out to infinity */
122 VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin ); /* MAX_WORLD_COORD * 2.0f */
124 /* set the facing to be the inverse of the sun direction */
125 VectorScale( direction, -1.0, light->normal );
126 light->dist = DotProduct( light->origin, light->normal );
128 /* set color and photons */
129 VectorCopy( sun->color, light->color );
130 light->photons = photons * skyScale;
134 if( sun->next != NULL )
135 CreateSunLight( sun->next );
141 CreateSkyLights() - ydnar
142 simulates sky light with multiple suns
145 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius, int style )
148 int angleSteps, elevationSteps;
149 float angle, elevation;
150 float angleStep, elevationStep;
155 if( value <= 0.0f || iterations < 2 )
158 /* basic sun setup */
159 VectorCopy( color, sun.color );
161 sun.filterRadius = filterRadius;
163 sun.style = noStyles ? LS_NORMAL : style;
167 elevationSteps = iterations - 1;
168 angleSteps = elevationSteps * 4;
170 elevationStep = DEG2RAD( 90.0f / iterations ); /* skip elevation 0 */
171 angleStep = DEG2RAD( 360.0f / angleSteps );
173 /* calc individual sun brightness */
174 numSuns = angleSteps * elevationSteps + 1;
175 sun.photons = value / numSuns;
177 /* iterate elevation */
178 elevation = elevationStep * 0.5f;
180 for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
183 for( j = 0; j < angleSteps; j++ )
186 sun.direction[ 0 ] = cos( angle ) * cos( elevation );
187 sun.direction[ 1 ] = sin( angle ) * cos( elevation );
188 sun.direction[ 2 ] = sin( elevation );
189 CreateSunLight( &sun );
196 elevation += elevationStep;
197 angle += angleStep / elevationSteps;
200 /* create vertical sun */
201 VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
202 CreateSunLight( &sun );
212 creates lights from light entities
215 void CreateEntityLights( void )
218 light_t *light, *light2;
224 float intensity, scale, deviance, filterRadius;
225 int spawnflags, flags, numSamples;
229 /* go throught entity list and find lights */
230 for( i = 0; i < numEntities; i++ )
234 name = ValueForKey( e, "classname" );
236 /* ydnar: check for lightJunior */
237 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
239 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
244 /* lights with target names (and therefore styles) are only parsed from BSP */
245 target = ValueForKey( e, "targetname" );
246 if( target[ 0 ] != '\0' && i >= numBSPEntities )
251 light = safe_malloc( sizeof( *light ) );
252 memset( light, 0, sizeof( *light ) );
253 light->next = lights;
256 /* handle spawnflags */
257 spawnflags = IntForKey( e, "spawnflags" );
259 /* ydnar: quake 3+ light behavior */
260 if( wolfLight == qfalse )
262 /* set default flags */
263 flags = LIGHT_Q3A_DEFAULT;
265 /* linear attenuation? */
268 flags |= LIGHT_ATTEN_LINEAR;
269 flags &= ~LIGHT_ATTEN_ANGLE;
272 /* no angle attenuate? */
274 flags &= ~LIGHT_ATTEN_ANGLE;
277 /* ydnar: wolf light behavior */
280 /* set default flags */
281 flags = LIGHT_WOLF_DEFAULT;
283 /* inverse distance squared attenuation? */
286 flags &= ~LIGHT_ATTEN_LINEAR;
287 flags |= LIGHT_ATTEN_ANGLE;
290 /* angle attenuate? */
292 flags |= LIGHT_ATTEN_ANGLE;
295 /* other flags (borrowed from wolf) */
297 /* wolf dark light? */
298 if( (spawnflags & 4) || (spawnflags & 8) )
302 if( spawnflags & 16 )
303 flags &= ~LIGHT_GRID;
309 flags &= ~LIGHT_SURFACES;
312 /* vortex: unnormalized? */
314 flags |= LIGHT_UNNORMALIZED;
316 /* vortex: distance atten? */
318 flags |= LIGHT_ATTEN_DISTANCE;
320 /* store the flags */
321 light->flags = flags;
323 /* ydnar: set fade key (from wolf) */
325 if( light->flags & LIGHT_ATTEN_LINEAR )
327 light->fade = FloatForKey( e, "fade" );
328 if( light->fade == 0.0f )
332 /* ydnar: set angle scaling (from vlight) */
333 light->angleScale = FloatForKey( e, "_anglescale" );
334 if( light->angleScale != 0.0f )
335 light->flags |= LIGHT_ATTEN_ANGLE;
338 GetVectorForKey( e, "origin", light->origin);
339 light->style = IntForKey( e, "_style" );
340 if( light->style == LS_NORMAL )
341 light->style = IntForKey( e, "style" );
342 if( light->style < LS_NORMAL || light->style >= LS_NONE )
343 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
345 if( light->style != LS_NORMAL ) {
346 Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
349 /* set light intensity */
350 intensity = FloatForKey( e, "_light" );
351 if( intensity == 0.0f )
352 intensity = FloatForKey( e, "light" );
353 if( intensity == 0.0f)
356 /* ydnar: set light scale (sof2) */
357 scale = FloatForKey( e, "scale" );
362 /* ydnar: get deviance and samples */
363 deviance = FloatForKey( e, "_deviance" );
364 if( deviance == 0.0f )
365 deviance = FloatForKey( e, "_deviation" );
366 if( deviance == 0.0f )
367 deviance = FloatForKey( e, "_jitter" );
368 numSamples = IntForKey( e, "_samples" );
369 if( deviance < 0.0f || numSamples < 1 )
374 intensity /= numSamples;
376 /* ydnar: get filter radius */
377 filterRadius = FloatForKey( e, "_filterradius" );
378 if( filterRadius == 0.0f )
379 filterRadius = FloatForKey( e, "_filteradius" );
380 if( filterRadius == 0.0f )
381 filterRadius = FloatForKey( e, "_filter" );
382 if( filterRadius < 0.0f )
384 light->filterRadius = filterRadius;
386 /* set light color */
387 _color = ValueForKey( e, "_color" );
388 if( _color && _color[ 0 ] )
390 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
391 if (!(light->flags & LIGHT_UNNORMALIZED))
393 ColorNormalize( light->color, light->color );
397 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
399 light->extraDist = FloatForKey( e, "_extradist" );
400 if(light->extraDist == 0.0f)
401 light->extraDist = extraDist;
403 light->photons = intensity;
405 light->type = EMIT_POINT;
407 /* set falloff threshold */
408 light->falloffTolerance = falloffTolerance / numSamples;
410 /* lights with a target will be spotlights */
411 target = ValueForKey( e, "target" );
421 e2 = FindTargetEntity( target );
424 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
425 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
426 light->photons *= pointScale;
430 /* not a point light */
434 /* make a spotlight */
435 GetVectorForKey( e2, "origin", dest );
436 VectorSubtract( dest, light->origin, light->normal );
437 dist = VectorNormalize( light->normal, light->normal );
438 radius = FloatForKey( e, "radius" );
443 light->radiusByDist = (radius + 16) / dist;
444 light->type = EMIT_SPOT;
446 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
447 light->flags &= ~LIGHT_ATTEN_LINEAR;
448 light->flags |= LIGHT_ATTEN_ANGLE;
451 /* ydnar: is this a sun? */
452 _sun = ValueForKey( e, "_sun" );
453 if( _sun[ 0 ] == '1' )
455 /* not a spot light */
458 /* unlink this light */
459 lights = light->next;
462 VectorScale( light->normal, -1.0f, sun.direction );
463 VectorCopy( light->color, sun.color );
464 sun.photons = intensity;
465 sun.deviance = deviance / 180.0f * Q_PI;
466 sun.numSamples = numSamples;
467 sun.style = noStyles ? LS_NORMAL : light->style;
470 /* make a sun light */
471 CreateSunLight( &sun );
473 /* free original light */
477 /* skip the rest of this love story */
482 light->photons *= spotScale;
487 light->photons *= pointScale;
489 /* jitter the light */
490 for( j = 1; j < numSamples; j++ )
493 light2 = safe_malloc( sizeof( *light ) );
494 memcpy( light2, light, sizeof( *light ) );
495 light2->next = lights;
499 if( light->type == EMIT_SPOT )
505 light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
506 light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
507 light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
515 CreateSurfaceLights() - ydnar
516 this hijacks the radiosity code to generate surface lights for first pass
519 #define APPROX_BOUNCE 1.0f
521 void CreateSurfaceLights( void )
524 bspDrawSurface_t *ds;
534 /* get sun shader supressor */
535 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
537 /* walk the list of surfaces */
538 for( i = 0; i < numBSPDrawSurfaces; i++ )
540 /* get surface and other bits */
541 ds = &bspDrawSurfaces[ i ];
542 info = &surfaceInfos[ i ];
546 if( si->sun != NULL && nss[ 0 ] != '1' )
548 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
549 CreateSunLight( si->sun );
550 si->sun = NULL; /* FIXME: leak! */
554 if( si->skyLightValue > 0.0f )
556 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
557 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
558 si->skyLightValue = 0.0f; /* FIXME: hack! */
561 /* try to early out */
565 /* autosprite shaders become point lights */
568 /* create an average xyz */
569 VectorAdd( info->mins, info->maxs, origin );
570 VectorScale( origin, 0.5f, origin );
573 light = safe_malloc( sizeof( *light ) );
574 memset( light, 0, sizeof( *light ) );
575 light->next = lights;
579 light->flags = LIGHT_Q3A_DEFAULT;
580 light->type = EMIT_POINT;
581 light->photons = si->value * pointScale;
584 VectorCopy( origin, light->origin );
585 VectorCopy( si->color, light->color );
586 light->falloffTolerance = falloffTolerance;
587 light->style = si->lightStyle;
589 /* add to point light count and continue */
594 /* get subdivision amount */
595 if( si->lightSubdivide > 0 )
596 subdivide = si->lightSubdivide;
598 subdivide = defaultLightSubdivide;
601 switch( ds->surfaceType )
604 case MST_TRIANGLE_SOUP:
605 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
609 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
622 find the offset values for inline models
625 void SetEntityOrigins( void )
633 bspDrawSurface_t *ds;
636 /* ydnar: copy drawverts into private storage for nefarious purposes */
637 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
638 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
640 /* set the entity origins */
641 for( i = 0; i < numEntities; i++ )
643 /* get entity and model */
645 key = ValueForKey( e, "model" );
646 if( key[ 0 ] != '*' )
648 modelnum = atoi( key + 1 );
649 dm = &bspModels[ modelnum ];
651 /* get entity origin */
652 key = ValueForKey( e, "origin" );
653 if( key[ 0 ] == '\0' )
655 GetVectorForKey( e, "origin", origin );
657 /* set origin for all surfaces for this model */
658 for( j = 0; j < dm->numBSPSurfaces; j++ )
661 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
664 for( k = 0; k < ds->numVerts; k++ )
666 f = ds->firstVert + k;
667 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
676 PointToPolygonFormFactor()
677 calculates the area over a point/normal hemisphere a winding covers
678 ydnar: fixme: there has to be a faster way to calculate this
679 without the expensive per-vert sqrts and transcendental functions
680 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
681 between this and the approximation
684 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
686 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
688 vec3_t triVector, triNormal;
690 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
692 float dot, angle, facing;
695 /* this is expensive */
696 for( i = 0; i < w->numpoints; i++ )
698 VectorSubtract( w->p[ i ], point, dirs[ i ] );
699 VectorNormalize( dirs[ i ], dirs[ i ] );
702 /* duplicate first vertex to avoid mod operation */
703 VectorCopy( dirs[ 0 ], dirs[ i ] );
705 /* calculcate relative area */
707 for( i = 0; i < w->numpoints; i++ )
711 dot = DotProduct( dirs[ i ], dirs[ j ] );
713 /* roundoff can cause slight creep, which gives an IND from acos */
716 else if( dot < -1.0f )
722 CrossProduct( dirs[ i ], dirs[ j ], triVector );
723 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
726 facing = DotProduct( normal, triNormal );
727 total += facing * angle;
729 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
730 if( total > 6.3f || total < -6.3f )
734 /* now in the range of 0 to 1 over the entire incoming hemisphere */
735 //% total /= (2.0f * 3.141592657f);
736 total *= ONE_OVER_2PI;
743 LightContributionTosample()
744 determines the amount of light reaching a sample (luxel or vertex) from a given light
747 int LightContributionToSample( trace_t *trace )
753 float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
754 qboolean angledDeluxe = qtrue;
755 float colorBrightness;
756 qboolean doAddDeluxe = qtrue;
759 light = trace->light;
762 trace->forceSubsampling = 0.0f; /* to make sure */
763 VectorClear( trace->color );
764 VectorClear( trace->colorNoShadow );
765 VectorClear( trace->directionContribution );
767 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
769 /* ydnar: early out */
770 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
773 /* do some culling checks */
774 if( light->type != EMIT_SUN )
776 /* MrE: if the light is behind the surface */
777 if( trace->twoSided == qfalse )
778 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
781 /* ydnar: test pvs */
782 if( !ClusterVisible( trace->cluster, light->cluster ) )
786 /* exact point to polygon form factor */
787 if( light->type == EMIT_AREA )
793 /* project sample point into light plane */
794 d = DotProduct( trace->origin, light->normal ) - light->dist;
797 /* sample point behind plane? */
798 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
801 /* sample plane coincident? */
802 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
806 /* nudge the point so that it is clearly forward of the light */
807 /* so that surfaces meeting a light emitter don't get black edges */
808 if( d > -8.0f && d < 8.0f )
809 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
811 VectorCopy( trace->origin, pushedOrigin );
813 /* get direction and distance */
814 VectorCopy( light->origin, trace->end );
815 dist = SetupTrace( trace );
816 if( dist >= light->envelope )
819 /* ptpff approximation */
822 /* angle attenuation */
823 angle = DotProduct( trace->normal, trace->direction );
825 /* twosided lighting */
826 if( trace->twoSided && angle < 0 )
830 /* no deluxemap contribution from "other side" light */
831 doAddDeluxe = qfalse;
835 angle *= -DotProduct( light->normal, trace->direction );
838 else if( angle < 0.0f &&
839 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
843 /* no deluxemap contribution from "other side" light */
844 doAddDeluxe = qfalse;
847 /* clamp the distance to prevent super hot spots */
848 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
852 add = light->photons / (dist * dist) * angle;
857 addDeluxe = light->photons / (dist * dist) * angle;
859 addDeluxe = light->photons / (dist * dist);
864 /* calculate the contribution */
865 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
868 else if( factor < 0.0f )
870 /* twosided lighting */
871 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
875 /* push light origin to other side of the plane */
876 VectorMA( light->origin, -2.0f, light->normal, trace->end );
877 dist = SetupTrace( trace );
878 if( dist >= light->envelope )
881 /* no deluxemap contribution from "other side" light */
882 doAddDeluxe = qfalse;
888 /* also don't deluxe if the direction is on the wrong side */
889 if(DotProduct(trace->normal, trace->direction) < 0)
891 /* no deluxemap contribution from "other side" light */
892 doAddDeluxe = qfalse;
895 /* ydnar: moved to here */
896 add = factor * light->add;
903 /* point/spot lights */
904 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
906 /* get direction and distance */
907 VectorCopy( light->origin, trace->end );
908 dist = SetupTrace( trace );
909 if( dist >= light->envelope )
912 /* clamp the distance to prevent super hot spots */
913 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
917 /* angle attenuation */
918 if( light->flags & LIGHT_ATTEN_ANGLE )
920 /* standard Lambert attenuation */
921 float dot = DotProduct( trace->normal, trace->direction );
923 /* twosided lighting */
924 if( trace->twoSided && dot < 0 )
928 /* no deluxemap contribution from "other side" light */
929 doAddDeluxe = qfalse;
932 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
935 if( dot > 0.001f ) // skip coplanar
937 if( dot > 1.0f ) dot = 1.0f;
938 dot = ( dot * 0.5f ) + 0.5f;
950 if( light->angleScale != 0.0f )
952 angle /= light->angleScale;
958 if( light->flags & LIGHT_ATTEN_LINEAR )
960 add = angle * light->photons * linearScale - (dist * light->fade);
967 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
969 addDeluxe = light->photons * linearScale - (dist * light->fade);
971 if( addDeluxe < 0.0f )
977 add = (light->photons / (dist * dist)) * angle;
984 addDeluxe = (light->photons / (dist * dist)) * angle;
986 addDeluxe = (light->photons / (dist * dist));
989 if( addDeluxe < 0.0f )
993 /* handle spotlights */
994 if( light->type == EMIT_SPOT )
996 float distByNormal, radiusAtDist, sampleRadius;
997 vec3_t pointAtDist, distToSample;
999 /* do cone calculation */
1000 distByNormal = -DotProduct( trace->displacement, light->normal );
1001 if( distByNormal < 0.0f )
1003 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1004 radiusAtDist = light->radiusByDist * distByNormal;
1005 VectorSubtract( trace->origin, pointAtDist, distToSample );
1006 sampleRadius = VectorLength( distToSample );
1008 /* outside the cone */
1009 if( sampleRadius >= radiusAtDist )
1013 if( sampleRadius > (radiusAtDist - 32.0f) )
1015 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1019 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1021 if( addDeluxe < 0.0f )
1027 /* ydnar: sunlight */
1028 else if( light->type == EMIT_SUN )
1030 /* get origin and direction */
1031 VectorAdd( trace->origin, light->origin, trace->end );
1032 dist = SetupTrace( trace );
1034 /* angle attenuation */
1035 if( light->flags & LIGHT_ATTEN_ANGLE )
1037 /* standard Lambert attenuation */
1038 float dot = DotProduct( trace->normal, trace->direction );
1040 /* twosided lighting */
1041 if( trace->twoSided && dot < 0 )
1045 /* no deluxemap contribution from "other side" light */
1046 doAddDeluxe = qfalse;
1049 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1052 if( dot > 0.001f ) // skip coplanar
1054 if( dot > 1.0f ) dot = 1.0f;
1055 dot = ( dot * 0.5f ) + 0.5f;
1068 add = light->photons * angle;
1073 addDeluxe = light->photons * angle;
1075 addDeluxe = light->photons;
1077 if( addDeluxe < 0.0f )
1084 /* VorteX: set noShadow color */
1085 VectorScale(light->color, add, trace->colorNoShadow);
1087 addDeluxe *= colorBrightness;
1091 addDeluxe *= addDeluxeBounceScale;
1092 if( addDeluxe < 0.00390625f )
1093 addDeluxe = 0.00390625f;
1096 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1099 trace->testAll = qtrue;
1100 VectorScale( light->color, add, trace->color );
1102 /* trace to point */
1103 if( trace->testOcclusion && !trace->forceSunlight )
1107 trace->forceSubsampling *= add;
1108 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1110 VectorClear( trace->color );
1111 VectorClear( trace->directionContribution );
1117 /* return to sender */
1121 Error("Light of undefined type!");
1123 /* VorteX: set noShadow color */
1124 VectorScale(light->color, add, trace->colorNoShadow);
1126 /* ydnar: changed to a variable number */
1127 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1130 addDeluxe *= colorBrightness;
1132 /* hack land: scale down the radiosity contribution to light directionality.
1133 Deluxemaps fusion many light directions into one. In a rtl process all lights
1134 would contribute individually to the bump map, so several light sources together
1135 would make it more directional (example: a yellow and red lights received from
1136 opposing sides would light one side in red and the other in blue, adding
1137 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1138 neutralize each other making it look like having no direction.
1139 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1140 is modifying the direction applied from directional lights, making it go closer and closer
1141 to the surface normal the bigger is the amount of radiosity received.
1142 So, for preserving the directional lights contributions, we scale down the radiosity
1143 contribution. It's a hack, but there's a reason behind it */
1146 addDeluxe *= addDeluxeBounceScale;
1147 /* better NOT increase it beyond the original value
1148 if( addDeluxe < 0.00390625f )
1149 addDeluxe = 0.00390625f;
1155 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1159 trace->testAll = qfalse;
1160 VectorScale( light->color, add, trace->color );
1164 trace->forceSubsampling *= add;
1165 if( trace->passSolid || trace->opaque )
1167 VectorClear( trace->color );
1168 VectorClear( trace->directionContribution );
1173 /* return to sender */
1181 determines the amount of light reaching a sample (luxel or vertex)
1184 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1190 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1191 VectorClear( colors[ lightmapNum ] );
1193 /* ydnar: normalmap */
1196 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1197 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1198 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1202 /* ydnar: don't bounce ambient all the time */
1204 VectorCopy( ambientColor, colors[ 0 ] );
1206 /* ydnar: trace to all the list of lights pre-stored in tw */
1207 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1210 trace->light = trace->lights[ i ];
1213 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1215 if( styles[ lightmapNum ] == trace->light->style ||
1216 styles[ lightmapNum ] == LS_NONE )
1220 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1221 if( lightmapNum >= MAX_LIGHTMAPS )
1225 LightContributionToSample( trace );
1226 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1229 /* handle negative light */
1230 if( trace->light->flags & LIGHT_NEGATIVE )
1231 VectorScale( trace->color, -1.0f, trace->color );
1234 styles[ lightmapNum ] = trace->light->style;
1237 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1241 colors[ 0 ][ 0 ] >= 255.0f &&
1242 colors[ 0 ][ 1 ] >= 255.0f &&
1243 colors[ 0 ][ 2 ] >= 255.0f )
1251 LightContributionToPoint()
1252 for a given light, how much light/color reaches a given point in space (with no facing)
1253 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1256 int LightContributionToPoint( trace_t *trace )
1263 light = trace->light;
1266 VectorClear( trace->color );
1268 /* ydnar: early out */
1269 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1272 /* is this a sun? */
1273 if( light->type != EMIT_SUN )
1280 if( !ClusterVisible( trace->cluster, light->cluster ) )
1284 /* ydnar: check origin against light's pvs envelope */
1285 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1286 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1287 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1293 /* set light origin */
1294 if( light->type == EMIT_SUN )
1295 VectorAdd( trace->origin, light->origin, trace->end );
1297 VectorCopy( light->origin, trace->end );
1300 dist = SetupTrace( trace );
1303 if( dist > light->envelope )
1305 gridEnvelopeCulled++;
1309 /* ptpff approximation */
1310 if( light->type == EMIT_AREA && faster )
1312 /* clamp the distance to prevent super hot spots */
1313 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1318 add = light->photons / (dist * dist);
1321 /* exact point to polygon form factor */
1322 else if( light->type == EMIT_AREA )
1325 vec3_t pushedOrigin;
1328 /* see if the point is behind the light */
1329 d = DotProduct( trace->origin, light->normal ) - light->dist;
1330 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1333 /* nudge the point so that it is clearly forward of the light */
1334 /* so that surfaces meeting a light emiter don't get black edges */
1335 if( d > -8.0f && d < 8.0f )
1336 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1338 VectorCopy( trace->origin, pushedOrigin );
1340 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1341 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1342 if( factor == 0.0f )
1344 else if( factor < 0.0f )
1346 if( light->flags & LIGHT_TWOSIDED )
1352 /* ydnar: moved to here */
1353 add = factor * light->add;
1356 /* point/spot lights */
1357 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1359 /* clamp the distance to prevent super hot spots */
1360 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1365 if( light->flags & LIGHT_ATTEN_LINEAR )
1367 add = light->photons * linearScale - (dist * light->fade);
1372 add = light->photons / (dist * dist);
1374 /* handle spotlights */
1375 if( light->type == EMIT_SPOT )
1377 float distByNormal, radiusAtDist, sampleRadius;
1378 vec3_t pointAtDist, distToSample;
1381 /* do cone calculation */
1382 distByNormal = -DotProduct( trace->displacement, light->normal );
1383 if( distByNormal < 0.0f )
1385 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1386 radiusAtDist = light->radiusByDist * distByNormal;
1387 VectorSubtract( trace->origin, pointAtDist, distToSample );
1388 sampleRadius = VectorLength( distToSample );
1390 /* outside the cone */
1391 if( sampleRadius >= radiusAtDist )
1395 if( sampleRadius > (radiusAtDist - 32.0f) )
1396 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1400 /* ydnar: sunlight */
1401 else if( light->type == EMIT_SUN )
1404 add = light->photons;
1409 trace->testAll = qtrue;
1410 VectorScale( light->color, add, trace->color );
1412 /* trace to point */
1413 if( trace->testOcclusion && !trace->forceSunlight )
1417 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1419 VectorClear( trace->color );
1424 /* return to sender */
1428 /* unknown light type */
1432 /* ydnar: changed to a variable number */
1433 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1437 trace->testAll = qfalse;
1438 VectorScale( light->color, add, trace->color );
1442 if( trace->passSolid )
1444 VectorClear( trace->color );
1448 /* we have a valid sample */
1456 grid samples are for quickly determining the lighting
1457 of dynamically placed entities in the world
1460 #define MAX_CONTRIBUTIONS 32768
1471 void TraceGrid( int num )
1473 int i, j, x, y, z, mod, numCon, numStyles;
1475 vec3_t baseOrigin, cheapColor, color, thisdir;
1477 bspGridPoint_t *bgp;
1478 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1481 /* get grid points */
1482 gp = &rawGridPoints[ num ];
1483 bgp = &bspGridPoints[ num ];
1485 /* get grid origin */
1487 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1488 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1489 y = mod / gridBounds[ 0 ];
1490 mod -= y * gridBounds[ 0 ];
1493 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1494 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1495 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1497 /* set inhibit sphere */
1498 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1499 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1500 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1501 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1503 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1505 /* find point cluster */
1506 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1507 if( trace.cluster < 0 )
1509 /* try to nudge the origin around to find a valid point */
1510 VectorCopy( trace.origin, baseOrigin );
1511 for( step = 0; (step += 0.005) <= 1.0; )
1513 VectorCopy( baseOrigin, trace.origin );
1514 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1515 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1516 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1518 /* ydnar: changed to find cluster num */
1519 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1520 if( trace.cluster >= 0 )
1524 /* can't find a valid point at all */
1530 trace.testOcclusion = !noTrace;
1531 trace.forceSunlight = qfalse;
1532 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1533 trace.numSurfaces = 0;
1534 trace.surfaces = NULL;
1535 trace.numLights = 0;
1536 trace.lights = NULL;
1540 VectorClear( cheapColor );
1542 /* trace to all the lights, find the major light direction, and divide the
1543 total light between that along the direction and the remaining in the ambient */
1544 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1550 if( !LightContributionToPoint( &trace ) )
1553 /* handle negative light */
1554 if( trace.light->flags & LIGHT_NEGATIVE )
1555 VectorScale( trace.color, -1.0f, trace.color );
1557 /* add a contribution */
1558 VectorCopy( trace.color, contributions[ numCon ].color );
1559 VectorCopy( trace.direction, contributions[ numCon ].dir );
1560 VectorClear( contributions[ numCon ].ambient );
1561 contributions[ numCon ].style = trace.light->style;
1564 /* push average direction around */
1565 addSize = VectorLength( trace.color );
1566 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1568 /* stop after a while */
1569 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1572 /* ydnar: cheap mode */
1573 VectorAdd( cheapColor, trace.color, cheapColor );
1574 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1578 /////// Floodlighting for point //////////////////
1579 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1584 vec3_t dir = { 0, 0, 1 };
1585 float ambientFrac = 0.25f;
1587 trace.testOcclusion = qtrue;
1588 trace.forceSunlight = qfalse;
1589 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1590 trace.testAll = qtrue;
1592 for( k = 0; k < 2; k++ )
1594 if( k == 0 ) // upper hemisphere
1596 trace.normal[0] = 0;
1597 trace.normal[1] = 0;
1598 trace.normal[2] = 1;
1600 else //lower hemisphere
1602 trace.normal[0] = 0;
1603 trace.normal[1] = 0;
1604 trace.normal[2] = -1;
1607 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1609 /* add a fraction as pure ambient, half as top-down direction */
1610 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1611 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1612 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1614 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1615 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1616 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1618 contributions[ numCon ].dir[0] = dir[0];
1619 contributions[ numCon ].dir[1] = dir[1];
1620 contributions[ numCon ].dir[2] = dir[2];
1622 contributions[ numCon ].style = 0;
1624 /* push average direction around */
1625 addSize = VectorLength( contributions[ numCon ].color );
1626 VectorMA( gp->dir, addSize, dir, gp->dir );
1631 /////////////////////
1633 /* normalize to get primary light direction */
1634 VectorNormalize( gp->dir, thisdir );
1636 /* now that we have identified the primary light direction,
1637 go back and separate all the light into directed and ambient */
1640 for( i = 0; i < numCon; i++ )
1642 /* get relative directed strength */
1643 d = DotProduct( contributions[ i ].dir, thisdir );
1644 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1645 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1649 /* find appropriate style */
1650 for( j = 0; j < numStyles; j++ )
1652 if( gp->styles[ j ] == contributions[ i ].style )
1656 /* style not found? */
1657 if( j >= numStyles )
1659 /* add a new style */
1660 if( numStyles < MAX_LIGHTMAPS )
1662 gp->styles[ numStyles ] = contributions[ i ].style;
1663 bgp->styles[ numStyles ] = contributions[ i ].style;
1665 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1673 /* add the directed color */
1674 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1676 /* ambient light will be at 1/4 the value of directed light */
1677 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1678 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1680 /* (Hobbes: always setting it to .25 is hardly any better) */
1681 d = 0.25f * (1.0f - d);
1682 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1684 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1688 * the total light average = ambient value + 0.25 * sum of all directional values
1689 * we can also get the total light average as 0.25 * the sum of all contributions
1691 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1694 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1696 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1701 /* store off sample */
1702 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1705 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1707 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1710 /* set minimum light and copy off to bytes */
1711 VectorCopy( gp->ambient[ i ], color );
1712 for( j = 0; j < 3; j++ )
1713 if( color[ j ] < minGridLight[ j ] )
1714 color[ j ] = minGridLight[ j ];
1716 /* vortex: apply gridscale and gridambientscale here */
1717 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1718 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1723 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1724 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1726 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1727 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1730 /* store direction */
1731 NormalToLatLong( thisdir, bgp->latLong );
1738 calculates the size of the lightgrid and allocates memory
1741 void SetupGrid( void )
1744 vec3_t maxs, oldGridSize;
1749 /* don't do this if not grid lighting */
1750 if( noGridLighting )
1753 /* ydnar: set grid size */
1754 value = ValueForKey( &entities[ 0 ], "gridsize" );
1755 if( value[ 0 ] != '\0' )
1756 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1759 VectorCopy( gridSize, oldGridSize );
1760 for( i = 0; i < 3; i++ )
1761 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1763 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1764 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1766 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1768 /* get world bounds */
1769 for( i = 0; i < 3; i++ )
1771 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1772 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1773 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1777 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1779 /* increase grid size a bit */
1780 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1781 gridSize[ j++ % 3 ] += 16.0f;
1785 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1788 if( !VectorCompare( gridSize, oldGridSize ) )
1790 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1791 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1792 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1795 /* 2nd variable. fixme: is this silly? */
1796 numBSPGridPoints = numRawGridPoints;
1798 /* allocate lightgrid */
1799 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1800 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1802 if( bspGridPoints != NULL )
1803 free( bspGridPoints );
1804 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1805 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1807 /* clear lightgrid */
1808 for( i = 0; i < numRawGridPoints; i++ )
1810 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1811 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1812 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1813 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1815 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1816 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1821 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1828 does what it says...
1831 void LightWorld( void )
1836 qboolean minVertex, minGrid;
1840 /* ydnar: smooth normals */
1843 Sys_Printf( "--- SmoothNormals ---\n" );
1847 /* determine the number of grid points */
1848 Sys_Printf( "--- SetupGrid ---\n" );
1851 /* find the optional minimum lighting values */
1852 GetVectorForKey( &entities[ 0 ], "_color", color );
1853 if( VectorLength( color ) == 0.0f )
1854 VectorSet( color, 1.0, 1.0, 1.0 );
1857 f = FloatForKey( &entities[ 0 ], "_ambient" );
1859 f = FloatForKey( &entities[ 0 ], "ambient" );
1860 VectorScale( color, f, ambientColor );
1862 /* minvertexlight */
1864 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1865 if( value[ 0 ] != '\0' )
1869 VectorScale( color, f, minVertexLight );
1874 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1875 if( value[ 0 ] != '\0' )
1879 VectorScale( color, f, minGridLight );
1883 value = ValueForKey( &entities[ 0 ], "_minlight" );
1884 if( value[ 0 ] != '\0' )
1887 VectorScale( color, f, minLight );
1888 if( minVertex == qfalse )
1889 VectorScale( color, f, minVertexLight );
1890 if( minGrid == qfalse )
1891 VectorScale( color, f, minGridLight );
1894 /* create world lights */
1895 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1896 CreateEntityLights();
1897 CreateSurfaceLights();
1898 Sys_Printf( "%9d point lights\n", numPointLights );
1899 Sys_Printf( "%9d spotlights\n", numSpotLights );
1900 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1901 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1903 /* calculate lightgrid */
1904 if( !noGridLighting )
1906 /* ydnar: set up light envelopes */
1907 SetupEnvelopes( qtrue, fastgrid );
1909 Sys_Printf( "--- TraceGrid ---\n" );
1911 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1913 Sys_Printf( "%d x %d x %d = %d grid\n",
1914 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1916 /* ydnar: emit statistics on light culling */
1917 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1918 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1921 /* slight optimization to remove a sqrt */
1922 subdivideThreshold *= subdivideThreshold;
1924 /* map the world luxels */
1925 Sys_Printf( "--- MapRawLightmap ---\n" );
1926 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1927 Sys_Printf( "%9d luxels\n", numLuxels );
1928 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1929 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1934 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1935 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1938 /* floodlight pass */
1939 FloodlightRawLightmaps();
1941 /* ydnar: set up light envelopes */
1942 SetupEnvelopes( qfalse, fast );
1944 /* light up my world */
1945 lightsPlaneCulled = 0;
1946 lightsEnvelopeCulled = 0;
1947 lightsBoundsCulled = 0;
1948 lightsClusterCulled = 0;
1950 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1951 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1952 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1954 StitchSurfaceLightmaps();
1956 Sys_Printf( "--- IlluminateVertexes ---\n" );
1957 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1958 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1960 /* ydnar: emit statistics on light culling */
1961 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1962 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1963 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1964 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1971 /* store off the bsp between bounces */
1972 StoreSurfaceLightmaps();
1974 Sys_Printf( "Writing %s\n", source );
1975 WriteBSPFile( source );
1978 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1982 VectorClear( ambientColor );
1983 floodlighty = qfalse;
1985 /* generate diffuse lights */
1987 RadCreateDiffuseLights();
1989 /* setup light envelopes */
1990 SetupEnvelopes( qfalse, fastbounce );
1991 if( numLights == 0 )
1993 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1997 /* add to lightgrid */
2000 gridEnvelopeCulled = 0;
2001 gridBoundsCulled = 0;
2003 Sys_Printf( "--- BounceGrid ---\n" );
2005 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2007 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2008 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2011 /* light up my world */
2012 lightsPlaneCulled = 0;
2013 lightsEnvelopeCulled = 0;
2014 lightsBoundsCulled = 0;
2015 lightsClusterCulled = 0;
2017 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2018 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2019 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2020 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2022 StitchSurfaceLightmaps();
2024 Sys_Printf( "--- IlluminateVertexes ---\n" );
2025 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2026 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2028 /* ydnar: emit statistics on light culling */
2029 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2030 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2031 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2032 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2044 main routine for light processing
2047 int LightMain( int argc, char **argv )
2051 char mapSource[ 1024 ];
2053 int lightmapMergeSize = 0;
2054 qboolean lightSamplesInsist = qfalse;
2058 Sys_Printf( "--- Light ---\n" );
2059 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2061 /* set standard game flags */
2062 wolfLight = game->wolfLight;
2063 if (wolfLight == qtrue)
2064 Sys_Printf( " lightning model: wolf\n" );
2066 Sys_Printf( " lightning model: quake3\n" );
2068 lmCustomSize = game->lightmapSize;
2069 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2071 lightmapGamma = game->lightmapGamma;
2072 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2074 lightmapsRGB = game->lightmapsRGB;
2076 Sys_Printf( " lightmap colorspace: sRGB\n" );
2078 Sys_Printf( " lightmap colorspace: linear\n" );
2080 texturesRGB = game->texturesRGB;
2082 Sys_Printf( " texture colorspace: sRGB\n" );
2084 Sys_Printf( " texture colorspace: linear\n" );
2086 lightmapCompensate = game->lightmapCompensate;
2087 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2089 lightmapExposure = game->lightmapExposure;
2090 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2092 gridScale = game->gridScale;
2093 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2095 gridAmbientScale = game->gridAmbientScale;
2096 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2098 lightAngleHL = game->lightAngleHL;
2100 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2102 noStyles = game->noStyles;
2103 if (noStyles == qtrue)
2104 Sys_Printf( " shader lightstyles hack: disabled\n" );
2106 Sys_Printf( " shader lightstyles hack: enabled\n" );
2108 patchShadows = game->patchShadows;
2109 if (patchShadows == qtrue)
2110 Sys_Printf( " patch shadows: enabled\n" );
2112 Sys_Printf( " patch shadows: disabled\n" );
2114 deluxemap = game->deluxeMap;
2115 deluxemode = game->deluxeMode;
2116 if (deluxemap == qtrue)
2119 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2121 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2124 Sys_Printf( " deluxemapping: disabled\n" );
2126 Sys_Printf( "--- ProcessCommandLine ---\n" );
2128 /* process commandline arguments */
2129 for( i = 1; i < (argc - 1); i++ )
2131 /* lightsource scaling */
2132 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2134 f = atof( argv[ i + 1 ] );
2137 Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2138 Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2142 else if( !strcmp( argv[ i ], "-spherical" ) || !strcmp( argv[ i ], "-sphericalscale" ) )
2144 f = atof( argv[ i + 1 ] );
2146 Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2150 else if( !strcmp( argv[ i ], "-spot" ) || !strcmp( argv[ i ], "-spotscale" ) )
2152 f = atof( argv[ i + 1 ] );
2154 Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2158 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2160 f = atof( argv[ i + 1 ] );
2162 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2166 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2168 f = atof( argv[ i + 1 ] );
2170 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2174 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2176 f = atof( argv[ i + 1 ] );
2178 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2182 else if( !strcmp( argv[ i ], "-scale" ) )
2184 f = atof( argv[ i + 1 ] );
2190 Sys_Printf( "All light scaled by %f\n", f );
2194 else if( !strcmp( argv[ i ], "-gridscale" ) )
2196 f = atof( argv[ i + 1 ] );
2197 Sys_Printf( "Grid lightning scaled by %f\n", f );
2202 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2204 f = atof( argv[ i + 1 ] );
2205 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2206 gridAmbientScale *= f;
2210 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2212 f = atof( argv[ i + 1 ] );
2214 if(f < gridAmbientDirectionality) gridAmbientDirectionality = f;
2215 Sys_Printf( "Grid directionality is %f\n", f );
2216 gridDirectionality = f;
2220 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2222 f = atof( argv[ i + 1 ] );
2224 if(f > gridDirectionality) gridDirectionality = f;
2225 Sys_Printf( "Grid ambient directionality is %f\n", f );
2226 gridAmbientDirectionality = f;
2230 else if( !strcmp( argv[ i ], "-gamma" ) )
2232 f = atof( argv[ i + 1 ] );
2234 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2238 else if( !strcmp( argv[ i ], "-sRGBlight" ) )
2240 lightmapsRGB = qtrue;
2241 Sys_Printf( "Lighting is in sRGB\n" );
2244 else if( !strcmp( argv[ i ], "-nosRGBlight" ) )
2246 lightmapsRGB = qfalse;
2247 Sys_Printf( "Lighting is linear\n" );
2250 else if( !strcmp( argv[ i ], "-sRGBtex" ) )
2252 texturesRGB = qtrue;
2253 Sys_Printf( "Textures are in sRGB\n" );
2256 else if( !strcmp( argv[ i ], "-nosRGBtex" ) )
2258 texturesRGB = qfalse;
2259 Sys_Printf( "Textures are linear\n" );
2262 else if( !strcmp( argv[ i ], "-exposure" ) )
2264 f = atof( argv[ i + 1 ] );
2265 lightmapExposure = f;
2266 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2270 else if( !strcmp( argv[ i ], "-compensate" ) )
2272 f = atof( argv[ i + 1 ] );
2275 lightmapCompensate = f;
2276 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2280 /* ydnar switches */
2281 else if( !strcmp( argv[ i ], "-bounce" ) )
2283 bounce = atoi( argv[ i + 1 ] );
2286 else if( bounce > 0 )
2287 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2291 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2293 superSample = atoi( argv[ i + 1 ] );
2294 if( superSample < 1 )
2296 else if( superSample > 1 )
2297 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2301 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2303 lightRandomSamples = qtrue;
2304 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2307 else if( !strcmp( argv[ i ], "-samples" ) )
2309 if(*argv[i+1] == '+')
2310 lightSamplesInsist = qtrue;
2312 lightSamplesInsist = qfalse;
2313 lightSamples = atoi( argv[ i + 1 ] );
2314 if( lightSamples < 1 )
2316 else if( lightSamples > 1 )
2317 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2321 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2323 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2324 if( lightSamplesSearchBoxSize <= 0 )
2325 lightSamplesSearchBoxSize = 1;
2326 if( lightSamplesSearchBoxSize > 4 )
2327 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2328 else if( lightSamplesSearchBoxSize != 1 )
2329 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2333 else if( !strcmp( argv[ i ], "-filter" ) )
2336 Sys_Printf( "Lightmap filtering enabled\n" );
2339 else if( !strcmp( argv[ i ], "-dark" ) )
2342 Sys_Printf( "Dark lightmap seams enabled\n" );
2345 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2347 shadeAngleDegrees = atof( argv[ i + 1 ] );
2348 if( shadeAngleDegrees < 0.0f )
2349 shadeAngleDegrees = 0.0f;
2350 else if( shadeAngleDegrees > 0.0f )
2353 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2358 else if( !strcmp( argv[ i ], "-thresh" ) )
2360 subdivideThreshold = atof( argv[ i + 1 ] );
2361 if( subdivideThreshold < 0 )
2362 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2364 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2368 else if( !strcmp( argv[ i ], "-approx" ) )
2370 approximateTolerance = atoi( argv[ i + 1 ] );
2371 if( approximateTolerance < 0 )
2372 approximateTolerance = 0;
2373 else if( approximateTolerance > 0 )
2374 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2377 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2380 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2382 else if( !strcmp( argv[ i ], "-deluxemode" ))
2384 deluxemode = atoi( argv[ i + 1 ] );
2385 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2387 Sys_Printf( "Generating modelspace deluxemaps\n" );
2391 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2394 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2397 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2399 else if( !strcmp( argv[ i ], "-external" ) )
2401 externalLightmaps = qtrue;
2402 Sys_Printf( "Storing all lightmaps externally\n" );
2405 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2407 lmCustomSize = atoi( argv[ i + 1 ] );
2409 /* must be a power of 2 and greater than 2 */
2410 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2412 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2413 lmCustomSize = game->lightmapSize;
2416 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2418 /* enable external lightmaps */
2419 if( lmCustomSize != game->lightmapSize )
2421 externalLightmaps = qtrue;
2422 Sys_Printf( "Storing all lightmaps externally\n" );
2426 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2428 lmLimitSize = atoi( argv[ i + 1 ] );
2431 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2434 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2436 lmCustomDir = argv[i + 1];
2438 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2439 externalLightmaps = qtrue;
2440 Sys_Printf( "Storing all lightmaps externally\n" );
2443 /* ydnar: add this to suppress warnings */
2444 else if( !strcmp( argv[ i ], "-custinfoparms") )
2446 Sys_Printf( "Custom info parms enabled\n" );
2447 useCustomInfoParms = qtrue;
2450 else if( !strcmp( argv[ i ], "-wolf" ) )
2452 /* -game should already be set */
2454 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2457 else if( !strcmp( argv[ i ], "-q3" ) )
2459 /* -game should already be set */
2461 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2464 else if( !strcmp( argv[ i ], "-extradist" ) )
2466 extraDist = atof( argv[ i + 1 ] );
2470 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2473 else if( !strcmp( argv[ i ], "-sunonly" ) )
2476 Sys_Printf( "Only computing sunlight\n" );
2479 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2482 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2485 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2488 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2491 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2493 lightmapSearchBlockSize = 1;
2494 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2497 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2499 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2501 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2504 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2506 lightmapSearchBlockSize = atoi(argv[i+1]);
2508 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2511 else if( !strcmp( argv[ i ], "-shade" ) )
2514 Sys_Printf( "Phong shading enabled\n" );
2517 else if( !strcmp( argv[ i ], "-bouncegrid") )
2521 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2524 else if( !strcmp( argv[ i ], "-smooth" ) )
2526 lightSamples = EXTRA_SCALE;
2527 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2530 else if( !strcmp( argv[ i ], "-fast" ) )
2535 Sys_Printf( "Fast mode enabled\n" );
2538 else if( !strcmp( argv[ i ], "-faster" ) )
2544 Sys_Printf( "Faster mode enabled\n" );
2547 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2550 Sys_Printf( "Fast grid lighting enabled\n" );
2553 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2556 Sys_Printf( "Fast bounce mode enabled\n" );
2559 else if( !strcmp( argv[ i ], "-cheap" ) )
2563 Sys_Printf( "Cheap mode enabled\n" );
2566 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2569 Sys_Printf( "Cheap grid mode enabled\n" );
2572 else if( !strcmp( argv[ i ], "-normalmap" ) )
2575 Sys_Printf( "Storing normal map instead of lightmap\n" );
2578 else if( !strcmp( argv[ i ], "-trisoup" ) )
2581 Sys_Printf( "Converting brush faces to triangle soup\n" );
2584 else if( !strcmp( argv[ i ], "-debug" ) )
2587 Sys_Printf( "Lightmap debugging enabled\n" );
2590 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2592 debugSurfaces = qtrue;
2593 Sys_Printf( "Lightmap surface debugging enabled\n" );
2596 else if( !strcmp( argv[ i ], "-debugunused" ) )
2598 debugUnused = qtrue;
2599 Sys_Printf( "Unused luxel debugging enabled\n" );
2602 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2605 Sys_Printf( "Lightmap axis debugging enabled\n" );
2608 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2610 debugCluster = qtrue;
2611 Sys_Printf( "Luxel cluster debugging enabled\n" );
2614 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2616 debugOrigin = qtrue;
2617 Sys_Printf( "Luxel origin debugging enabled\n" );
2620 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2623 debugDeluxemap = qtrue;
2624 Sys_Printf( "Deluxemap debugging enabled\n" );
2627 else if( !strcmp( argv[ i ], "-export" ) )
2629 exportLightmaps = qtrue;
2630 Sys_Printf( "Exporting lightmaps\n" );
2633 else if( !strcmp(argv[ i ], "-notrace" ))
2636 Sys_Printf( "Shadow occlusion disabled\n" );
2638 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2640 patchShadows = qtrue;
2641 Sys_Printf( "Patch shadow casting enabled\n" );
2643 else if( !strcmp( argv[ i ], "-extra" ) )
2645 superSample = EXTRA_SCALE; /* ydnar */
2646 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2648 else if( !strcmp( argv[ i ], "-extrawide" ) )
2650 superSample = EXTRAWIDE_SCALE; /* ydnar */
2651 filter = qtrue; /* ydnar */
2652 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2654 else if( !strcmp( argv[ i ], "-samplesize" ) )
2656 sampleSize = atoi( argv[ i + 1 ] );
2657 if( sampleSize < 1 )
2660 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2662 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2664 minSampleSize = atoi( argv[ i + 1 ] );
2665 if( minSampleSize < 1 )
2668 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2670 else if( !strcmp( argv[ i ], "-samplescale" ) )
2672 sampleScale = atoi( argv[ i + 1 ] );
2674 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2676 else if( !strcmp( argv[ i ], "-novertex" ) )
2678 noVertexLighting = qtrue;
2679 Sys_Printf( "Disabling vertex lighting\n" );
2681 else if( !strcmp( argv[ i ], "-nogrid" ) )
2683 noGridLighting = qtrue;
2684 Sys_Printf( "Disabling grid lighting\n" );
2686 else if( !strcmp( argv[ i ], "-border" ) )
2688 lightmapBorder = qtrue;
2689 Sys_Printf( "Adding debug border to lightmaps\n" );
2691 else if( !strcmp( argv[ i ], "-nosurf" ) )
2694 Sys_Printf( "Not tracing against surfaces\n" );
2696 else if( !strcmp( argv[ i ], "-dump" ) )
2699 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2701 else if( !strcmp( argv[ i ], "-lomem" ) )
2704 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2706 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2708 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2710 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2712 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2714 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2717 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2720 Sys_Printf( "Disabling lightstyles\n" );
2722 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2725 Sys_Printf( "Enabling lightstyles\n" );
2727 else if( !strcmp( argv[ i ], "-cpma" ) )
2730 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2732 else if( !strcmp( argv[ i ], "-floodlight" ) )
2734 floodlighty = qtrue;
2735 Sys_Printf( "FloodLighting enabled\n" );
2737 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2739 debugnormals = qtrue;
2740 Sys_Printf( "DebugNormals enabled\n" );
2742 else if( !strcmp( argv[ i ], "-lowquality" ) )
2744 floodlight_lowquality = qtrue;
2745 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2748 /* r7: dirtmapping */
2749 else if( !strcmp( argv[ i ], "-dirty" ) )
2752 Sys_Printf( "Dirtmapping enabled\n" );
2754 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2757 Sys_Printf( "Dirtmap debugging enabled\n" );
2759 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2761 dirtMode = atoi( argv[ i + 1 ] );
2762 if( dirtMode != 0 && dirtMode != 1 )
2765 Sys_Printf( "Enabling randomized dirtmapping\n" );
2767 Sys_Printf( "Enabling ordered dir mapping\n" );
2770 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2772 dirtDepth = atof( argv[ i + 1 ] );
2773 if( dirtDepth <= 0.0f )
2775 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2778 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2780 dirtScale = atof( argv[ i + 1 ] );
2781 if( dirtScale <= 0.0f )
2783 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2786 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2788 dirtGain = atof( argv[ i + 1 ] );
2789 if( dirtGain <= 0.0f )
2791 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2794 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2796 lightmapTriangleCheck = qtrue;
2798 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2800 lightmapExtraVisClusterNudge = qtrue;
2802 else if( !strcmp( argv[ i ], "-fill" ) )
2804 lightmapFill = qtrue;
2805 Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2807 /* unhandled args */
2810 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2815 /* fix up samples count */
2816 if(lightRandomSamples)
2818 if(!lightSamplesInsist)
2820 /* approximately match -samples in quality */
2821 switch(lightSamples)
2827 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2833 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2839 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2847 /* fix up lightmap search power */
2848 if(lightmapMergeSize)
2850 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2851 if(lightmapSearchBlockSize < 1)
2852 lightmapSearchBlockSize = 1;
2854 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2857 /* clean up map name */
2858 strcpy( source, ExpandArg( argv[ i ] ) );
2859 StripExtension( source );
2860 DefaultExtension( source, ".bsp" );
2861 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2862 StripExtension( mapSource );
2863 DefaultExtension( mapSource, ".map" );
2865 /* ydnar: set default sample size */
2866 SetDefaultSampleSize( sampleSize );
2868 /* ydnar: handle shaders */
2869 BeginMapShaderFile( source );
2873 Sys_Printf( "Loading %s\n", source );
2875 /* ydnar: load surface file */
2876 LoadSurfaceExtraFile( source );
2879 LoadBSPFile( source );
2881 /* parse bsp entities */
2884 /* inject command line parameters */
2885 InjectCommandLine(argv, 0, argc - 1);
2888 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2889 if( value[ 0 ] != '1' )
2890 LoadMapFile( mapSource, qtrue, qfalse );
2892 /* set the entity/model origins and init yDrawVerts */
2895 /* ydnar: set up optimization */
2899 SetupSurfaceLightmaps();
2901 /* initialize the surface facet tracing */
2904 /* light the world */
2907 /* ydnar: store off lightmaps */
2908 StoreSurfaceLightmaps();
2910 /* write out the bsp */
2912 Sys_Printf( "Writing %s\n", source );
2913 WriteBSPFile( source );
2915 /* ydnar: export lightmaps */
2916 if( exportLightmaps && !externalLightmaps )
2919 /* return to sender */