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 lightmapCompensate = game->lightmapCompensate;
2081 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2083 lightmapExposure = game->lightmapExposure;
2084 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2086 gridScale = game->gridScale;
2087 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2089 gridAmbientScale = game->gridAmbientScale;
2090 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2092 lightAngleHL = game->lightAngleHL;
2094 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2096 noStyles = game->noStyles;
2097 if (noStyles == qtrue)
2098 Sys_Printf( " shader lightstyles hack: disabled\n" );
2100 Sys_Printf( " shader lightstyles hack: enabled\n" );
2102 keepLights = game->keepLights;
2103 if (keepLights == qtrue)
2104 Sys_Printf( " keep lights: enabled\n" );
2106 Sys_Printf( " keep lights: disabled\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 ], "-sRGB" ) )
2240 lightmapsRGB = qtrue;
2241 Sys_Printf( "Lighting is in sRGB\n" );
2244 else if( !strcmp( argv[ i ], "-nosRGB" ) )
2246 lightmapsRGB = qfalse;
2247 Sys_Printf( "Lighting is linear\n" );
2250 else if( !strcmp( argv[ i ], "-exposure" ) )
2252 f = atof( argv[ i + 1 ] );
2253 lightmapExposure = f;
2254 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2258 else if( !strcmp( argv[ i ], "-compensate" ) )
2260 f = atof( argv[ i + 1 ] );
2263 lightmapCompensate = f;
2264 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2268 /* ydnar switches */
2269 else if( !strcmp( argv[ i ], "-bounce" ) )
2271 bounce = atoi( argv[ i + 1 ] );
2274 else if( bounce > 0 )
2275 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2279 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2281 superSample = atoi( argv[ i + 1 ] );
2282 if( superSample < 1 )
2284 else if( superSample > 1 )
2285 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2289 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2291 lightRandomSamples = qtrue;
2292 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2295 else if( !strcmp( argv[ i ], "-samples" ) )
2297 if(*argv[i+1] == '+')
2298 lightSamplesInsist = qtrue;
2300 lightSamplesInsist = qfalse;
2301 lightSamples = atoi( argv[ i + 1 ] );
2302 if( lightSamples < 1 )
2304 else if( lightSamples > 1 )
2305 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2309 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2311 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2312 if( lightSamplesSearchBoxSize <= 0 )
2313 lightSamplesSearchBoxSize = 1;
2314 if( lightSamplesSearchBoxSize > 4 )
2315 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2316 else if( lightSamplesSearchBoxSize != 1 )
2317 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2321 else if( !strcmp( argv[ i ], "-filter" ) )
2324 Sys_Printf( "Lightmap filtering enabled\n" );
2327 else if( !strcmp( argv[ i ], "-dark" ) )
2330 Sys_Printf( "Dark lightmap seams enabled\n" );
2333 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2335 shadeAngleDegrees = atof( argv[ i + 1 ] );
2336 if( shadeAngleDegrees < 0.0f )
2337 shadeAngleDegrees = 0.0f;
2338 else if( shadeAngleDegrees > 0.0f )
2341 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2346 else if( !strcmp( argv[ i ], "-thresh" ) )
2348 subdivideThreshold = atof( argv[ i + 1 ] );
2349 if( subdivideThreshold < 0 )
2350 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2352 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2356 else if( !strcmp( argv[ i ], "-approx" ) )
2358 approximateTolerance = atoi( argv[ i + 1 ] );
2359 if( approximateTolerance < 0 )
2360 approximateTolerance = 0;
2361 else if( approximateTolerance > 0 )
2362 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2365 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2368 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2370 else if( !strcmp( argv[ i ], "-deluxemode" ))
2372 deluxemode = atoi( argv[ i + 1 ] );
2373 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2375 Sys_Printf( "Generating modelspace deluxemaps\n" );
2379 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2382 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2385 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2387 else if( !strcmp( argv[ i ], "-external" ) )
2389 externalLightmaps = qtrue;
2390 Sys_Printf( "Storing all lightmaps externally\n" );
2393 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2395 lmCustomSize = atoi( argv[ i + 1 ] );
2397 /* must be a power of 2 and greater than 2 */
2398 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2400 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2401 lmCustomSize = game->lightmapSize;
2404 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2406 /* enable external lightmaps */
2407 if( lmCustomSize != game->lightmapSize )
2409 externalLightmaps = qtrue;
2410 Sys_Printf( "Storing all lightmaps externally\n" );
2414 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2416 lmLimitSize = atoi( argv[ i + 1 ] );
2419 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2422 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2424 lmCustomDir = argv[i + 1];
2426 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2427 externalLightmaps = qtrue;
2428 Sys_Printf( "Storing all lightmaps externally\n" );
2431 /* ydnar: add this to suppress warnings */
2432 else if( !strcmp( argv[ i ], "-custinfoparms") )
2434 Sys_Printf( "Custom info parms enabled\n" );
2435 useCustomInfoParms = qtrue;
2438 else if( !strcmp( argv[ i ], "-wolf" ) )
2440 /* -game should already be set */
2442 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2445 else if( !strcmp( argv[ i ], "-q3" ) )
2447 /* -game should already be set */
2449 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2452 else if( !strcmp( argv[ i ], "-extradist" ) )
2454 extraDist = atof( argv[ i + 1 ] );
2458 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2461 else if( !strcmp( argv[ i ], "-sunonly" ) )
2464 Sys_Printf( "Only computing sunlight\n" );
2467 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2470 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2473 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2476 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2479 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2481 lightmapSearchBlockSize = 1;
2482 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2485 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2487 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2489 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2492 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2494 lightmapSearchBlockSize = atoi(argv[i+1]);
2496 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2499 else if( !strcmp( argv[ i ], "-shade" ) )
2502 Sys_Printf( "Phong shading enabled\n" );
2505 else if( !strcmp( argv[ i ], "-bouncegrid") )
2509 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2512 else if( !strcmp( argv[ i ], "-smooth" ) )
2514 lightSamples = EXTRA_SCALE;
2515 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2518 else if( !strcmp( argv[ i ], "-fast" ) )
2523 Sys_Printf( "Fast mode enabled\n" );
2526 else if( !strcmp( argv[ i ], "-faster" ) )
2532 Sys_Printf( "Faster mode enabled\n" );
2535 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2538 Sys_Printf( "Fast grid lighting enabled\n" );
2541 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2544 Sys_Printf( "Fast bounce mode enabled\n" );
2547 else if( !strcmp( argv[ i ], "-cheap" ) )
2551 Sys_Printf( "Cheap mode enabled\n" );
2554 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2557 Sys_Printf( "Cheap grid mode enabled\n" );
2560 else if( !strcmp( argv[ i ], "-normalmap" ) )
2563 Sys_Printf( "Storing normal map instead of lightmap\n" );
2566 else if( !strcmp( argv[ i ], "-trisoup" ) )
2569 Sys_Printf( "Converting brush faces to triangle soup\n" );
2572 else if( !strcmp( argv[ i ], "-debug" ) )
2575 Sys_Printf( "Lightmap debugging enabled\n" );
2578 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2580 debugSurfaces = qtrue;
2581 Sys_Printf( "Lightmap surface debugging enabled\n" );
2584 else if( !strcmp( argv[ i ], "-debugunused" ) )
2586 debugUnused = qtrue;
2587 Sys_Printf( "Unused luxel debugging enabled\n" );
2590 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2593 Sys_Printf( "Lightmap axis debugging enabled\n" );
2596 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2598 debugCluster = qtrue;
2599 Sys_Printf( "Luxel cluster debugging enabled\n" );
2602 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2604 debugOrigin = qtrue;
2605 Sys_Printf( "Luxel origin debugging enabled\n" );
2608 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2611 debugDeluxemap = qtrue;
2612 Sys_Printf( "Deluxemap debugging enabled\n" );
2615 else if( !strcmp( argv[ i ], "-export" ) )
2617 exportLightmaps = qtrue;
2618 Sys_Printf( "Exporting lightmaps\n" );
2621 else if( !strcmp(argv[ i ], "-notrace" ))
2624 Sys_Printf( "Shadow occlusion disabled\n" );
2626 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2628 patchShadows = qtrue;
2629 Sys_Printf( "Patch shadow casting enabled\n" );
2631 else if( !strcmp( argv[ i ], "-extra" ) )
2633 superSample = EXTRA_SCALE; /* ydnar */
2634 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2636 else if( !strcmp( argv[ i ], "-extrawide" ) )
2638 superSample = EXTRAWIDE_SCALE; /* ydnar */
2639 filter = qtrue; /* ydnar */
2640 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2642 else if( !strcmp( argv[ i ], "-samplesize" ) )
2644 sampleSize = atoi( argv[ i + 1 ] );
2645 if( sampleSize < 1 )
2648 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2650 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2652 minSampleSize = atoi( argv[ i + 1 ] );
2653 if( minSampleSize < 1 )
2656 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2658 else if( !strcmp( argv[ i ], "-samplescale" ) )
2660 sampleScale = atoi( argv[ i + 1 ] );
2662 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2664 else if( !strcmp( argv[ i ], "-novertex" ) )
2666 noVertexLighting = qtrue;
2667 Sys_Printf( "Disabling vertex lighting\n" );
2669 else if( !strcmp( argv[ i ], "-nogrid" ) )
2671 noGridLighting = qtrue;
2672 Sys_Printf( "Disabling grid lighting\n" );
2674 else if( !strcmp( argv[ i ], "-border" ) )
2676 lightmapBorder = qtrue;
2677 Sys_Printf( "Adding debug border to lightmaps\n" );
2679 else if( !strcmp( argv[ i ], "-nosurf" ) )
2682 Sys_Printf( "Not tracing against surfaces\n" );
2684 else if( !strcmp( argv[ i ], "-dump" ) )
2687 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2689 else if( !strcmp( argv[ i ], "-lomem" ) )
2692 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2694 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2696 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2698 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2700 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2702 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2705 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2708 Sys_Printf( "Disabling lightstyles\n" );
2710 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2713 Sys_Printf( "Enabling lightstyles\n" );
2715 else if( !strcmp( argv[ i ], "-keeplights" ))
2718 Sys_Printf( "Leaving light entities on map after compile\n" );
2720 else if( !strcmp( argv[ i ], "-cpma" ) )
2723 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2725 else if( !strcmp( argv[ i ], "-floodlight" ) )
2727 floodlighty = qtrue;
2728 Sys_Printf( "FloodLighting enabled\n" );
2730 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2732 debugnormals = qtrue;
2733 Sys_Printf( "DebugNormals enabled\n" );
2735 else if( !strcmp( argv[ i ], "-lowquality" ) )
2737 floodlight_lowquality = qtrue;
2738 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2741 /* r7: dirtmapping */
2742 else if( !strcmp( argv[ i ], "-dirty" ) )
2745 Sys_Printf( "Dirtmapping enabled\n" );
2747 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2750 Sys_Printf( "Dirtmap debugging enabled\n" );
2752 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2754 dirtMode = atoi( argv[ i + 1 ] );
2755 if( dirtMode != 0 && dirtMode != 1 )
2758 Sys_Printf( "Enabling randomized dirtmapping\n" );
2760 Sys_Printf( "Enabling ordered dir mapping\n" );
2763 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2765 dirtDepth = atof( argv[ i + 1 ] );
2766 if( dirtDepth <= 0.0f )
2768 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2771 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2773 dirtScale = atof( argv[ i + 1 ] );
2774 if( dirtScale <= 0.0f )
2776 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2779 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2781 dirtGain = atof( argv[ i + 1 ] );
2782 if( dirtGain <= 0.0f )
2784 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2787 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2789 lightmapTriangleCheck = qtrue;
2791 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2793 lightmapExtraVisClusterNudge = qtrue;
2795 else if( !strcmp( argv[ i ], "-fill" ) )
2797 lightmapFill = qtrue;
2798 Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2800 /* unhandled args */
2803 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2808 /* fix up samples count */
2809 if(lightRandomSamples)
2811 if(!lightSamplesInsist)
2813 /* approximately match -samples in quality */
2814 switch(lightSamples)
2820 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2826 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2832 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2840 /* fix up lightmap search power */
2841 if(lightmapMergeSize)
2843 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2844 if(lightmapSearchBlockSize < 1)
2845 lightmapSearchBlockSize = 1;
2847 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2850 /* clean up map name */
2851 strcpy( source, ExpandArg( argv[ i ] ) );
2852 StripExtension( source );
2853 DefaultExtension( source, ".bsp" );
2854 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2855 StripExtension( mapSource );
2856 DefaultExtension( mapSource, ".map" );
2858 /* ydnar: set default sample size */
2859 SetDefaultSampleSize( sampleSize );
2861 /* ydnar: handle shaders */
2862 BeginMapShaderFile( source );
2866 Sys_Printf( "Loading %s\n", source );
2868 /* ydnar: load surface file */
2869 LoadSurfaceExtraFile( source );
2872 LoadBSPFile( source );
2874 /* parse bsp entities */
2877 /* inject command line parameters */
2878 InjectCommandLine(argv, 0, argc - 1);
2881 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2882 if( value[ 0 ] != '1' )
2883 LoadMapFile( mapSource, qtrue, qfalse );
2885 /* set the entity/model origins and init yDrawVerts */
2888 /* ydnar: set up optimization */
2892 SetupSurfaceLightmaps();
2894 /* initialize the surface facet tracing */
2897 /* light the world */
2900 /* ydnar: store off lightmaps */
2901 StoreSurfaceLightmaps();
2903 /* write out the bsp */
2905 Sys_Printf( "Writing %s\n", source );
2906 WriteBSPFile( source );
2908 /* ydnar: export lightmaps */
2909 if( exportLightmaps && !externalLightmaps )
2912 /* return to sender */