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 intensity = intensity * pointScale;
404 light->photons = intensity;
406 light->type = EMIT_POINT;
408 /* set falloff threshold */
409 light->falloffTolerance = falloffTolerance / numSamples;
411 /* lights with a target will be spotlights */
412 target = ValueForKey( e, "target" );
422 e2 = FindTargetEntity( target );
425 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
426 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
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 / pointScale);
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 */
483 /* jitter the light */
484 for( j = 1; j < numSamples; j++ )
487 light2 = safe_malloc( sizeof( *light ) );
488 memcpy( light2, light, sizeof( *light ) );
489 light2->next = lights;
493 if( light->type == EMIT_SPOT )
499 light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
500 light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
501 light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
509 CreateSurfaceLights() - ydnar
510 this hijacks the radiosity code to generate surface lights for first pass
513 #define APPROX_BOUNCE 1.0f
515 void CreateSurfaceLights( void )
518 bspDrawSurface_t *ds;
528 /* get sun shader supressor */
529 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
531 /* walk the list of surfaces */
532 for( i = 0; i < numBSPDrawSurfaces; i++ )
534 /* get surface and other bits */
535 ds = &bspDrawSurfaces[ i ];
536 info = &surfaceInfos[ i ];
540 if( si->sun != NULL && nss[ 0 ] != '1' )
542 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
543 CreateSunLight( si->sun );
544 si->sun = NULL; /* FIXME: leak! */
548 if( si->skyLightValue > 0.0f )
550 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
551 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
552 si->skyLightValue = 0.0f; /* FIXME: hack! */
555 /* try to early out */
559 /* autosprite shaders become point lights */
562 /* create an average xyz */
563 VectorAdd( info->mins, info->maxs, origin );
564 VectorScale( origin, 0.5f, origin );
567 light = safe_malloc( sizeof( *light ) );
568 memset( light, 0, sizeof( *light ) );
569 light->next = lights;
573 light->flags = LIGHT_Q3A_DEFAULT;
574 light->type = EMIT_POINT;
575 light->photons = si->value * pointScale;
578 VectorCopy( origin, light->origin );
579 VectorCopy( si->color, light->color );
580 light->falloffTolerance = falloffTolerance;
581 light->style = si->lightStyle;
583 /* add to point light count and continue */
588 /* get subdivision amount */
589 if( si->lightSubdivide > 0 )
590 subdivide = si->lightSubdivide;
592 subdivide = defaultLightSubdivide;
595 switch( ds->surfaceType )
598 case MST_TRIANGLE_SOUP:
599 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
603 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
616 find the offset values for inline models
619 void SetEntityOrigins( void )
627 bspDrawSurface_t *ds;
630 /* ydnar: copy drawverts into private storage for nefarious purposes */
631 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
632 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
634 /* set the entity origins */
635 for( i = 0; i < numEntities; i++ )
637 /* get entity and model */
639 key = ValueForKey( e, "model" );
640 if( key[ 0 ] != '*' )
642 modelnum = atoi( key + 1 );
643 dm = &bspModels[ modelnum ];
645 /* get entity origin */
646 key = ValueForKey( e, "origin" );
647 if( key[ 0 ] == '\0' )
649 GetVectorForKey( e, "origin", origin );
651 /* set origin for all surfaces for this model */
652 for( j = 0; j < dm->numBSPSurfaces; j++ )
655 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
658 for( k = 0; k < ds->numVerts; k++ )
660 f = ds->firstVert + k;
661 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
670 PointToPolygonFormFactor()
671 calculates the area over a point/normal hemisphere a winding covers
672 ydnar: fixme: there has to be a faster way to calculate this
673 without the expensive per-vert sqrts and transcendental functions
674 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
675 between this and the approximation
678 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
680 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
682 vec3_t triVector, triNormal;
684 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
686 float dot, angle, facing;
689 /* this is expensive */
690 for( i = 0; i < w->numpoints; i++ )
692 VectorSubtract( w->p[ i ], point, dirs[ i ] );
693 VectorNormalize( dirs[ i ], dirs[ i ] );
696 /* duplicate first vertex to avoid mod operation */
697 VectorCopy( dirs[ 0 ], dirs[ i ] );
699 /* calculcate relative area */
701 for( i = 0; i < w->numpoints; i++ )
705 dot = DotProduct( dirs[ i ], dirs[ j ] );
707 /* roundoff can cause slight creep, which gives an IND from acos */
710 else if( dot < -1.0f )
716 CrossProduct( dirs[ i ], dirs[ j ], triVector );
717 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
720 facing = DotProduct( normal, triNormal );
721 total += facing * angle;
723 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
724 if( total > 6.3f || total < -6.3f )
728 /* now in the range of 0 to 1 over the entire incoming hemisphere */
729 //% total /= (2.0f * 3.141592657f);
730 total *= ONE_OVER_2PI;
737 LightContributionTosample()
738 determines the amount of light reaching a sample (luxel or vertex) from a given light
741 int LightContributionToSample( trace_t *trace )
747 float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
748 qboolean angledDeluxe = qtrue;
749 float colorBrightness;
750 qboolean doAddDeluxe = qtrue;
753 light = trace->light;
756 trace->forceSubsampling = 0.0f; /* to make sure */
757 VectorClear( trace->color );
758 VectorClear( trace->colorNoShadow );
759 VectorClear( trace->directionContribution );
761 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
763 /* ydnar: early out */
764 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
767 /* do some culling checks */
768 if( light->type != EMIT_SUN )
770 /* MrE: if the light is behind the surface */
771 if( trace->twoSided == qfalse )
772 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
775 /* ydnar: test pvs */
776 if( !ClusterVisible( trace->cluster, light->cluster ) )
780 /* exact point to polygon form factor */
781 if( light->type == EMIT_AREA )
787 /* project sample point into light plane */
788 d = DotProduct( trace->origin, light->normal ) - light->dist;
791 /* sample point behind plane? */
792 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
795 /* sample plane coincident? */
796 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
800 /* nudge the point so that it is clearly forward of the light */
801 /* so that surfaces meeting a light emitter don't get black edges */
802 if( d > -8.0f && d < 8.0f )
803 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
805 VectorCopy( trace->origin, pushedOrigin );
807 /* get direction and distance */
808 VectorCopy( light->origin, trace->end );
809 dist = SetupTrace( trace );
810 if( dist >= light->envelope )
813 /* ptpff approximation */
816 /* angle attenuation */
817 angle = DotProduct( trace->normal, trace->direction );
819 /* twosided lighting */
820 if( trace->twoSided && angle < 0 )
824 /* no deluxemap contribution from "other side" light */
825 doAddDeluxe = qfalse;
829 angle *= -DotProduct( light->normal, trace->direction );
832 else if( angle < 0.0f &&
833 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
837 /* no deluxemap contribution from "other side" light */
838 doAddDeluxe = qfalse;
841 /* clamp the distance to prevent super hot spots */
842 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
846 add = light->photons / (dist * dist) * angle;
851 addDeluxe = light->photons / (dist * dist) * angle;
853 addDeluxe = light->photons / (dist * dist);
858 /* calculate the contribution */
859 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
862 else if( factor < 0.0f )
864 /* twosided lighting */
865 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
869 /* push light origin to other side of the plane */
870 VectorMA( light->origin, -2.0f, light->normal, trace->end );
871 dist = SetupTrace( trace );
872 if( dist >= light->envelope )
875 /* no deluxemap contribution from "other side" light */
876 doAddDeluxe = qfalse;
882 /* also don't deluxe if the direction is on the wrong side */
883 if(DotProduct(trace->normal, trace->direction) < 0)
885 /* no deluxemap contribution from "other side" light */
886 doAddDeluxe = qfalse;
889 /* ydnar: moved to here */
890 add = factor * light->add;
897 /* point/spot lights */
898 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
900 /* get direction and distance */
901 VectorCopy( light->origin, trace->end );
902 dist = SetupTrace( trace );
903 if( dist >= light->envelope )
906 /* clamp the distance to prevent super hot spots */
907 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
911 /* angle attenuation */
912 if( light->flags & LIGHT_ATTEN_ANGLE )
914 /* standard Lambert attenuation */
915 float dot = DotProduct( trace->normal, trace->direction );
917 /* twosided lighting */
918 if( trace->twoSided && dot < 0 )
922 /* no deluxemap contribution from "other side" light */
923 doAddDeluxe = qfalse;
926 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
929 if( dot > 0.001f ) // skip coplanar
931 if( dot > 1.0f ) dot = 1.0f;
932 dot = ( dot * 0.5f ) + 0.5f;
944 if( light->angleScale != 0.0f )
946 angle /= light->angleScale;
952 if( light->flags & LIGHT_ATTEN_LINEAR )
954 add = angle * light->photons * linearScale - (dist * light->fade);
961 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
963 addDeluxe = light->photons * linearScale - (dist * light->fade);
965 if( addDeluxe < 0.0f )
971 add = (light->photons / (dist * dist)) * angle;
978 addDeluxe = (light->photons / (dist * dist)) * angle;
980 addDeluxe = (light->photons / (dist * dist));
983 if( addDeluxe < 0.0f )
987 /* handle spotlights */
988 if( light->type == EMIT_SPOT )
990 float distByNormal, radiusAtDist, sampleRadius;
991 vec3_t pointAtDist, distToSample;
993 /* do cone calculation */
994 distByNormal = -DotProduct( trace->displacement, light->normal );
995 if( distByNormal < 0.0f )
997 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
998 radiusAtDist = light->radiusByDist * distByNormal;
999 VectorSubtract( trace->origin, pointAtDist, distToSample );
1000 sampleRadius = VectorLength( distToSample );
1002 /* outside the cone */
1003 if( sampleRadius >= radiusAtDist )
1007 if( sampleRadius > (radiusAtDist - 32.0f) )
1009 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1013 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1015 if( addDeluxe < 0.0f )
1021 /* ydnar: sunlight */
1022 else if( light->type == EMIT_SUN )
1024 /* get origin and direction */
1025 VectorAdd( trace->origin, light->origin, trace->end );
1026 dist = SetupTrace( trace );
1028 /* angle attenuation */
1029 if( light->flags & LIGHT_ATTEN_ANGLE )
1031 /* standard Lambert attenuation */
1032 float dot = DotProduct( trace->normal, trace->direction );
1034 /* twosided lighting */
1035 if( trace->twoSided && dot < 0 )
1039 /* no deluxemap contribution from "other side" light */
1040 doAddDeluxe = qfalse;
1043 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1046 if( dot > 0.001f ) // skip coplanar
1048 if( dot > 1.0f ) dot = 1.0f;
1049 dot = ( dot * 0.5f ) + 0.5f;
1062 add = light->photons * angle;
1067 addDeluxe = light->photons * angle;
1069 addDeluxe = light->photons;
1071 if( addDeluxe < 0.0f )
1078 /* VorteX: set noShadow color */
1079 VectorScale(light->color, add, trace->colorNoShadow);
1081 addDeluxe *= colorBrightness;
1085 addDeluxe *= addDeluxeBounceScale;
1086 if( addDeluxe < 0.00390625f )
1087 addDeluxe = 0.00390625f;
1090 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1093 trace->testAll = qtrue;
1094 VectorScale( light->color, add, trace->color );
1096 /* trace to point */
1097 if( trace->testOcclusion && !trace->forceSunlight )
1101 trace->forceSubsampling *= add;
1102 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1104 VectorClear( trace->color );
1105 VectorClear( trace->directionContribution );
1111 /* return to sender */
1115 Error("Light of undefined type!");
1117 /* VorteX: set noShadow color */
1118 VectorScale(light->color, add, trace->colorNoShadow);
1120 /* ydnar: changed to a variable number */
1121 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1124 addDeluxe *= colorBrightness;
1126 /* hack land: scale down the radiosity contribution to light directionality.
1127 Deluxemaps fusion many light directions into one. In a rtl process all lights
1128 would contribute individually to the bump map, so several light sources together
1129 would make it more directional (example: a yellow and red lights received from
1130 opposing sides would light one side in red and the other in blue, adding
1131 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1132 neutralize each other making it look like having no direction.
1133 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1134 is modifying the direction applied from directional lights, making it go closer and closer
1135 to the surface normal the bigger is the amount of radiosity received.
1136 So, for preserving the directional lights contributions, we scale down the radiosity
1137 contribution. It's a hack, but there's a reason behind it */
1140 addDeluxe *= addDeluxeBounceScale;
1141 /* better NOT increase it beyond the original value
1142 if( addDeluxe < 0.00390625f )
1143 addDeluxe = 0.00390625f;
1149 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1153 trace->testAll = qfalse;
1154 VectorScale( light->color, add, trace->color );
1158 trace->forceSubsampling *= add;
1159 if( trace->passSolid || trace->opaque )
1161 VectorClear( trace->color );
1162 VectorClear( trace->directionContribution );
1167 /* return to sender */
1175 determines the amount of light reaching a sample (luxel or vertex)
1178 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1184 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1185 VectorClear( colors[ lightmapNum ] );
1187 /* ydnar: normalmap */
1190 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1191 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1192 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1196 /* ydnar: don't bounce ambient all the time */
1198 VectorCopy( ambientColor, colors[ 0 ] );
1200 /* ydnar: trace to all the list of lights pre-stored in tw */
1201 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1204 trace->light = trace->lights[ i ];
1207 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1209 if( styles[ lightmapNum ] == trace->light->style ||
1210 styles[ lightmapNum ] == LS_NONE )
1214 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1215 if( lightmapNum >= MAX_LIGHTMAPS )
1219 LightContributionToSample( trace );
1220 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1223 /* handle negative light */
1224 if( trace->light->flags & LIGHT_NEGATIVE )
1225 VectorScale( trace->color, -1.0f, trace->color );
1228 styles[ lightmapNum ] = trace->light->style;
1231 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1235 colors[ 0 ][ 0 ] >= 255.0f &&
1236 colors[ 0 ][ 1 ] >= 255.0f &&
1237 colors[ 0 ][ 2 ] >= 255.0f )
1245 LightContributionToPoint()
1246 for a given light, how much light/color reaches a given point in space (with no facing)
1247 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1250 int LightContributionToPoint( trace_t *trace )
1257 light = trace->light;
1260 VectorClear( trace->color );
1262 /* ydnar: early out */
1263 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1266 /* is this a sun? */
1267 if( light->type != EMIT_SUN )
1274 if( !ClusterVisible( trace->cluster, light->cluster ) )
1278 /* ydnar: check origin against light's pvs envelope */
1279 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1280 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1281 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1287 /* set light origin */
1288 if( light->type == EMIT_SUN )
1289 VectorAdd( trace->origin, light->origin, trace->end );
1291 VectorCopy( light->origin, trace->end );
1294 dist = SetupTrace( trace );
1297 if( dist > light->envelope )
1299 gridEnvelopeCulled++;
1303 /* ptpff approximation */
1304 if( light->type == EMIT_AREA && faster )
1306 /* clamp the distance to prevent super hot spots */
1307 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1312 add = light->photons / (dist * dist);
1315 /* exact point to polygon form factor */
1316 else if( light->type == EMIT_AREA )
1319 vec3_t pushedOrigin;
1322 /* see if the point is behind the light */
1323 d = DotProduct( trace->origin, light->normal ) - light->dist;
1324 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1327 /* nudge the point so that it is clearly forward of the light */
1328 /* so that surfaces meeting a light emiter don't get black edges */
1329 if( d > -8.0f && d < 8.0f )
1330 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1332 VectorCopy( trace->origin, pushedOrigin );
1334 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1335 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1336 if( factor == 0.0f )
1338 else if( factor < 0.0f )
1340 if( light->flags & LIGHT_TWOSIDED )
1346 /* ydnar: moved to here */
1347 add = factor * light->add;
1350 /* point/spot lights */
1351 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1353 /* clamp the distance to prevent super hot spots */
1354 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1359 if( light->flags & LIGHT_ATTEN_LINEAR )
1361 add = light->photons * linearScale - (dist * light->fade);
1366 add = light->photons / (dist * dist);
1368 /* handle spotlights */
1369 if( light->type == EMIT_SPOT )
1371 float distByNormal, radiusAtDist, sampleRadius;
1372 vec3_t pointAtDist, distToSample;
1375 /* do cone calculation */
1376 distByNormal = -DotProduct( trace->displacement, light->normal );
1377 if( distByNormal < 0.0f )
1379 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1380 radiusAtDist = light->radiusByDist * distByNormal;
1381 VectorSubtract( trace->origin, pointAtDist, distToSample );
1382 sampleRadius = VectorLength( distToSample );
1384 /* outside the cone */
1385 if( sampleRadius >= radiusAtDist )
1389 if( sampleRadius > (radiusAtDist - 32.0f) )
1390 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1394 /* ydnar: sunlight */
1395 else if( light->type == EMIT_SUN )
1398 add = light->photons;
1403 trace->testAll = qtrue;
1404 VectorScale( light->color, add, trace->color );
1406 /* trace to point */
1407 if( trace->testOcclusion && !trace->forceSunlight )
1411 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1413 VectorClear( trace->color );
1418 /* return to sender */
1422 /* unknown light type */
1426 /* ydnar: changed to a variable number */
1427 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1431 trace->testAll = qfalse;
1432 VectorScale( light->color, add, trace->color );
1436 if( trace->passSolid )
1438 VectorClear( trace->color );
1442 /* we have a valid sample */
1450 grid samples are for quickly determining the lighting
1451 of dynamically placed entities in the world
1454 #define MAX_CONTRIBUTIONS 32768
1465 void TraceGrid( int num )
1467 int i, j, x, y, z, mod, numCon, numStyles;
1469 vec3_t baseOrigin, cheapColor, color, thisdir;
1471 bspGridPoint_t *bgp;
1472 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1475 /* get grid points */
1476 gp = &rawGridPoints[ num ];
1477 bgp = &bspGridPoints[ num ];
1479 /* get grid origin */
1481 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1482 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1483 y = mod / gridBounds[ 0 ];
1484 mod -= y * gridBounds[ 0 ];
1487 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1488 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1489 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1491 /* set inhibit sphere */
1492 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1493 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1494 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1495 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1497 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1499 /* find point cluster */
1500 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1501 if( trace.cluster < 0 )
1503 /* try to nudge the origin around to find a valid point */
1504 VectorCopy( trace.origin, baseOrigin );
1505 for( step = 0; (step += 0.005) <= 1.0; )
1507 VectorCopy( baseOrigin, trace.origin );
1508 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1509 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1510 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1512 /* ydnar: changed to find cluster num */
1513 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1514 if( trace.cluster >= 0 )
1518 /* can't find a valid point at all */
1524 trace.testOcclusion = !noTrace;
1525 trace.forceSunlight = qfalse;
1526 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1527 trace.numSurfaces = 0;
1528 trace.surfaces = NULL;
1529 trace.numLights = 0;
1530 trace.lights = NULL;
1534 VectorClear( cheapColor );
1536 /* trace to all the lights, find the major light direction, and divide the
1537 total light between that along the direction and the remaining in the ambient */
1538 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1544 if( !LightContributionToPoint( &trace ) )
1547 /* handle negative light */
1548 if( trace.light->flags & LIGHT_NEGATIVE )
1549 VectorScale( trace.color, -1.0f, trace.color );
1551 /* add a contribution */
1552 VectorCopy( trace.color, contributions[ numCon ].color );
1553 VectorCopy( trace.direction, contributions[ numCon ].dir );
1554 VectorClear( contributions[ numCon ].ambient );
1555 contributions[ numCon ].style = trace.light->style;
1558 /* push average direction around */
1559 addSize = VectorLength( trace.color );
1560 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1562 /* stop after a while */
1563 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1566 /* ydnar: cheap mode */
1567 VectorAdd( cheapColor, trace.color, cheapColor );
1568 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1572 /////// Floodlighting for point //////////////////
1573 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1578 vec3_t dir = { 0, 0, 1 };
1579 float ambientFrac = 0.25f;
1581 trace.testOcclusion = qtrue;
1582 trace.forceSunlight = qfalse;
1583 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1584 trace.testAll = qtrue;
1586 for( k = 0; k < 2; k++ )
1588 if( k == 0 ) // upper hemisphere
1590 trace.normal[0] = 0;
1591 trace.normal[1] = 0;
1592 trace.normal[2] = 1;
1594 else //lower hemisphere
1596 trace.normal[0] = 0;
1597 trace.normal[1] = 0;
1598 trace.normal[2] = -1;
1601 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1603 /* add a fraction as pure ambient, half as top-down direction */
1604 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1605 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1606 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1608 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1609 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1610 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1612 contributions[ numCon ].dir[0] = dir[0];
1613 contributions[ numCon ].dir[1] = dir[1];
1614 contributions[ numCon ].dir[2] = dir[2];
1616 contributions[ numCon ].style = 0;
1618 /* push average direction around */
1619 addSize = VectorLength( contributions[ numCon ].color );
1620 VectorMA( gp->dir, addSize, dir, gp->dir );
1625 /////////////////////
1627 /* normalize to get primary light direction */
1628 VectorNormalize( gp->dir, thisdir );
1630 /* now that we have identified the primary light direction,
1631 go back and separate all the light into directed and ambient */
1634 for( i = 0; i < numCon; i++ )
1636 /* get relative directed strength */
1637 d = DotProduct( contributions[ i ].dir, thisdir );
1638 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1639 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1643 /* find appropriate style */
1644 for( j = 0; j < numStyles; j++ )
1646 if( gp->styles[ j ] == contributions[ i ].style )
1650 /* style not found? */
1651 if( j >= numStyles )
1653 /* add a new style */
1654 if( numStyles < MAX_LIGHTMAPS )
1656 gp->styles[ numStyles ] = contributions[ i ].style;
1657 bgp->styles[ numStyles ] = contributions[ i ].style;
1659 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1667 /* add the directed color */
1668 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1670 /* ambient light will be at 1/4 the value of directed light */
1671 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1672 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1674 /* (Hobbes: always setting it to .25 is hardly any better) */
1675 d = 0.25f * (1.0f - d);
1676 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1678 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1682 * the total light average = ambient value + 0.25 * sum of all directional values
1683 * we can also get the total light average as 0.25 * the sum of all contributions
1685 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1688 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1690 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1695 /* store off sample */
1696 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1699 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1701 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1704 /* set minimum light and copy off to bytes */
1705 VectorCopy( gp->ambient[ i ], color );
1706 for( j = 0; j < 3; j++ )
1707 if( color[ j ] < minGridLight[ j ] )
1708 color[ j ] = minGridLight[ j ];
1710 /* vortex: apply gridscale and gridambientscale here */
1711 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1712 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1717 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1718 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1720 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1721 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1724 /* store direction */
1725 NormalToLatLong( thisdir, bgp->latLong );
1732 calculates the size of the lightgrid and allocates memory
1735 void SetupGrid( void )
1738 vec3_t maxs, oldGridSize;
1743 /* don't do this if not grid lighting */
1744 if( noGridLighting )
1747 /* ydnar: set grid size */
1748 value = ValueForKey( &entities[ 0 ], "gridsize" );
1749 if( value[ 0 ] != '\0' )
1750 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1753 VectorCopy( gridSize, oldGridSize );
1754 for( i = 0; i < 3; i++ )
1755 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1757 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1758 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1760 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1762 /* get world bounds */
1763 for( i = 0; i < 3; i++ )
1765 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1766 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1767 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1771 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1773 /* increase grid size a bit */
1774 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1775 gridSize[ j++ % 3 ] += 16.0f;
1779 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1782 if( !VectorCompare( gridSize, oldGridSize ) )
1784 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1785 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1786 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1789 /* 2nd variable. fixme: is this silly? */
1790 numBSPGridPoints = numRawGridPoints;
1792 /* allocate lightgrid */
1793 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1794 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1796 if( bspGridPoints != NULL )
1797 free( bspGridPoints );
1798 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1799 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1801 /* clear lightgrid */
1802 for( i = 0; i < numRawGridPoints; i++ )
1804 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1805 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1806 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1807 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1809 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1810 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1815 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1822 does what it says...
1825 void LightWorld( void )
1830 qboolean minVertex, minGrid;
1834 /* ydnar: smooth normals */
1837 Sys_Printf( "--- SmoothNormals ---\n" );
1841 /* determine the number of grid points */
1842 Sys_Printf( "--- SetupGrid ---\n" );
1845 /* find the optional minimum lighting values */
1846 GetVectorForKey( &entities[ 0 ], "_color", color );
1847 if( VectorLength( color ) == 0.0f )
1848 VectorSet( color, 1.0, 1.0, 1.0 );
1851 f = FloatForKey( &entities[ 0 ], "_ambient" );
1853 f = FloatForKey( &entities[ 0 ], "ambient" );
1854 VectorScale( color, f, ambientColor );
1856 /* minvertexlight */
1858 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1859 if( value[ 0 ] != '\0' )
1863 VectorScale( color, f, minVertexLight );
1868 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1869 if( value[ 0 ] != '\0' )
1873 VectorScale( color, f, minGridLight );
1877 value = ValueForKey( &entities[ 0 ], "_minlight" );
1878 if( value[ 0 ] != '\0' )
1881 VectorScale( color, f, minLight );
1882 if( minVertex == qfalse )
1883 VectorScale( color, f, minVertexLight );
1884 if( minGrid == qfalse )
1885 VectorScale( color, f, minGridLight );
1888 /* create world lights */
1889 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1890 CreateEntityLights();
1891 CreateSurfaceLights();
1892 Sys_Printf( "%9d point lights\n", numPointLights );
1893 Sys_Printf( "%9d spotlights\n", numSpotLights );
1894 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1895 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1897 /* calculate lightgrid */
1898 if( !noGridLighting )
1900 /* ydnar: set up light envelopes */
1901 SetupEnvelopes( qtrue, fastgrid );
1903 Sys_Printf( "--- TraceGrid ---\n" );
1905 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1907 Sys_Printf( "%d x %d x %d = %d grid\n",
1908 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1910 /* ydnar: emit statistics on light culling */
1911 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1912 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1915 /* slight optimization to remove a sqrt */
1916 subdivideThreshold *= subdivideThreshold;
1918 /* map the world luxels */
1919 Sys_Printf( "--- MapRawLightmap ---\n" );
1920 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1921 Sys_Printf( "%9d luxels\n", numLuxels );
1922 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1923 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1928 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1929 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1932 /* floodlight pass */
1933 FloodlightRawLightmaps();
1935 /* ydnar: set up light envelopes */
1936 SetupEnvelopes( qfalse, fast );
1938 /* light up my world */
1939 lightsPlaneCulled = 0;
1940 lightsEnvelopeCulled = 0;
1941 lightsBoundsCulled = 0;
1942 lightsClusterCulled = 0;
1944 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1945 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1946 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1948 StitchSurfaceLightmaps();
1950 Sys_Printf( "--- IlluminateVertexes ---\n" );
1951 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1952 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1954 /* ydnar: emit statistics on light culling */
1955 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1956 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1957 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1958 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1965 /* store off the bsp between bounces */
1966 StoreSurfaceLightmaps();
1968 Sys_Printf( "Writing %s\n", source );
1969 WriteBSPFile( source );
1972 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1976 VectorClear( ambientColor );
1977 floodlighty = qfalse;
1979 /* generate diffuse lights */
1981 RadCreateDiffuseLights();
1983 /* setup light envelopes */
1984 SetupEnvelopes( qfalse, fastbounce );
1985 if( numLights == 0 )
1987 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1991 /* add to lightgrid */
1994 gridEnvelopeCulled = 0;
1995 gridBoundsCulled = 0;
1997 Sys_Printf( "--- BounceGrid ---\n" );
1999 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2001 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2002 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2005 /* light up my world */
2006 lightsPlaneCulled = 0;
2007 lightsEnvelopeCulled = 0;
2008 lightsBoundsCulled = 0;
2009 lightsClusterCulled = 0;
2011 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2012 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2013 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2014 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2016 StitchSurfaceLightmaps();
2018 Sys_Printf( "--- IlluminateVertexes ---\n" );
2019 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2020 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2022 /* ydnar: emit statistics on light culling */
2023 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2024 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2025 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2026 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2038 main routine for light processing
2041 int LightMain( int argc, char **argv )
2045 char mapSource[ 1024 ];
2047 int lightmapMergeSize = 0;
2048 qboolean lightSamplesInsist = qfalse;
2052 Sys_Printf( "--- Light ---\n" );
2053 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2055 /* set standard game flags */
2056 wolfLight = game->wolfLight;
2057 if (wolfLight == qtrue)
2058 Sys_Printf( " lightning model: wolf\n" );
2060 Sys_Printf( " lightning model: quake3\n" );
2062 lmCustomSize = game->lightmapSize;
2063 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2065 lightmapGamma = game->lightmapGamma;
2066 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2068 lightmapsRGB = game->lightmapsRGB;
2070 Sys_Printf( " lightmap colorspace: sRGB\n" );
2072 Sys_Printf( " lightmap colorspace: linear\n" );
2074 lightmapCompensate = game->lightmapCompensate;
2075 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2077 lightmapExposure = game->lightmapExposure;
2078 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2080 gridScale = game->gridScale;
2081 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2083 gridAmbientScale = game->gridAmbientScale;
2084 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2086 lightAngleHL = game->lightAngleHL;
2088 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2090 noStyles = game->noStyles;
2091 if (noStyles == qtrue)
2092 Sys_Printf( " shader lightstyles hack: disabled\n" );
2094 Sys_Printf( " shader lightstyles hack: enabled\n" );
2096 keepLights = game->keepLights;
2097 if (keepLights == qtrue)
2098 Sys_Printf( " keep lights: enabled\n" );
2100 Sys_Printf( " keep lights: disabled\n" );
2102 patchShadows = game->patchShadows;
2103 if (patchShadows == qtrue)
2104 Sys_Printf( " patch shadows: enabled\n" );
2106 Sys_Printf( " patch shadows: disabled\n" );
2108 deluxemap = game->deluxeMap;
2109 deluxemode = game->deluxeMode;
2110 if (deluxemap == qtrue)
2113 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2115 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2118 Sys_Printf( " deluxemapping: disabled\n" );
2120 Sys_Printf( "--- ProcessCommandLine ---\n" );
2122 /* process commandline arguments */
2123 for( i = 1; i < (argc - 1); i++ )
2125 /* lightsource scaling */
2126 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2128 f = atof( argv[ i + 1 ] );
2130 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2134 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2136 f = atof( argv[ i + 1 ] );
2138 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2142 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2144 f = atof( argv[ i + 1 ] );
2146 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2150 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2152 f = atof( argv[ i + 1 ] );
2154 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2158 else if( !strcmp( argv[ i ], "-scale" ) )
2160 f = atof( argv[ i + 1 ] );
2165 Sys_Printf( "All light scaled by %f\n", f );
2169 else if( !strcmp( argv[ i ], "-gridscale" ) )
2171 f = atof( argv[ i + 1 ] );
2172 Sys_Printf( "Grid lightning scaled by %f\n", f );
2177 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2179 f = atof( argv[ i + 1 ] );
2180 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2181 gridAmbientScale *= f;
2185 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2187 f = atof( argv[ i + 1 ] );
2189 if(f < gridAmbientDirectionality) gridAmbientDirectionality = f;
2190 Sys_Printf( "Grid directionality is %f\n", f );
2191 gridDirectionality = f;
2195 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2197 f = atof( argv[ i + 1 ] );
2199 if(f > gridDirectionality) gridDirectionality = f;
2200 Sys_Printf( "Grid ambient directionality is %f\n", f );
2201 gridAmbientDirectionality = f;
2205 else if( !strcmp( argv[ i ], "-gamma" ) )
2207 f = atof( argv[ i + 1 ] );
2209 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2213 else if( !strcmp( argv[ i ], "-sRGB" ) )
2215 lightmapsRGB = qtrue;
2216 Sys_Printf( "Lighting is in sRGB\n" );
2220 else if( !strcmp( argv[ i ], "-exposure" ) )
2222 f = atof( argv[ i + 1 ] );
2223 lightmapExposure = f;
2224 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2228 else if( !strcmp( argv[ i ], "-compensate" ) )
2230 f = atof( argv[ i + 1 ] );
2233 lightmapCompensate = f;
2234 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2238 /* ydnar switches */
2239 else if( !strcmp( argv[ i ], "-bounce" ) )
2241 bounce = atoi( argv[ i + 1 ] );
2244 else if( bounce > 0 )
2245 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2249 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2251 superSample = atoi( argv[ i + 1 ] );
2252 if( superSample < 1 )
2254 else if( superSample > 1 )
2255 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2259 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2261 lightRandomSamples = qtrue;
2262 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2265 else if( !strcmp( argv[ i ], "-samples" ) )
2267 if(*argv[i+1] == '+')
2268 lightSamplesInsist = qtrue;
2270 lightSamplesInsist = qfalse;
2271 lightSamples = atoi( argv[ i + 1 ] );
2272 if( lightSamples < 1 )
2274 else if( lightSamples > 1 )
2275 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2279 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2281 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2282 if( lightSamplesSearchBoxSize <= 0 )
2283 lightSamplesSearchBoxSize = 1;
2284 if( lightSamplesSearchBoxSize > 4 )
2285 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2286 else if( lightSamplesSearchBoxSize != 1 )
2287 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2291 else if( !strcmp( argv[ i ], "-filter" ) )
2294 Sys_Printf( "Lightmap filtering enabled\n" );
2297 else if( !strcmp( argv[ i ], "-dark" ) )
2300 Sys_Printf( "Dark lightmap seams enabled\n" );
2303 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2305 shadeAngleDegrees = atof( argv[ i + 1 ] );
2306 if( shadeAngleDegrees < 0.0f )
2307 shadeAngleDegrees = 0.0f;
2308 else if( shadeAngleDegrees > 0.0f )
2311 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2316 else if( !strcmp( argv[ i ], "-thresh" ) )
2318 subdivideThreshold = atof( argv[ i + 1 ] );
2319 if( subdivideThreshold < 0 )
2320 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2322 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2326 else if( !strcmp( argv[ i ], "-approx" ) )
2328 approximateTolerance = atoi( argv[ i + 1 ] );
2329 if( approximateTolerance < 0 )
2330 approximateTolerance = 0;
2331 else if( approximateTolerance > 0 )
2332 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2335 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2338 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2340 else if( !strcmp( argv[ i ], "-deluxemode" ))
2342 deluxemode = atoi( argv[ i + 1 ] );
2343 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2345 Sys_Printf( "Generating modelspace deluxemaps\n" );
2349 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2352 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2355 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2357 else if( !strcmp( argv[ i ], "-external" ) )
2359 externalLightmaps = qtrue;
2360 Sys_Printf( "Storing all lightmaps externally\n" );
2363 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2365 lmCustomSize = atoi( argv[ i + 1 ] );
2367 /* must be a power of 2 and greater than 2 */
2368 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2370 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2371 lmCustomSize = game->lightmapSize;
2374 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2376 /* enable external lightmaps */
2377 if( lmCustomSize != game->lightmapSize )
2379 externalLightmaps = qtrue;
2380 Sys_Printf( "Storing all lightmaps externally\n" );
2384 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2386 lmLimitSize = atoi( argv[ i + 1 ] );
2389 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2392 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2394 lmCustomDir = argv[i + 1];
2396 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2397 externalLightmaps = qtrue;
2398 Sys_Printf( "Storing all lightmaps externally\n" );
2401 /* ydnar: add this to suppress warnings */
2402 else if( !strcmp( argv[ i ], "-custinfoparms") )
2404 Sys_Printf( "Custom info parms enabled\n" );
2405 useCustomInfoParms = qtrue;
2408 else if( !strcmp( argv[ i ], "-wolf" ) )
2410 /* -game should already be set */
2412 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2415 else if( !strcmp( argv[ i ], "-q3" ) )
2417 /* -game should already be set */
2419 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2422 else if( !strcmp( argv[ i ], "-extradist" ) )
2424 extraDist = atof( argv[ i + 1 ] );
2428 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2431 else if( !strcmp( argv[ i ], "-sunonly" ) )
2434 Sys_Printf( "Only computing sunlight\n" );
2437 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2440 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2443 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2446 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2449 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2451 lightmapSearchBlockSize = 1;
2452 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2455 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2457 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2459 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2462 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2464 lightmapSearchBlockSize = atoi(argv[i+1]);
2466 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2469 else if( !strcmp( argv[ i ], "-shade" ) )
2472 Sys_Printf( "Phong shading enabled\n" );
2475 else if( !strcmp( argv[ i ], "-bouncegrid") )
2479 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2482 else if( !strcmp( argv[ i ], "-smooth" ) )
2484 lightSamples = EXTRA_SCALE;
2485 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2488 else if( !strcmp( argv[ i ], "-fast" ) )
2493 Sys_Printf( "Fast mode enabled\n" );
2496 else if( !strcmp( argv[ i ], "-faster" ) )
2502 Sys_Printf( "Faster mode enabled\n" );
2505 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2508 Sys_Printf( "Fast grid lighting enabled\n" );
2511 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2514 Sys_Printf( "Fast bounce mode enabled\n" );
2517 else if( !strcmp( argv[ i ], "-cheap" ) )
2521 Sys_Printf( "Cheap mode enabled\n" );
2524 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2527 Sys_Printf( "Cheap grid mode enabled\n" );
2530 else if( !strcmp( argv[ i ], "-normalmap" ) )
2533 Sys_Printf( "Storing normal map instead of lightmap\n" );
2536 else if( !strcmp( argv[ i ], "-trisoup" ) )
2539 Sys_Printf( "Converting brush faces to triangle soup\n" );
2542 else if( !strcmp( argv[ i ], "-debug" ) )
2545 Sys_Printf( "Lightmap debugging enabled\n" );
2548 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2550 debugSurfaces = qtrue;
2551 Sys_Printf( "Lightmap surface debugging enabled\n" );
2554 else if( !strcmp( argv[ i ], "-debugunused" ) )
2556 debugUnused = qtrue;
2557 Sys_Printf( "Unused luxel debugging enabled\n" );
2560 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2563 Sys_Printf( "Lightmap axis debugging enabled\n" );
2566 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2568 debugCluster = qtrue;
2569 Sys_Printf( "Luxel cluster debugging enabled\n" );
2572 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2574 debugOrigin = qtrue;
2575 Sys_Printf( "Luxel origin debugging enabled\n" );
2578 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2581 debugDeluxemap = qtrue;
2582 Sys_Printf( "Deluxemap debugging enabled\n" );
2585 else if( !strcmp( argv[ i ], "-export" ) )
2587 exportLightmaps = qtrue;
2588 Sys_Printf( "Exporting lightmaps\n" );
2591 else if( !strcmp(argv[ i ], "-notrace" ))
2594 Sys_Printf( "Shadow occlusion disabled\n" );
2596 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2598 patchShadows = qtrue;
2599 Sys_Printf( "Patch shadow casting enabled\n" );
2601 else if( !strcmp( argv[ i ], "-extra" ) )
2603 superSample = EXTRA_SCALE; /* ydnar */
2604 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2606 else if( !strcmp( argv[ i ], "-extrawide" ) )
2608 superSample = EXTRAWIDE_SCALE; /* ydnar */
2609 filter = qtrue; /* ydnar */
2610 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2612 else if( !strcmp( argv[ i ], "-samplesize" ) )
2614 sampleSize = atoi( argv[ i + 1 ] );
2615 if( sampleSize < 1 )
2618 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2620 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2622 minSampleSize = atoi( argv[ i + 1 ] );
2623 if( minSampleSize < 1 )
2626 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2628 else if( !strcmp( argv[ i ], "-samplescale" ) )
2630 sampleScale = atoi( argv[ i + 1 ] );
2632 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2634 else if( !strcmp( argv[ i ], "-novertex" ) )
2636 noVertexLighting = qtrue;
2637 Sys_Printf( "Disabling vertex lighting\n" );
2639 else if( !strcmp( argv[ i ], "-nogrid" ) )
2641 noGridLighting = qtrue;
2642 Sys_Printf( "Disabling grid lighting\n" );
2644 else if( !strcmp( argv[ i ], "-border" ) )
2646 lightmapBorder = qtrue;
2647 Sys_Printf( "Adding debug border to lightmaps\n" );
2649 else if( !strcmp( argv[ i ], "-nosurf" ) )
2652 Sys_Printf( "Not tracing against surfaces\n" );
2654 else if( !strcmp( argv[ i ], "-dump" ) )
2657 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2659 else if( !strcmp( argv[ i ], "-lomem" ) )
2662 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2664 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2666 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2668 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2670 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2672 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2675 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2678 Sys_Printf( "Disabling lightstyles\n" );
2680 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2683 Sys_Printf( "Enabling lightstyles\n" );
2685 else if( !strcmp( argv[ i ], "-keeplights" ))
2688 Sys_Printf( "Leaving light entities on map after compile\n" );
2690 else if( !strcmp( argv[ i ], "-cpma" ) )
2693 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2695 else if( !strcmp( argv[ i ], "-floodlight" ) )
2697 floodlighty = qtrue;
2698 Sys_Printf( "FloodLighting enabled\n" );
2700 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2702 debugnormals = qtrue;
2703 Sys_Printf( "DebugNormals enabled\n" );
2705 else if( !strcmp( argv[ i ], "-lowquality" ) )
2707 floodlight_lowquality = qtrue;
2708 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2711 /* r7: dirtmapping */
2712 else if( !strcmp( argv[ i ], "-dirty" ) )
2715 Sys_Printf( "Dirtmapping enabled\n" );
2717 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2720 Sys_Printf( "Dirtmap debugging enabled\n" );
2722 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2724 dirtMode = atoi( argv[ i + 1 ] );
2725 if( dirtMode != 0 && dirtMode != 1 )
2728 Sys_Printf( "Enabling randomized dirtmapping\n" );
2730 Sys_Printf( "Enabling ordered dir mapping\n" );
2733 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2735 dirtDepth = atof( argv[ i + 1 ] );
2736 if( dirtDepth <= 0.0f )
2738 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2741 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2743 dirtScale = atof( argv[ i + 1 ] );
2744 if( dirtScale <= 0.0f )
2746 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2749 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2751 dirtGain = atof( argv[ i + 1 ] );
2752 if( dirtGain <= 0.0f )
2754 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2757 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2759 lightmapTriangleCheck = qtrue;
2761 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2763 lightmapExtraVisClusterNudge = qtrue;
2765 else if( !strcmp( argv[ i ], "-fill" ) )
2767 lightmapFill = qtrue;
2768 Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2770 /* unhandled args */
2773 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2778 /* fix up samples count */
2779 if(lightRandomSamples)
2781 if(!lightSamplesInsist)
2783 /* approximately match -samples in quality */
2784 switch(lightSamples)
2790 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2796 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2802 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2810 /* fix up lightmap search power */
2811 if(lightmapMergeSize)
2813 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2814 if(lightmapSearchBlockSize < 1)
2815 lightmapSearchBlockSize = 1;
2817 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2820 /* clean up map name */
2821 strcpy( source, ExpandArg( argv[ i ] ) );
2822 StripExtension( source );
2823 DefaultExtension( source, ".bsp" );
2824 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2825 StripExtension( mapSource );
2826 DefaultExtension( mapSource, ".map" );
2828 /* ydnar: set default sample size */
2829 SetDefaultSampleSize( sampleSize );
2831 /* ydnar: handle shaders */
2832 BeginMapShaderFile( source );
2836 Sys_Printf( "Loading %s\n", source );
2838 /* ydnar: load surface file */
2839 LoadSurfaceExtraFile( source );
2842 LoadBSPFile( source );
2844 /* parse bsp entities */
2847 /* inject command line parameters */
2848 InjectCommandLine(argv, 0, argc - 1);
2851 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2852 if( value[ 0 ] != '1' )
2853 LoadMapFile( mapSource, qtrue, qfalse );
2855 /* set the entity/model origins and init yDrawVerts */
2858 /* ydnar: set up optimization */
2862 SetupSurfaceLightmaps();
2864 /* initialize the surface facet tracing */
2867 /* light the world */
2870 /* ydnar: store off lightmaps */
2871 StoreSurfaceLightmaps();
2873 /* write out the bsp */
2875 Sys_Printf( "Writing %s\n", source );
2876 WriteBSPFile( source );
2878 /* ydnar: export lightmaps */
2879 if( exportLightmaps && !externalLightmaps )
2882 /* return to sender */