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;
156 if( value <= 0.0f || iterations < 2 )
159 /* calculate some stuff */
160 step = 2.0f / (iterations - 1);
163 /* basic sun setup */
164 VectorCopy( color, sun.color );
166 sun.filterRadius = filterRadius;
168 sun.style = noStyles ? LS_NORMAL : style;
172 elevationSteps = iterations - 1;
173 angleSteps = elevationSteps * 4;
175 elevationStep = DEG2RAD( 90.0f / iterations ); /* skip elevation 0 */
176 angleStep = DEG2RAD( 360.0f / angleSteps );
178 /* calc individual sun brightness */
179 numSuns = angleSteps * elevationSteps + 1;
180 sun.photons = value / numSuns;
182 /* iterate elevation */
183 elevation = elevationStep * 0.5f;
185 for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
188 for( j = 0; j < angleSteps; j++ )
191 sun.direction[ 0 ] = cos( angle ) * cos( elevation );
192 sun.direction[ 1 ] = sin( angle ) * cos( elevation );
193 sun.direction[ 2 ] = sin( elevation );
194 CreateSunLight( &sun );
201 elevation += elevationStep;
202 angle += angleStep / elevationSteps;
205 /* create vertical sun */
206 VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
207 CreateSunLight( &sun );
217 creates lights from light entities
220 void CreateEntityLights( void )
223 light_t *light, *light2;
229 float intensity, scale, deviance, filterRadius;
230 int spawnflags, flags, numSamples;
234 /* go throught entity list and find lights */
235 for( i = 0; i < numEntities; i++ )
239 name = ValueForKey( e, "classname" );
241 /* ydnar: check for lightJunior */
242 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
244 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
249 /* lights with target names (and therefore styles) are only parsed from BSP */
250 target = ValueForKey( e, "targetname" );
251 if( target[ 0 ] != '\0' && i >= numBSPEntities )
256 light = safe_malloc( sizeof( *light ) );
257 memset( light, 0, sizeof( *light ) );
258 light->next = lights;
261 /* handle spawnflags */
262 spawnflags = IntForKey( e, "spawnflags" );
264 /* ydnar: quake 3+ light behavior */
265 if( wolfLight == qfalse )
267 /* set default flags */
268 flags = LIGHT_Q3A_DEFAULT;
270 /* linear attenuation? */
273 flags |= LIGHT_ATTEN_LINEAR;
274 flags &= ~LIGHT_ATTEN_ANGLE;
277 /* no angle attenuate? */
279 flags &= ~LIGHT_ATTEN_ANGLE;
282 /* ydnar: wolf light behavior */
285 /* set default flags */
286 flags = LIGHT_WOLF_DEFAULT;
288 /* inverse distance squared attenuation? */
291 flags &= ~LIGHT_ATTEN_LINEAR;
292 flags |= LIGHT_ATTEN_ANGLE;
295 /* angle attenuate? */
297 flags |= LIGHT_ATTEN_ANGLE;
300 /* other flags (borrowed from wolf) */
302 /* wolf dark light? */
303 if( (spawnflags & 4) || (spawnflags & 8) )
307 if( spawnflags & 16 )
308 flags &= ~LIGHT_GRID;
314 flags &= ~LIGHT_SURFACES;
317 /* vortex: unnormalized? */
319 flags |= LIGHT_UNNORMALIZED;
321 /* vortex: distance atten? */
323 flags |= LIGHT_ATTEN_DISTANCE;
325 /* store the flags */
326 light->flags = flags;
328 /* ydnar: set fade key (from wolf) */
330 if( light->flags & LIGHT_ATTEN_LINEAR )
332 light->fade = FloatForKey( e, "fade" );
333 if( light->fade == 0.0f )
337 /* ydnar: set angle scaling (from vlight) */
338 light->angleScale = FloatForKey( e, "_anglescale" );
339 if( light->angleScale != 0.0f )
340 light->flags |= LIGHT_ATTEN_ANGLE;
343 GetVectorForKey( e, "origin", light->origin);
344 light->style = IntForKey( e, "_style" );
345 if( light->style == LS_NORMAL )
346 light->style = IntForKey( e, "style" );
347 if( light->style < LS_NORMAL || light->style >= LS_NONE )
348 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
350 if( light->style != LS_NORMAL ) {
351 Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
354 /* set light intensity */
355 intensity = FloatForKey( e, "_light" );
356 if( intensity == 0.0f )
357 intensity = FloatForKey( e, "light" );
358 if( intensity == 0.0f)
361 /* ydnar: set light scale (sof2) */
362 scale = FloatForKey( e, "scale" );
367 /* ydnar: get deviance and samples */
368 deviance = FloatForKey( e, "_deviance" );
369 if( deviance == 0.0f )
370 deviance = FloatForKey( e, "_deviation" );
371 if( deviance == 0.0f )
372 deviance = FloatForKey( e, "_jitter" );
373 numSamples = IntForKey( e, "_samples" );
374 if( deviance < 0.0f || numSamples < 1 )
379 intensity /= numSamples;
381 /* ydnar: get filter radius */
382 filterRadius = FloatForKey( e, "_filterradius" );
383 if( filterRadius == 0.0f )
384 filterRadius = FloatForKey( e, "_filteradius" );
385 if( filterRadius == 0.0f )
386 filterRadius = FloatForKey( e, "_filter" );
387 if( filterRadius < 0.0f )
389 light->filterRadius = filterRadius;
391 /* set light color */
392 _color = ValueForKey( e, "_color" );
393 if( _color && _color[ 0 ] )
395 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
396 if (!(light->flags & LIGHT_UNNORMALIZED))
398 ColorNormalize( light->color, light->color );
402 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
404 light->extraDist = FloatForKey( e, "_extradist" );
405 if(light->extraDist == 0.0f)
406 light->extraDist = extraDist;
408 intensity = intensity * pointScale;
409 light->photons = intensity;
411 light->type = EMIT_POINT;
413 /* set falloff threshold */
414 light->falloffTolerance = falloffTolerance / numSamples;
416 /* lights with a target will be spotlights */
417 target = ValueForKey( e, "target" );
427 e2 = FindTargetEntity( target );
430 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
431 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
435 /* not a point light */
439 /* make a spotlight */
440 GetVectorForKey( e2, "origin", dest );
441 VectorSubtract( dest, light->origin, light->normal );
442 dist = VectorNormalize( light->normal, light->normal );
443 radius = FloatForKey( e, "radius" );
448 light->radiusByDist = (radius + 16) / dist;
449 light->type = EMIT_SPOT;
451 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
452 light->flags &= ~LIGHT_ATTEN_LINEAR;
453 light->flags |= LIGHT_ATTEN_ANGLE;
456 /* ydnar: is this a sun? */
457 _sun = ValueForKey( e, "_sun" );
458 if( _sun[ 0 ] == '1' )
460 /* not a spot light */
463 /* unlink this light */
464 lights = light->next;
467 VectorScale( light->normal, -1.0f, sun.direction );
468 VectorCopy( light->color, sun.color );
469 sun.photons = (intensity / pointScale);
470 sun.deviance = deviance / 180.0f * Q_PI;
471 sun.numSamples = numSamples;
472 sun.style = noStyles ? LS_NORMAL : light->style;
475 /* make a sun light */
476 CreateSunLight( &sun );
478 /* free original light */
482 /* skip the rest of this love story */
488 /* jitter the light */
489 for( j = 1; j < numSamples; j++ )
492 light2 = safe_malloc( sizeof( *light ) );
493 memcpy( light2, light, sizeof( *light ) );
494 light2->next = lights;
498 if( light->type == EMIT_SPOT )
504 light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
505 light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
506 light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
514 CreateSurfaceLights() - ydnar
515 this hijacks the radiosity code to generate surface lights for first pass
518 #define APPROX_BOUNCE 1.0f
520 void CreateSurfaceLights( void )
523 bspDrawSurface_t *ds;
533 /* get sun shader supressor */
534 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
536 /* walk the list of surfaces */
537 for( i = 0; i < numBSPDrawSurfaces; i++ )
539 /* get surface and other bits */
540 ds = &bspDrawSurfaces[ i ];
541 info = &surfaceInfos[ i ];
545 if( si->sun != NULL && nss[ 0 ] != '1' )
547 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
548 CreateSunLight( si->sun );
549 si->sun = NULL; /* FIXME: leak! */
553 if( si->skyLightValue > 0.0f )
555 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
556 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
557 si->skyLightValue = 0.0f; /* FIXME: hack! */
560 /* try to early out */
564 /* autosprite shaders become point lights */
567 /* create an average xyz */
568 VectorAdd( info->mins, info->maxs, origin );
569 VectorScale( origin, 0.5f, origin );
572 light = safe_malloc( sizeof( *light ) );
573 memset( light, 0, sizeof( *light ) );
574 light->next = lights;
578 light->flags = LIGHT_Q3A_DEFAULT;
579 light->type = EMIT_POINT;
580 light->photons = si->value * pointScale;
583 VectorCopy( origin, light->origin );
584 VectorCopy( si->color, light->color );
585 light->falloffTolerance = falloffTolerance;
586 light->style = si->lightStyle;
588 /* add to point light count and continue */
593 /* get subdivision amount */
594 if( si->lightSubdivide > 0 )
595 subdivide = si->lightSubdivide;
597 subdivide = defaultLightSubdivide;
600 switch( ds->surfaceType )
603 case MST_TRIANGLE_SOUP:
604 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
608 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
621 find the offset values for inline models
624 void SetEntityOrigins( void )
632 bspDrawSurface_t *ds;
635 /* ydnar: copy drawverts into private storage for nefarious purposes */
636 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
637 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
639 /* set the entity origins */
640 for( i = 0; i < numEntities; i++ )
642 /* get entity and model */
644 key = ValueForKey( e, "model" );
645 if( key[ 0 ] != '*' )
647 modelnum = atoi( key + 1 );
648 dm = &bspModels[ modelnum ];
650 /* get entity origin */
651 key = ValueForKey( e, "origin" );
652 if( key[ 0 ] == '\0' )
654 GetVectorForKey( e, "origin", origin );
656 /* set origin for all surfaces for this model */
657 for( j = 0; j < dm->numBSPSurfaces; j++ )
660 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
663 for( k = 0; k < ds->numVerts; k++ )
665 f = ds->firstVert + k;
666 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
675 PointToPolygonFormFactor()
676 calculates the area over a point/normal hemisphere a winding covers
677 ydnar: fixme: there has to be a faster way to calculate this
678 without the expensive per-vert sqrts and transcendental functions
679 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
680 between this and the approximation
683 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
685 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
687 vec3_t triVector, triNormal;
689 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
691 float dot, angle, facing;
694 /* this is expensive */
695 for( i = 0; i < w->numpoints; i++ )
697 VectorSubtract( w->p[ i ], point, dirs[ i ] );
698 VectorNormalize( dirs[ i ], dirs[ i ] );
701 /* duplicate first vertex to avoid mod operation */
702 VectorCopy( dirs[ 0 ], dirs[ i ] );
704 /* calculcate relative area */
706 for( i = 0; i < w->numpoints; i++ )
710 dot = DotProduct( dirs[ i ], dirs[ j ] );
712 /* roundoff can cause slight creep, which gives an IND from acos */
715 else if( dot < -1.0f )
721 CrossProduct( dirs[ i ], dirs[ j ], triVector );
722 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
725 facing = DotProduct( normal, triNormal );
726 total += facing * angle;
728 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
729 if( total > 6.3f || total < -6.3f )
733 /* now in the range of 0 to 1 over the entire incoming hemisphere */
734 //% total /= (2.0f * 3.141592657f);
735 total *= ONE_OVER_2PI;
742 LightContributionTosample()
743 determines the amount of light reaching a sample (luxel or vertex) from a given light
746 int LightContributionToSample( trace_t *trace )
752 float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
753 qboolean angledDeluxe = qtrue;
754 float colorBrightness;
755 qboolean doAddDeluxe = qtrue;
758 light = trace->light;
761 trace->forceSubsampling = qfalse; /* to make sure */
762 VectorClear( trace->color );
763 VectorClear( trace->colorNoShadow );
764 VectorClear( trace->directionContribution );
766 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
768 /* ydnar: early out */
769 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
772 /* do some culling checks */
773 if( light->type != EMIT_SUN )
775 /* MrE: if the light is behind the surface */
776 if( trace->twoSided == qfalse )
777 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
780 /* ydnar: test pvs */
781 if( !ClusterVisible( trace->cluster, light->cluster ) )
785 /* exact point to polygon form factor */
786 if( light->type == EMIT_AREA )
792 /* project sample point into light plane */
793 d = DotProduct( trace->origin, light->normal ) - light->dist;
796 /* sample point behind plane? */
797 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
800 /* sample plane coincident? */
801 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
805 /* nudge the point so that it is clearly forward of the light */
806 /* so that surfaces meeting a light emitter don't get black edges */
807 if( d > -8.0f && d < 8.0f )
808 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
810 VectorCopy( trace->origin, pushedOrigin );
812 /* get direction and distance */
813 VectorCopy( light->origin, trace->end );
814 dist = SetupTrace( trace );
815 if( dist >= light->envelope )
818 /* ptpff approximation */
821 /* angle attenuation */
822 angle = DotProduct( trace->normal, trace->direction );
824 /* twosided lighting */
825 if( trace->twoSided )
829 /* no deluxemap contribution from "other side" light */
830 doAddDeluxe = qfalse;
834 angle *= -DotProduct( light->normal, trace->direction );
837 else if( angle < 0.0f &&
838 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
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 /* ydnar: moved to here */
883 add = factor * light->add;
890 /* point/spot lights */
891 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
893 /* get direction and distance */
894 VectorCopy( light->origin, trace->end );
895 dist = SetupTrace( trace );
896 if( dist >= light->envelope )
899 /* clamp the distance to prevent super hot spots */
900 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
904 /* angle attenuation */
905 if( light->flags & LIGHT_ATTEN_ANGLE )
907 /* standard Lambert attenuation */
908 float dot = DotProduct( trace->normal, trace->direction );
910 /* twosided lighting */
911 if( trace->twoSided && dot < 0 )
915 /* no deluxemap contribution from "other side" light */
916 doAddDeluxe = qfalse;
919 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
922 if( dot > 0.001f ) // skip coplanar
924 if( dot > 1.0f ) dot = 1.0f;
925 dot = ( dot * 0.5f ) + 0.5f;
937 if( light->angleScale != 0.0f )
939 angle /= light->angleScale;
945 if( light->flags & LIGHT_ATTEN_LINEAR )
947 add = angle * light->photons * linearScale - (dist * light->fade);
954 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
956 addDeluxe = light->photons * linearScale - (dist * light->fade);
958 if( addDeluxe < 0.0f )
964 add = (light->photons / (dist * dist)) * angle;
971 addDeluxe = (light->photons / (dist * dist)) * angle;
973 addDeluxe = (light->photons / (dist * dist));
976 if( addDeluxe < 0.0f )
980 /* handle spotlights */
981 if( light->type == EMIT_SPOT )
983 float distByNormal, radiusAtDist, sampleRadius;
984 vec3_t pointAtDist, distToSample;
986 /* do cone calculation */
987 distByNormal = -DotProduct( trace->displacement, light->normal );
988 if( distByNormal < 0.0f )
990 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
991 radiusAtDist = light->radiusByDist * distByNormal;
992 VectorSubtract( trace->origin, pointAtDist, distToSample );
993 sampleRadius = VectorLength( distToSample );
995 /* outside the cone */
996 if( sampleRadius >= radiusAtDist )
1000 if( sampleRadius > (radiusAtDist - 32.0f) )
1002 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1006 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1008 if( addDeluxe < 0.0f )
1014 /* ydnar: sunlight */
1015 else if( light->type == EMIT_SUN )
1017 /* get origin and direction */
1018 VectorAdd( trace->origin, light->origin, trace->end );
1019 dist = SetupTrace( trace );
1021 /* angle attenuation */
1022 if( light->flags & LIGHT_ATTEN_ANGLE )
1024 /* standard Lambert attenuation */
1025 float dot = DotProduct( trace->normal, trace->direction );
1027 /* twosided lighting */
1028 if( trace->twoSided && dot < 0 )
1032 /* no deluxemap contribution from "other side" light */
1033 doAddDeluxe = qfalse;
1036 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1039 if( dot > 0.001f ) // skip coplanar
1041 if( dot > 1.0f ) dot = 1.0f;
1042 dot = ( dot * 0.5f ) + 0.5f;
1055 add = light->photons * angle;
1060 addDeluxe = light->photons * angle;
1062 addDeluxe = light->photons;
1064 if( addDeluxe < 0.0f )
1071 /* VorteX: set noShadow color */
1072 VectorScale(light->color, add, trace->colorNoShadow);
1074 addDeluxe *= colorBrightness;
1078 addDeluxe *= addDeluxeBounceScale;
1079 if( addDeluxe < 0.00390625f )
1080 addDeluxe = 0.00390625f;
1083 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1086 trace->testAll = qtrue;
1087 VectorScale( light->color, add, trace->color );
1089 /* trace to point */
1090 if( trace->testOcclusion && !trace->forceSunlight )
1094 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1096 VectorClear( trace->color );
1097 VectorClear( trace->directionContribution );
1103 /* return to sender */
1107 /* VorteX: set noShadow color */
1108 VectorScale(light->color, add, trace->colorNoShadow);
1110 /* ydnar: changed to a variable number */
1111 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1114 addDeluxe *= colorBrightness;
1116 /* hack land: scale down the radiosity contribution to light directionality.
1117 Deluxemaps fusion many light directions into one. In a rtl process all lights
1118 would contribute individually to the bump map, so several light sources together
1119 would make it more directional (example: a yellow and red lights received from
1120 opposing sides would light one side in red and the other in blue, adding
1121 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1122 neutralize each other making it look like having no direction.
1123 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1124 is modifying the direction applied from directional lights, making it go closer and closer
1125 to the surface normal the bigger is the amount of radiosity received.
1126 So, for preserving the directional lights contributions, we scale down the radiosity
1127 contribution. It's a hack, but there's a reason behind it */
1130 addDeluxe *= addDeluxeBounceScale;
1131 /* better NOT increase it beyond the original value
1132 if( addDeluxe < 0.00390625f )
1133 addDeluxe = 0.00390625f;
1139 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1143 trace->testAll = qfalse;
1144 VectorScale( light->color, add, trace->color );
1148 if( trace->passSolid || trace->opaque )
1150 VectorClear( trace->color );
1151 VectorClear( trace->directionContribution );
1156 /* return to sender */
1164 determines the amount of light reaching a sample (luxel or vertex)
1167 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1173 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1174 VectorClear( colors[ lightmapNum ] );
1176 /* ydnar: normalmap */
1179 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1180 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1181 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1185 /* ydnar: don't bounce ambient all the time */
1187 VectorCopy( ambientColor, colors[ 0 ] );
1189 /* ydnar: trace to all the list of lights pre-stored in tw */
1190 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1193 trace->light = trace->lights[ i ];
1196 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1198 if( styles[ lightmapNum ] == trace->light->style ||
1199 styles[ lightmapNum ] == LS_NONE )
1203 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1204 if( lightmapNum >= MAX_LIGHTMAPS )
1208 LightContributionToSample( trace );
1209 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1212 /* handle negative light */
1213 if( trace->light->flags & LIGHT_NEGATIVE )
1214 VectorScale( trace->color, -1.0f, trace->color );
1217 styles[ lightmapNum ] = trace->light->style;
1220 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1224 colors[ 0 ][ 0 ] >= 255.0f &&
1225 colors[ 0 ][ 1 ] >= 255.0f &&
1226 colors[ 0 ][ 2 ] >= 255.0f )
1234 LightContributionToPoint()
1235 for a given light, how much light/color reaches a given point in space (with no facing)
1236 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1239 int LightContributionToPoint( trace_t *trace )
1246 light = trace->light;
1249 VectorClear( trace->color );
1251 /* ydnar: early out */
1252 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1255 /* is this a sun? */
1256 if( light->type != EMIT_SUN )
1263 if( !ClusterVisible( trace->cluster, light->cluster ) )
1267 /* ydnar: check origin against light's pvs envelope */
1268 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1269 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1270 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1276 /* set light origin */
1277 if( light->type == EMIT_SUN )
1278 VectorAdd( trace->origin, light->origin, trace->end );
1280 VectorCopy( light->origin, trace->end );
1283 dist = SetupTrace( trace );
1286 if( dist > light->envelope )
1288 gridEnvelopeCulled++;
1292 /* ptpff approximation */
1293 if( light->type == EMIT_AREA && faster )
1295 /* clamp the distance to prevent super hot spots */
1296 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1301 add = light->photons / (dist * dist);
1304 /* exact point to polygon form factor */
1305 else if( light->type == EMIT_AREA )
1308 vec3_t pushedOrigin;
1311 /* see if the point is behind the light */
1312 d = DotProduct( trace->origin, light->normal ) - light->dist;
1313 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1316 /* nudge the point so that it is clearly forward of the light */
1317 /* so that surfaces meeting a light emiter don't get black edges */
1318 if( d > -8.0f && d < 8.0f )
1319 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1321 VectorCopy( trace->origin, pushedOrigin );
1323 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1324 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1325 if( factor == 0.0f )
1327 else if( factor < 0.0f )
1329 if( light->flags & LIGHT_TWOSIDED )
1335 /* ydnar: moved to here */
1336 add = factor * light->add;
1339 /* point/spot lights */
1340 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1342 /* clamp the distance to prevent super hot spots */
1343 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1348 if( light->flags & LIGHT_ATTEN_LINEAR )
1350 add = light->photons * linearScale - (dist * light->fade);
1355 add = light->photons / (dist * dist);
1357 /* handle spotlights */
1358 if( light->type == EMIT_SPOT )
1360 float distByNormal, radiusAtDist, sampleRadius;
1361 vec3_t pointAtDist, distToSample;
1364 /* do cone calculation */
1365 distByNormal = -DotProduct( trace->displacement, light->normal );
1366 if( distByNormal < 0.0f )
1368 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1369 radiusAtDist = light->radiusByDist * distByNormal;
1370 VectorSubtract( trace->origin, pointAtDist, distToSample );
1371 sampleRadius = VectorLength( distToSample );
1373 /* outside the cone */
1374 if( sampleRadius >= radiusAtDist )
1378 if( sampleRadius > (radiusAtDist - 32.0f) )
1379 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1383 /* ydnar: sunlight */
1384 else if( light->type == EMIT_SUN )
1387 add = light->photons;
1392 trace->testAll = qtrue;
1393 VectorScale( light->color, add, trace->color );
1395 /* trace to point */
1396 if( trace->testOcclusion && !trace->forceSunlight )
1400 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1402 VectorClear( trace->color );
1407 /* return to sender */
1411 /* unknown light type */
1415 /* ydnar: changed to a variable number */
1416 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1420 trace->testAll = qfalse;
1421 VectorScale( light->color, add, trace->color );
1425 if( trace->passSolid )
1427 VectorClear( trace->color );
1431 /* we have a valid sample */
1439 grid samples are for quickly determining the lighting
1440 of dynamically placed entities in the world
1443 #define MAX_CONTRIBUTIONS 32768
1454 void TraceGrid( int num )
1456 int i, j, x, y, z, mod, numCon, numStyles;
1458 vec3_t baseOrigin, cheapColor, color, thisdir;
1460 bspGridPoint_t *bgp;
1461 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1464 /* get grid points */
1465 gp = &rawGridPoints[ num ];
1466 bgp = &bspGridPoints[ num ];
1468 /* get grid origin */
1470 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1471 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1472 y = mod / gridBounds[ 0 ];
1473 mod -= y * gridBounds[ 0 ];
1476 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1477 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1478 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1480 /* set inhibit sphere */
1481 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1482 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1483 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1484 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1486 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1488 /* find point cluster */
1489 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1490 if( trace.cluster < 0 )
1492 /* try to nudge the origin around to find a valid point */
1493 VectorCopy( trace.origin, baseOrigin );
1494 for( step = 0; (step += 0.005) <= 1.0; )
1496 VectorCopy( baseOrigin, trace.origin );
1497 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1498 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1499 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1501 /* ydnar: changed to find cluster num */
1502 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1503 if( trace.cluster >= 0 )
1507 /* can't find a valid point at all */
1513 trace.testOcclusion = !noTrace;
1514 trace.forceSunlight = qfalse;
1515 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1516 trace.numSurfaces = 0;
1517 trace.surfaces = NULL;
1518 trace.numLights = 0;
1519 trace.lights = NULL;
1523 VectorClear( cheapColor );
1525 /* trace to all the lights, find the major light direction, and divide the
1526 total light between that along the direction and the remaining in the ambient */
1527 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1533 if( !LightContributionToPoint( &trace ) )
1536 /* handle negative light */
1537 if( trace.light->flags & LIGHT_NEGATIVE )
1538 VectorScale( trace.color, -1.0f, trace.color );
1540 /* add a contribution */
1541 VectorCopy( trace.color, contributions[ numCon ].color );
1542 VectorCopy( trace.direction, contributions[ numCon ].dir );
1543 VectorClear( contributions[ numCon ].ambient );
1544 contributions[ numCon ].style = trace.light->style;
1547 /* push average direction around */
1548 addSize = VectorLength( trace.color );
1549 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1551 /* stop after a while */
1552 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1555 /* ydnar: cheap mode */
1556 VectorAdd( cheapColor, trace.color, cheapColor );
1557 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1561 /////// Floodlighting for point //////////////////
1562 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1567 vec3_t dir = { 0, 0, 1 };
1568 float ambientFrac = 0.25f;
1570 trace.testOcclusion = qtrue;
1571 trace.forceSunlight = qfalse;
1572 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1573 trace.testAll = qtrue;
1575 for( k = 0; k < 2; k++ )
1577 if( k == 0 ) // upper hemisphere
1579 trace.normal[0] = 0;
1580 trace.normal[1] = 0;
1581 trace.normal[2] = 1;
1583 else //lower hemisphere
1585 trace.normal[0] = 0;
1586 trace.normal[1] = 0;
1587 trace.normal[2] = -1;
1590 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1592 /* add a fraction as pure ambient, half as top-down direction */
1593 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1594 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1595 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1597 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1598 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1599 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1601 contributions[ numCon ].dir[0] = dir[0];
1602 contributions[ numCon ].dir[1] = dir[1];
1603 contributions[ numCon ].dir[2] = dir[2];
1605 contributions[ numCon ].style = 0;
1607 /* push average direction around */
1608 addSize = VectorLength( contributions[ numCon ].color );
1609 VectorMA( gp->dir, addSize, dir, gp->dir );
1614 /////////////////////
1616 /* normalize to get primary light direction */
1617 VectorNormalize( gp->dir, thisdir );
1619 /* now that we have identified the primary light direction,
1620 go back and separate all the light into directed and ambient */
1623 for( i = 0; i < numCon; i++ )
1625 /* get relative directed strength */
1626 d = DotProduct( contributions[ i ].dir, thisdir );
1627 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1628 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1632 /* find appropriate style */
1633 for( j = 0; j < numStyles; j++ )
1635 if( gp->styles[ j ] == contributions[ i ].style )
1639 /* style not found? */
1640 if( j >= numStyles )
1642 /* add a new style */
1643 if( numStyles < MAX_LIGHTMAPS )
1645 gp->styles[ numStyles ] = contributions[ i ].style;
1646 bgp->styles[ numStyles ] = contributions[ i ].style;
1648 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1656 /* add the directed color */
1657 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1659 /* ambient light will be at 1/4 the value of directed light */
1660 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1661 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1663 /* (Hobbes: always setting it to .25 is hardly any better) */
1664 d = 0.25f * (1.0f - d);
1665 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1667 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1671 * the total light average = ambient value + 0.25 * sum of all directional values
1672 * we can also get the total light average as 0.25 * the sum of all contributions
1674 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1677 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1679 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1684 /* store off sample */
1685 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1688 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1690 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1693 /* set minimum light and copy off to bytes */
1694 VectorCopy( gp->ambient[ i ], color );
1695 for( j = 0; j < 3; j++ )
1696 if( color[ j ] < minGridLight[ j ] )
1697 color[ j ] = minGridLight[ j ];
1699 /* vortex: apply gridscale and gridambientscale here */
1700 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1701 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1706 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1707 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1709 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1710 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1713 /* store direction */
1714 NormalToLatLong( thisdir, bgp->latLong );
1721 calculates the size of the lightgrid and allocates memory
1724 void SetupGrid( void )
1727 vec3_t maxs, oldGridSize;
1732 /* don't do this if not grid lighting */
1733 if( noGridLighting )
1736 /* ydnar: set grid size */
1737 value = ValueForKey( &entities[ 0 ], "gridsize" );
1738 if( value[ 0 ] != '\0' )
1739 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1742 VectorCopy( gridSize, oldGridSize );
1743 for( i = 0; i < 3; i++ )
1744 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1746 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1747 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1749 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1751 /* get world bounds */
1752 for( i = 0; i < 3; i++ )
1754 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1755 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1756 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1760 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1762 /* increase grid size a bit */
1763 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1764 gridSize[ j++ % 3 ] += 16.0f;
1768 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1771 if( !VectorCompare( gridSize, oldGridSize ) )
1773 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1774 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1775 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1778 /* 2nd variable. fixme: is this silly? */
1779 numBSPGridPoints = numRawGridPoints;
1781 /* allocate lightgrid */
1782 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1783 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1785 if( bspGridPoints != NULL )
1786 free( bspGridPoints );
1787 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1788 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1790 /* clear lightgrid */
1791 for( i = 0; i < numRawGridPoints; i++ )
1793 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1794 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1795 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1796 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1798 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1799 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1804 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1811 does what it says...
1814 void LightWorld( void )
1819 qboolean minVertex, minGrid, ps;
1823 /* ydnar: smooth normals */
1826 Sys_Printf( "--- SmoothNormals ---\n" );
1830 /* determine the number of grid points */
1831 Sys_Printf( "--- SetupGrid ---\n" );
1834 /* find the optional minimum lighting values */
1835 GetVectorForKey( &entities[ 0 ], "_color", color );
1836 if( VectorLength( color ) == 0.0f )
1837 VectorSet( color, 1.0, 1.0, 1.0 );
1840 f = FloatForKey( &entities[ 0 ], "_ambient" );
1842 f = FloatForKey( &entities[ 0 ], "ambient" );
1843 VectorScale( color, f, ambientColor );
1845 /* minvertexlight */
1847 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1848 if( value[ 0 ] != '\0' )
1852 VectorScale( color, f, minVertexLight );
1857 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1858 if( value[ 0 ] != '\0' )
1862 VectorScale( color, f, minGridLight );
1866 value = ValueForKey( &entities[ 0 ], "_minlight" );
1867 if( value[ 0 ] != '\0' )
1870 VectorScale( color, f, minLight );
1871 if( minVertex == qfalse )
1872 VectorScale( color, f, minVertexLight );
1873 if( minGrid == qfalse )
1874 VectorScale( color, f, minGridLight );
1877 /* create world lights */
1878 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1879 CreateEntityLights();
1880 CreateSurfaceLights();
1881 Sys_Printf( "%9d point lights\n", numPointLights );
1882 Sys_Printf( "%9d spotlights\n", numSpotLights );
1883 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1884 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1886 /* calculate lightgrid */
1887 if( !noGridLighting )
1889 /* ydnar: set up light envelopes */
1890 SetupEnvelopes( qtrue, fastgrid );
1892 Sys_Printf( "--- TraceGrid ---\n" );
1894 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1896 Sys_Printf( "%d x %d x %d = %d grid\n",
1897 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1899 /* ydnar: emit statistics on light culling */
1900 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1901 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1904 /* slight optimization to remove a sqrt */
1905 subdivideThreshold *= subdivideThreshold;
1907 /* map the world luxels */
1908 Sys_Printf( "--- MapRawLightmap ---\n" );
1909 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1910 Sys_Printf( "%9d luxels\n", numLuxels );
1911 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1912 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1917 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1918 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1921 /* floodlight pass */
1922 FloodlightRawLightmaps();
1924 /* ydnar: set up light envelopes */
1925 SetupEnvelopes( qfalse, fast );
1927 /* light up my world */
1928 lightsPlaneCulled = 0;
1929 lightsEnvelopeCulled = 0;
1930 lightsBoundsCulled = 0;
1931 lightsClusterCulled = 0;
1933 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1934 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1935 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1937 StitchSurfaceLightmaps();
1939 Sys_Printf( "--- IlluminateVertexes ---\n" );
1940 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1941 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1943 /* ydnar: emit statistics on light culling */
1944 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1945 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1946 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1947 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1954 /* store off the bsp between bounces */
1955 StoreSurfaceLightmaps();
1957 Sys_Printf( "Writing %s\n", source );
1958 WriteBSPFile( source );
1961 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1965 VectorClear( ambientColor );
1966 floodlighty = qfalse;
1968 /* generate diffuse lights */
1970 RadCreateDiffuseLights();
1972 /* setup light envelopes */
1973 SetupEnvelopes( qfalse, fastbounce );
1974 if( numLights == 0 )
1976 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1980 /* add to lightgrid */
1983 gridEnvelopeCulled = 0;
1984 gridBoundsCulled = 0;
1986 Sys_Printf( "--- BounceGrid ---\n" );
1988 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1990 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1991 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1994 /* light up my world */
1995 lightsPlaneCulled = 0;
1996 lightsEnvelopeCulled = 0;
1997 lightsBoundsCulled = 0;
1998 lightsClusterCulled = 0;
2000 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2001 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2002 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2003 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2005 StitchSurfaceLightmaps();
2007 Sys_Printf( "--- IlluminateVertexes ---\n" );
2008 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2009 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2011 /* ydnar: emit statistics on light culling */
2012 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2013 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2014 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2015 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2027 main routine for light processing
2030 int LightMain( int argc, char **argv )
2034 char mapSource[ 1024 ];
2036 int lightmapMergeSize = 0;
2040 Sys_Printf( "--- Light ---\n" );
2041 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2043 /* set standard game flags */
2044 wolfLight = game->wolfLight;
2045 if (wolfLight == qtrue)
2046 Sys_Printf( " lightning model: wolf\n" );
2048 Sys_Printf( " lightning model: quake3\n" );
2050 lmCustomSize = game->lightmapSize;
2051 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2053 lightmapGamma = game->lightmapGamma;
2054 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2056 lightmapCompensate = game->lightmapCompensate;
2057 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2059 lightmapExposure = game->lightmapExposure;
2060 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2062 gridScale = game->gridScale;
2063 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2065 gridAmbientScale = game->gridAmbientScale;
2066 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2068 lightAngleHL = game->lightAngleHL;
2070 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2072 noStyles = game->noStyles;
2073 if (noStyles == qtrue)
2074 Sys_Printf( " shader lightstyles hack: disabled\n" );
2076 Sys_Printf( " shader lightstyles hack: enabled\n" );
2078 keepLights = game->keepLights;
2079 if (keepLights == qtrue)
2080 Sys_Printf( " keep lights: enabled\n" );
2082 Sys_Printf( " keep lights: disabled\n" );
2084 patchShadows = game->patchShadows;
2085 if (patchShadows == qtrue)
2086 Sys_Printf( " patch shadows: enabled\n" );
2088 Sys_Printf( " patch shadows: disabled\n" );
2090 deluxemap = game->deluxeMap;
2091 deluxemode = game->deluxeMode;
2092 if (deluxemap == qtrue)
2095 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2097 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2100 Sys_Printf( " deluxemapping: disabled\n" );
2102 Sys_Printf( "--- ProcessCommandLine ---\n" );
2104 /* process commandline arguments */
2105 for( i = 1; i < (argc - 1); i++ )
2107 /* lightsource scaling */
2108 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2110 f = atof( argv[ i + 1 ] );
2112 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2116 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2118 f = atof( argv[ i + 1 ] );
2120 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2124 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2126 f = atof( argv[ i + 1 ] );
2128 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2132 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2134 f = atof( argv[ i + 1 ] );
2136 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2140 else if( !strcmp( argv[ i ], "-scale" ) )
2142 f = atof( argv[ i + 1 ] );
2147 Sys_Printf( "All light scaled by %f\n", f );
2151 else if( !strcmp( argv[ i ], "-gridscale" ) )
2153 f = atof( argv[ i + 1 ] );
2154 Sys_Printf( "Grid lightning scaled by %f\n", f );
2159 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2161 f = atof( argv[ i + 1 ] );
2162 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2163 gridAmbientScale *= f;
2167 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2169 f = atof( argv[ i + 1 ] );
2171 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2172 Sys_Printf( "Grid directionality is %f\n", f );
2173 gridDirectionality *= f;
2177 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2179 f = atof( argv[ i + 1 ] );
2180 if(f > gridDirectionality) f = gridDirectionality;
2182 Sys_Printf( "Grid ambient directionality is %f\n", f );
2183 gridAmbientDirectionality *= f;
2187 else if( !strcmp( argv[ i ], "-gamma" ) )
2189 f = atof( argv[ i + 1 ] );
2191 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2195 else if( !strcmp( argv[ i ], "-exposure" ) )
2197 f = atof( argv[ i + 1 ] );
2198 lightmapExposure = f;
2199 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2203 else if( !strcmp( argv[ i ], "-compensate" ) )
2205 f = atof( argv[ i + 1 ] );
2208 lightmapCompensate = f;
2209 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2213 /* ydnar switches */
2214 else if( !strcmp( argv[ i ], "-bounce" ) )
2216 bounce = atoi( argv[ i + 1 ] );
2219 else if( bounce > 0 )
2220 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2224 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2226 superSample = atoi( argv[ i + 1 ] );
2227 if( superSample < 1 )
2229 else if( superSample > 1 )
2230 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2234 else if( !strcmp( argv[ i ], "-samples" ) )
2236 lightSamples = atoi( argv[ i + 1 ] );
2237 if( lightSamples < 1 )
2239 else if( lightSamples > 1 )
2240 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2244 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2246 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2247 if( lightSamplesSearchBoxSize <= 0 )
2248 lightSamplesSearchBoxSize = 1;
2249 if( lightSamplesSearchBoxSize > 4 )
2250 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2251 else if( lightSamplesSearchBoxSize != 1 )
2252 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2256 else if( !strcmp( argv[ i ], "-filter" ) )
2259 Sys_Printf( "Lightmap filtering enabled\n" );
2262 else if( !strcmp( argv[ i ], "-dark" ) )
2265 Sys_Printf( "Dark lightmap seams enabled\n" );
2268 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2270 shadeAngleDegrees = atof( argv[ i + 1 ] );
2271 if( shadeAngleDegrees < 0.0f )
2272 shadeAngleDegrees = 0.0f;
2273 else if( shadeAngleDegrees > 0.0f )
2276 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2281 else if( !strcmp( argv[ i ], "-thresh" ) )
2283 subdivideThreshold = atof( argv[ i + 1 ] );
2284 if( subdivideThreshold < 0 )
2285 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2287 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2291 else if( !strcmp( argv[ i ], "-approx" ) )
2293 approximateTolerance = atoi( argv[ i + 1 ] );
2294 if( approximateTolerance < 0 )
2295 approximateTolerance = 0;
2296 else if( approximateTolerance > 0 )
2297 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2300 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2303 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2305 else if( !strcmp( argv[ i ], "-deluxemode" ))
2307 deluxemode = atoi( argv[ i + 1 ] );
2308 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2310 Sys_Printf( "Generating modelspace deluxemaps\n" );
2314 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2317 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2320 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2322 else if( !strcmp( argv[ i ], "-external" ) )
2324 externalLightmaps = qtrue;
2325 Sys_Printf( "Storing all lightmaps externally\n" );
2328 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2330 lmCustomSize = atoi( argv[ i + 1 ] );
2332 /* must be a power of 2 and greater than 2 */
2333 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2335 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2336 lmCustomSize = game->lightmapSize;
2339 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2341 /* enable external lightmaps */
2342 if( lmCustomSize != game->lightmapSize )
2344 externalLightmaps = qtrue;
2345 Sys_Printf( "Storing all lightmaps externally\n" );
2349 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2351 lmLimitSize = atoi( argv[ i + 1 ] );
2354 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2357 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2359 lmCustomDir = argv[i + 1];
2361 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2362 externalLightmaps = qtrue;
2363 Sys_Printf( "Storing all lightmaps externally\n" );
2366 /* ydnar: add this to suppress warnings */
2367 else if( !strcmp( argv[ i ], "-custinfoparms") )
2369 Sys_Printf( "Custom info parms enabled\n" );
2370 useCustomInfoParms = qtrue;
2373 else if( !strcmp( argv[ i ], "-wolf" ) )
2375 /* -game should already be set */
2377 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2380 else if( !strcmp( argv[ i ], "-q3" ) )
2382 /* -game should already be set */
2384 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2387 else if( !strcmp( argv[ i ], "-extradist" ) )
2389 extraDist = atof( argv[ i + 1 ] );
2393 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2396 else if( !strcmp( argv[ i ], "-sunonly" ) )
2399 Sys_Printf( "Only computing sunlight\n" );
2402 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2405 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2408 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2411 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2414 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2416 lightmapSearchBlockSize = 1;
2417 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2420 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2422 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2424 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2427 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2429 lightmapSearchBlockSize = atoi(argv[i+1]);
2431 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2434 else if( !strcmp( argv[ i ], "-shade" ) )
2437 Sys_Printf( "Phong shading enabled\n" );
2440 else if( !strcmp( argv[ i ], "-bouncegrid") )
2444 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2447 else if( !strcmp( argv[ i ], "-smooth" ) )
2449 lightSamples = EXTRA_SCALE;
2450 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2453 else if( !strcmp( argv[ i ], "-fast" ) )
2458 Sys_Printf( "Fast mode enabled\n" );
2461 else if( !strcmp( argv[ i ], "-faster" ) )
2467 Sys_Printf( "Faster mode enabled\n" );
2470 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2473 Sys_Printf( "Fast grid lighting enabled\n" );
2476 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2479 Sys_Printf( "Fast bounce mode enabled\n" );
2482 else if( !strcmp( argv[ i ], "-cheap" ) )
2486 Sys_Printf( "Cheap mode enabled\n" );
2489 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2492 Sys_Printf( "Cheap grid mode enabled\n" );
2495 else if( !strcmp( argv[ i ], "-normalmap" ) )
2498 Sys_Printf( "Storing normal map instead of lightmap\n" );
2501 else if( !strcmp( argv[ i ], "-trisoup" ) )
2504 Sys_Printf( "Converting brush faces to triangle soup\n" );
2507 else if( !strcmp( argv[ i ], "-debug" ) )
2510 Sys_Printf( "Lightmap debugging enabled\n" );
2513 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2515 debugSurfaces = qtrue;
2516 Sys_Printf( "Lightmap surface debugging enabled\n" );
2519 else if( !strcmp( argv[ i ], "-debugunused" ) )
2521 debugUnused = qtrue;
2522 Sys_Printf( "Unused luxel debugging enabled\n" );
2525 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2528 Sys_Printf( "Lightmap axis debugging enabled\n" );
2531 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2533 debugCluster = qtrue;
2534 Sys_Printf( "Luxel cluster debugging enabled\n" );
2537 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2539 debugOrigin = qtrue;
2540 Sys_Printf( "Luxel origin debugging enabled\n" );
2543 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2546 debugDeluxemap = qtrue;
2547 Sys_Printf( "Deluxemap debugging enabled\n" );
2550 else if( !strcmp( argv[ i ], "-export" ) )
2552 exportLightmaps = qtrue;
2553 Sys_Printf( "Exporting lightmaps\n" );
2556 else if( !strcmp(argv[ i ], "-notrace" ))
2559 Sys_Printf( "Shadow occlusion disabled\n" );
2561 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2563 patchShadows = qtrue;
2564 Sys_Printf( "Patch shadow casting enabled\n" );
2566 else if( !strcmp( argv[ i ], "-extra" ) )
2568 superSample = EXTRA_SCALE; /* ydnar */
2569 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2571 else if( !strcmp( argv[ i ], "-extrawide" ) )
2573 superSample = EXTRAWIDE_SCALE; /* ydnar */
2574 filter = qtrue; /* ydnar */
2575 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2577 else if( !strcmp( argv[ i ], "-samplesize" ) )
2579 sampleSize = atoi( argv[ i + 1 ] );
2580 if( sampleSize < 1 )
2583 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2585 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2587 minSampleSize = atoi( argv[ i + 1 ] );
2588 if( minSampleSize < 1 )
2591 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2593 else if( !strcmp( argv[ i ], "-samplescale" ) )
2595 sampleScale = atoi( argv[ i + 1 ] );
2597 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2599 else if( !strcmp( argv[ i ], "-novertex" ) )
2601 noVertexLighting = qtrue;
2602 Sys_Printf( "Disabling vertex lighting\n" );
2604 else if( !strcmp( argv[ i ], "-nogrid" ) )
2606 noGridLighting = qtrue;
2607 Sys_Printf( "Disabling grid lighting\n" );
2609 else if( !strcmp( argv[ i ], "-border" ) )
2611 lightmapBorder = qtrue;
2612 Sys_Printf( "Adding debug border to lightmaps\n" );
2614 else if( !strcmp( argv[ i ], "-nosurf" ) )
2617 Sys_Printf( "Not tracing against surfaces\n" );
2619 else if( !strcmp( argv[ i ], "-dump" ) )
2622 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2624 else if( !strcmp( argv[ i ], "-lomem" ) )
2627 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2629 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2631 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2633 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2635 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2637 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2640 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2643 Sys_Printf( "Disabling lightstyles\n" );
2645 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2648 Sys_Printf( "Enabling lightstyles\n" );
2650 else if( !strcmp( argv[ i ], "-keeplights" ))
2653 Sys_Printf( "Leaving light entities on map after compile\n" );
2655 else if( !strcmp( argv[ i ], "-cpma" ) )
2658 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2660 else if( !strcmp( argv[ i ], "-floodlight" ) )
2662 floodlighty = qtrue;
2663 Sys_Printf( "FloodLighting enabled\n" );
2665 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2667 debugnormals = qtrue;
2668 Sys_Printf( "DebugNormals enabled\n" );
2670 else if( !strcmp( argv[ i ], "-lowquality" ) )
2672 floodlight_lowquality = qtrue;
2673 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2676 /* r7: dirtmapping */
2677 else if( !strcmp( argv[ i ], "-dirty" ) )
2680 Sys_Printf( "Dirtmapping enabled\n" );
2682 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2685 Sys_Printf( "Dirtmap debugging enabled\n" );
2687 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2689 dirtMode = atoi( argv[ i + 1 ] );
2690 if( dirtMode != 0 && dirtMode != 1 )
2693 Sys_Printf( "Enabling randomized dirtmapping\n" );
2695 Sys_Printf( "Enabling ordered dir mapping\n" );
2698 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2700 dirtDepth = atof( argv[ i + 1 ] );
2701 if( dirtDepth <= 0.0f )
2703 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2706 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2708 dirtScale = atof( argv[ i + 1 ] );
2709 if( dirtScale <= 0.0f )
2711 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2714 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2716 dirtGain = atof( argv[ i + 1 ] );
2717 if( dirtGain <= 0.0f )
2719 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2722 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2724 lightmapTriangleCheck = qtrue;
2726 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2728 lightmapExtraVisClusterNudge = qtrue;
2730 /* unhandled args */
2733 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2738 /* fix up lightmap search power */
2739 if(lightmapMergeSize)
2741 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2742 if(lightmapSearchBlockSize < 1)
2743 lightmapSearchBlockSize = 1;
2745 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2748 /* clean up map name */
2749 strcpy( source, ExpandArg( argv[ i ] ) );
2750 StripExtension( source );
2751 DefaultExtension( source, ".bsp" );
2752 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2753 StripExtension( mapSource );
2754 DefaultExtension( mapSource, ".map" );
2756 /* ydnar: set default sample size */
2757 SetDefaultSampleSize( sampleSize );
2759 /* ydnar: handle shaders */
2760 BeginMapShaderFile( source );
2764 Sys_Printf( "Loading %s\n", source );
2766 /* ydnar: load surface file */
2767 LoadSurfaceExtraFile( source );
2770 LoadBSPFile( source );
2772 /* parse bsp entities */
2775 /* inject command line parameters */
2776 InjectCommandLine(argv, 0, argc - 1);
2779 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2780 if( value[ 0 ] != '1' )
2781 LoadMapFile( mapSource, qtrue );
2783 /* set the entity/model origins and init yDrawVerts */
2786 /* ydnar: set up optimization */
2790 SetupSurfaceLightmaps();
2792 /* initialize the surface facet tracing */
2795 /* light the world */
2798 /* ydnar: store off lightmaps */
2799 StoreSurfaceLightmaps();
2801 /* write out the bsp */
2803 Sys_Printf( "Writing %s\n", source );
2804 WriteBSPFile( source );
2806 /* ydnar: export lightmaps */
2807 if( exportLightmaps && !externalLightmaps )
2810 /* return to sender */