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 = 0.0f; /* 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 trace->forceSubsampling *= add;
1095 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1097 VectorClear( trace->color );
1098 VectorClear( trace->directionContribution );
1104 /* return to sender */
1108 /* VorteX: set noShadow color */
1109 VectorScale(light->color, add, trace->colorNoShadow);
1111 /* ydnar: changed to a variable number */
1112 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1115 addDeluxe *= colorBrightness;
1117 /* hack land: scale down the radiosity contribution to light directionality.
1118 Deluxemaps fusion many light directions into one. In a rtl process all lights
1119 would contribute individually to the bump map, so several light sources together
1120 would make it more directional (example: a yellow and red lights received from
1121 opposing sides would light one side in red and the other in blue, adding
1122 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1123 neutralize each other making it look like having no direction.
1124 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1125 is modifying the direction applied from directional lights, making it go closer and closer
1126 to the surface normal the bigger is the amount of radiosity received.
1127 So, for preserving the directional lights contributions, we scale down the radiosity
1128 contribution. It's a hack, but there's a reason behind it */
1131 addDeluxe *= addDeluxeBounceScale;
1132 /* better NOT increase it beyond the original value
1133 if( addDeluxe < 0.00390625f )
1134 addDeluxe = 0.00390625f;
1140 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1144 trace->testAll = qfalse;
1145 VectorScale( light->color, add, trace->color );
1149 trace->forceSubsampling *= add;
1150 if( trace->passSolid || trace->opaque )
1152 VectorClear( trace->color );
1153 VectorClear( trace->directionContribution );
1158 /* return to sender */
1166 determines the amount of light reaching a sample (luxel or vertex)
1169 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1175 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1176 VectorClear( colors[ lightmapNum ] );
1178 /* ydnar: normalmap */
1181 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1182 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1183 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1187 /* ydnar: don't bounce ambient all the time */
1189 VectorCopy( ambientColor, colors[ 0 ] );
1191 /* ydnar: trace to all the list of lights pre-stored in tw */
1192 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1195 trace->light = trace->lights[ i ];
1198 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1200 if( styles[ lightmapNum ] == trace->light->style ||
1201 styles[ lightmapNum ] == LS_NONE )
1205 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1206 if( lightmapNum >= MAX_LIGHTMAPS )
1210 LightContributionToSample( trace );
1211 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1214 /* handle negative light */
1215 if( trace->light->flags & LIGHT_NEGATIVE )
1216 VectorScale( trace->color, -1.0f, trace->color );
1219 styles[ lightmapNum ] = trace->light->style;
1222 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1226 colors[ 0 ][ 0 ] >= 255.0f &&
1227 colors[ 0 ][ 1 ] >= 255.0f &&
1228 colors[ 0 ][ 2 ] >= 255.0f )
1236 LightContributionToPoint()
1237 for a given light, how much light/color reaches a given point in space (with no facing)
1238 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1241 int LightContributionToPoint( trace_t *trace )
1248 light = trace->light;
1251 VectorClear( trace->color );
1253 /* ydnar: early out */
1254 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1257 /* is this a sun? */
1258 if( light->type != EMIT_SUN )
1265 if( !ClusterVisible( trace->cluster, light->cluster ) )
1269 /* ydnar: check origin against light's pvs envelope */
1270 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1271 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1272 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1278 /* set light origin */
1279 if( light->type == EMIT_SUN )
1280 VectorAdd( trace->origin, light->origin, trace->end );
1282 VectorCopy( light->origin, trace->end );
1285 dist = SetupTrace( trace );
1288 if( dist > light->envelope )
1290 gridEnvelopeCulled++;
1294 /* ptpff approximation */
1295 if( light->type == EMIT_AREA && faster )
1297 /* clamp the distance to prevent super hot spots */
1298 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1303 add = light->photons / (dist * dist);
1306 /* exact point to polygon form factor */
1307 else if( light->type == EMIT_AREA )
1310 vec3_t pushedOrigin;
1313 /* see if the point is behind the light */
1314 d = DotProduct( trace->origin, light->normal ) - light->dist;
1315 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1318 /* nudge the point so that it is clearly forward of the light */
1319 /* so that surfaces meeting a light emiter don't get black edges */
1320 if( d > -8.0f && d < 8.0f )
1321 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1323 VectorCopy( trace->origin, pushedOrigin );
1325 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1326 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1327 if( factor == 0.0f )
1329 else if( factor < 0.0f )
1331 if( light->flags & LIGHT_TWOSIDED )
1337 /* ydnar: moved to here */
1338 add = factor * light->add;
1341 /* point/spot lights */
1342 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1344 /* clamp the distance to prevent super hot spots */
1345 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1350 if( light->flags & LIGHT_ATTEN_LINEAR )
1352 add = light->photons * linearScale - (dist * light->fade);
1357 add = light->photons / (dist * dist);
1359 /* handle spotlights */
1360 if( light->type == EMIT_SPOT )
1362 float distByNormal, radiusAtDist, sampleRadius;
1363 vec3_t pointAtDist, distToSample;
1366 /* do cone calculation */
1367 distByNormal = -DotProduct( trace->displacement, light->normal );
1368 if( distByNormal < 0.0f )
1370 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1371 radiusAtDist = light->radiusByDist * distByNormal;
1372 VectorSubtract( trace->origin, pointAtDist, distToSample );
1373 sampleRadius = VectorLength( distToSample );
1375 /* outside the cone */
1376 if( sampleRadius >= radiusAtDist )
1380 if( sampleRadius > (radiusAtDist - 32.0f) )
1381 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1385 /* ydnar: sunlight */
1386 else if( light->type == EMIT_SUN )
1389 add = light->photons;
1394 trace->testAll = qtrue;
1395 VectorScale( light->color, add, trace->color );
1397 /* trace to point */
1398 if( trace->testOcclusion && !trace->forceSunlight )
1402 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1404 VectorClear( trace->color );
1409 /* return to sender */
1413 /* unknown light type */
1417 /* ydnar: changed to a variable number */
1418 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1422 trace->testAll = qfalse;
1423 VectorScale( light->color, add, trace->color );
1427 if( trace->passSolid )
1429 VectorClear( trace->color );
1433 /* we have a valid sample */
1441 grid samples are for quickly determining the lighting
1442 of dynamically placed entities in the world
1445 #define MAX_CONTRIBUTIONS 32768
1456 void TraceGrid( int num )
1458 int i, j, x, y, z, mod, numCon, numStyles;
1460 vec3_t baseOrigin, cheapColor, color, thisdir;
1462 bspGridPoint_t *bgp;
1463 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1466 /* get grid points */
1467 gp = &rawGridPoints[ num ];
1468 bgp = &bspGridPoints[ num ];
1470 /* get grid origin */
1472 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1473 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1474 y = mod / gridBounds[ 0 ];
1475 mod -= y * gridBounds[ 0 ];
1478 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1479 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1480 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1482 /* set inhibit sphere */
1483 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1484 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1485 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1486 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1488 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1490 /* find point cluster */
1491 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1492 if( trace.cluster < 0 )
1494 /* try to nudge the origin around to find a valid point */
1495 VectorCopy( trace.origin, baseOrigin );
1496 for( step = 0; (step += 0.005) <= 1.0; )
1498 VectorCopy( baseOrigin, trace.origin );
1499 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1500 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1501 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1503 /* ydnar: changed to find cluster num */
1504 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1505 if( trace.cluster >= 0 )
1509 /* can't find a valid point at all */
1515 trace.testOcclusion = !noTrace;
1516 trace.forceSunlight = qfalse;
1517 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1518 trace.numSurfaces = 0;
1519 trace.surfaces = NULL;
1520 trace.numLights = 0;
1521 trace.lights = NULL;
1525 VectorClear( cheapColor );
1527 /* trace to all the lights, find the major light direction, and divide the
1528 total light between that along the direction and the remaining in the ambient */
1529 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1535 if( !LightContributionToPoint( &trace ) )
1538 /* handle negative light */
1539 if( trace.light->flags & LIGHT_NEGATIVE )
1540 VectorScale( trace.color, -1.0f, trace.color );
1542 /* add a contribution */
1543 VectorCopy( trace.color, contributions[ numCon ].color );
1544 VectorCopy( trace.direction, contributions[ numCon ].dir );
1545 VectorClear( contributions[ numCon ].ambient );
1546 contributions[ numCon ].style = trace.light->style;
1549 /* push average direction around */
1550 addSize = VectorLength( trace.color );
1551 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1553 /* stop after a while */
1554 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1557 /* ydnar: cheap mode */
1558 VectorAdd( cheapColor, trace.color, cheapColor );
1559 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1563 /////// Floodlighting for point //////////////////
1564 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1569 vec3_t dir = { 0, 0, 1 };
1570 float ambientFrac = 0.25f;
1572 trace.testOcclusion = qtrue;
1573 trace.forceSunlight = qfalse;
1574 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1575 trace.testAll = qtrue;
1577 for( k = 0; k < 2; k++ )
1579 if( k == 0 ) // upper hemisphere
1581 trace.normal[0] = 0;
1582 trace.normal[1] = 0;
1583 trace.normal[2] = 1;
1585 else //lower hemisphere
1587 trace.normal[0] = 0;
1588 trace.normal[1] = 0;
1589 trace.normal[2] = -1;
1592 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1594 /* add a fraction as pure ambient, half as top-down direction */
1595 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1596 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1597 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1599 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1600 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1601 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1603 contributions[ numCon ].dir[0] = dir[0];
1604 contributions[ numCon ].dir[1] = dir[1];
1605 contributions[ numCon ].dir[2] = dir[2];
1607 contributions[ numCon ].style = 0;
1609 /* push average direction around */
1610 addSize = VectorLength( contributions[ numCon ].color );
1611 VectorMA( gp->dir, addSize, dir, gp->dir );
1616 /////////////////////
1618 /* normalize to get primary light direction */
1619 VectorNormalize( gp->dir, thisdir );
1621 /* now that we have identified the primary light direction,
1622 go back and separate all the light into directed and ambient */
1625 for( i = 0; i < numCon; i++ )
1627 /* get relative directed strength */
1628 d = DotProduct( contributions[ i ].dir, thisdir );
1629 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1630 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1634 /* find appropriate style */
1635 for( j = 0; j < numStyles; j++ )
1637 if( gp->styles[ j ] == contributions[ i ].style )
1641 /* style not found? */
1642 if( j >= numStyles )
1644 /* add a new style */
1645 if( numStyles < MAX_LIGHTMAPS )
1647 gp->styles[ numStyles ] = contributions[ i ].style;
1648 bgp->styles[ numStyles ] = contributions[ i ].style;
1650 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1658 /* add the directed color */
1659 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1661 /* ambient light will be at 1/4 the value of directed light */
1662 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1663 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1665 /* (Hobbes: always setting it to .25 is hardly any better) */
1666 d = 0.25f * (1.0f - d);
1667 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1669 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1673 * the total light average = ambient value + 0.25 * sum of all directional values
1674 * we can also get the total light average as 0.25 * the sum of all contributions
1676 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1679 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1681 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1686 /* store off sample */
1687 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1690 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1692 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1695 /* set minimum light and copy off to bytes */
1696 VectorCopy( gp->ambient[ i ], color );
1697 for( j = 0; j < 3; j++ )
1698 if( color[ j ] < minGridLight[ j ] )
1699 color[ j ] = minGridLight[ j ];
1701 /* vortex: apply gridscale and gridambientscale here */
1702 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1703 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1708 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1709 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1711 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1712 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1715 /* store direction */
1716 NormalToLatLong( thisdir, bgp->latLong );
1723 calculates the size of the lightgrid and allocates memory
1726 void SetupGrid( void )
1729 vec3_t maxs, oldGridSize;
1734 /* don't do this if not grid lighting */
1735 if( noGridLighting )
1738 /* ydnar: set grid size */
1739 value = ValueForKey( &entities[ 0 ], "gridsize" );
1740 if( value[ 0 ] != '\0' )
1741 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1744 VectorCopy( gridSize, oldGridSize );
1745 for( i = 0; i < 3; i++ )
1746 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1748 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1749 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1751 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1753 /* get world bounds */
1754 for( i = 0; i < 3; i++ )
1756 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1757 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1758 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1762 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1764 /* increase grid size a bit */
1765 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1766 gridSize[ j++ % 3 ] += 16.0f;
1770 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1773 if( !VectorCompare( gridSize, oldGridSize ) )
1775 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1776 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1777 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1780 /* 2nd variable. fixme: is this silly? */
1781 numBSPGridPoints = numRawGridPoints;
1783 /* allocate lightgrid */
1784 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1785 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1787 if( bspGridPoints != NULL )
1788 free( bspGridPoints );
1789 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1790 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1792 /* clear lightgrid */
1793 for( i = 0; i < numRawGridPoints; i++ )
1795 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1796 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1797 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1798 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1800 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1801 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1806 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1813 does what it says...
1816 void LightWorld( void )
1821 qboolean minVertex, minGrid, ps;
1825 /* ydnar: smooth normals */
1828 Sys_Printf( "--- SmoothNormals ---\n" );
1832 /* determine the number of grid points */
1833 Sys_Printf( "--- SetupGrid ---\n" );
1836 /* find the optional minimum lighting values */
1837 GetVectorForKey( &entities[ 0 ], "_color", color );
1838 if( VectorLength( color ) == 0.0f )
1839 VectorSet( color, 1.0, 1.0, 1.0 );
1842 f = FloatForKey( &entities[ 0 ], "_ambient" );
1844 f = FloatForKey( &entities[ 0 ], "ambient" );
1845 VectorScale( color, f, ambientColor );
1847 /* minvertexlight */
1849 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1850 if( value[ 0 ] != '\0' )
1854 VectorScale( color, f, minVertexLight );
1859 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1860 if( value[ 0 ] != '\0' )
1864 VectorScale( color, f, minGridLight );
1868 value = ValueForKey( &entities[ 0 ], "_minlight" );
1869 if( value[ 0 ] != '\0' )
1872 VectorScale( color, f, minLight );
1873 if( minVertex == qfalse )
1874 VectorScale( color, f, minVertexLight );
1875 if( minGrid == qfalse )
1876 VectorScale( color, f, minGridLight );
1879 /* create world lights */
1880 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1881 CreateEntityLights();
1882 CreateSurfaceLights();
1883 Sys_Printf( "%9d point lights\n", numPointLights );
1884 Sys_Printf( "%9d spotlights\n", numSpotLights );
1885 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1886 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1888 /* calculate lightgrid */
1889 if( !noGridLighting )
1891 /* ydnar: set up light envelopes */
1892 SetupEnvelopes( qtrue, fastgrid );
1894 Sys_Printf( "--- TraceGrid ---\n" );
1896 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1898 Sys_Printf( "%d x %d x %d = %d grid\n",
1899 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1901 /* ydnar: emit statistics on light culling */
1902 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1903 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1906 /* slight optimization to remove a sqrt */
1907 subdivideThreshold *= subdivideThreshold;
1909 /* map the world luxels */
1910 Sys_Printf( "--- MapRawLightmap ---\n" );
1911 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1912 Sys_Printf( "%9d luxels\n", numLuxels );
1913 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1914 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1919 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1920 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1923 /* floodlight pass */
1924 FloodlightRawLightmaps();
1926 /* ydnar: set up light envelopes */
1927 SetupEnvelopes( qfalse, fast );
1929 /* light up my world */
1930 lightsPlaneCulled = 0;
1931 lightsEnvelopeCulled = 0;
1932 lightsBoundsCulled = 0;
1933 lightsClusterCulled = 0;
1935 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1936 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1937 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1939 StitchSurfaceLightmaps();
1941 Sys_Printf( "--- IlluminateVertexes ---\n" );
1942 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1943 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1945 /* ydnar: emit statistics on light culling */
1946 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1947 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1948 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1949 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1956 /* store off the bsp between bounces */
1957 StoreSurfaceLightmaps();
1959 Sys_Printf( "Writing %s\n", source );
1960 WriteBSPFile( source );
1963 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1967 VectorClear( ambientColor );
1968 floodlighty = qfalse;
1970 /* generate diffuse lights */
1972 RadCreateDiffuseLights();
1974 /* setup light envelopes */
1975 SetupEnvelopes( qfalse, fastbounce );
1976 if( numLights == 0 )
1978 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1982 /* add to lightgrid */
1985 gridEnvelopeCulled = 0;
1986 gridBoundsCulled = 0;
1988 Sys_Printf( "--- BounceGrid ---\n" );
1990 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1992 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1993 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1996 /* light up my world */
1997 lightsPlaneCulled = 0;
1998 lightsEnvelopeCulled = 0;
1999 lightsBoundsCulled = 0;
2000 lightsClusterCulled = 0;
2002 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2003 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2004 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2005 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2007 StitchSurfaceLightmaps();
2009 Sys_Printf( "--- IlluminateVertexes ---\n" );
2010 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2011 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2013 /* ydnar: emit statistics on light culling */
2014 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2015 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2016 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2017 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2029 main routine for light processing
2032 int LightMain( int argc, char **argv )
2036 char mapSource[ 1024 ];
2038 int lightmapMergeSize = 0;
2042 Sys_Printf( "--- Light ---\n" );
2043 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2045 /* set standard game flags */
2046 wolfLight = game->wolfLight;
2047 if (wolfLight == qtrue)
2048 Sys_Printf( " lightning model: wolf\n" );
2050 Sys_Printf( " lightning model: quake3\n" );
2052 lmCustomSize = game->lightmapSize;
2053 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2055 lightmapGamma = game->lightmapGamma;
2056 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2058 lightmapCompensate = game->lightmapCompensate;
2059 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2061 lightmapExposure = game->lightmapExposure;
2062 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2064 gridScale = game->gridScale;
2065 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2067 gridAmbientScale = game->gridAmbientScale;
2068 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2070 lightAngleHL = game->lightAngleHL;
2072 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2074 noStyles = game->noStyles;
2075 if (noStyles == qtrue)
2076 Sys_Printf( " shader lightstyles hack: disabled\n" );
2078 Sys_Printf( " shader lightstyles hack: enabled\n" );
2080 keepLights = game->keepLights;
2081 if (keepLights == qtrue)
2082 Sys_Printf( " keep lights: enabled\n" );
2084 Sys_Printf( " keep lights: disabled\n" );
2086 patchShadows = game->patchShadows;
2087 if (patchShadows == qtrue)
2088 Sys_Printf( " patch shadows: enabled\n" );
2090 Sys_Printf( " patch shadows: disabled\n" );
2092 deluxemap = game->deluxeMap;
2093 deluxemode = game->deluxeMode;
2094 if (deluxemap == qtrue)
2097 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2099 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2102 Sys_Printf( " deluxemapping: disabled\n" );
2104 Sys_Printf( "--- ProcessCommandLine ---\n" );
2106 /* process commandline arguments */
2107 for( i = 1; i < (argc - 1); i++ )
2109 /* lightsource scaling */
2110 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2112 f = atof( argv[ i + 1 ] );
2114 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2118 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2120 f = atof( argv[ i + 1 ] );
2122 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2126 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2128 f = atof( argv[ i + 1 ] );
2130 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2134 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2136 f = atof( argv[ i + 1 ] );
2138 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2142 else if( !strcmp( argv[ i ], "-scale" ) )
2144 f = atof( argv[ i + 1 ] );
2149 Sys_Printf( "All light scaled by %f\n", f );
2153 else if( !strcmp( argv[ i ], "-gridscale" ) )
2155 f = atof( argv[ i + 1 ] );
2156 Sys_Printf( "Grid lightning scaled by %f\n", f );
2161 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2163 f = atof( argv[ i + 1 ] );
2164 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2165 gridAmbientScale *= f;
2169 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2171 f = atof( argv[ i + 1 ] );
2173 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2174 Sys_Printf( "Grid directionality is %f\n", f );
2175 gridDirectionality *= f;
2179 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2181 f = atof( argv[ i + 1 ] );
2182 if(f > gridDirectionality) f = gridDirectionality;
2184 Sys_Printf( "Grid ambient directionality is %f\n", f );
2185 gridAmbientDirectionality *= f;
2189 else if( !strcmp( argv[ i ], "-gamma" ) )
2191 f = atof( argv[ i + 1 ] );
2193 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2197 else if( !strcmp( argv[ i ], "-exposure" ) )
2199 f = atof( argv[ i + 1 ] );
2200 lightmapExposure = f;
2201 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2205 else if( !strcmp( argv[ i ], "-compensate" ) )
2207 f = atof( argv[ i + 1 ] );
2210 lightmapCompensate = f;
2211 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2215 /* ydnar switches */
2216 else if( !strcmp( argv[ i ], "-bounce" ) )
2218 bounce = atoi( argv[ i + 1 ] );
2221 else if( bounce > 0 )
2222 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2226 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2228 superSample = atoi( argv[ i + 1 ] );
2229 if( superSample < 1 )
2231 else if( superSample > 1 )
2232 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2236 else if( !strcmp( argv[ i ], "-samples" ) )
2238 lightSamples = atoi( argv[ i + 1 ] );
2239 if( lightSamples < 1 )
2241 else if( lightSamples > 1 )
2242 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2246 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2248 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2249 if( lightSamplesSearchBoxSize <= 0 )
2250 lightSamplesSearchBoxSize = 1;
2251 if( lightSamplesSearchBoxSize > 4 )
2252 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2253 else if( lightSamplesSearchBoxSize != 1 )
2254 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2258 else if( !strcmp( argv[ i ], "-filter" ) )
2261 Sys_Printf( "Lightmap filtering enabled\n" );
2264 else if( !strcmp( argv[ i ], "-dark" ) )
2267 Sys_Printf( "Dark lightmap seams enabled\n" );
2270 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2272 shadeAngleDegrees = atof( argv[ i + 1 ] );
2273 if( shadeAngleDegrees < 0.0f )
2274 shadeAngleDegrees = 0.0f;
2275 else if( shadeAngleDegrees > 0.0f )
2278 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2283 else if( !strcmp( argv[ i ], "-thresh" ) )
2285 subdivideThreshold = atof( argv[ i + 1 ] );
2286 if( subdivideThreshold < 0 )
2287 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2289 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2293 else if( !strcmp( argv[ i ], "-approx" ) )
2295 approximateTolerance = atoi( argv[ i + 1 ] );
2296 if( approximateTolerance < 0 )
2297 approximateTolerance = 0;
2298 else if( approximateTolerance > 0 )
2299 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2302 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2305 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2307 else if( !strcmp( argv[ i ], "-deluxemode" ))
2309 deluxemode = atoi( argv[ i + 1 ] );
2310 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2312 Sys_Printf( "Generating modelspace deluxemaps\n" );
2316 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2319 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2322 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2324 else if( !strcmp( argv[ i ], "-external" ) )
2326 externalLightmaps = qtrue;
2327 Sys_Printf( "Storing all lightmaps externally\n" );
2330 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2332 lmCustomSize = atoi( argv[ i + 1 ] );
2334 /* must be a power of 2 and greater than 2 */
2335 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2337 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2338 lmCustomSize = game->lightmapSize;
2341 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2343 /* enable external lightmaps */
2344 if( lmCustomSize != game->lightmapSize )
2346 externalLightmaps = qtrue;
2347 Sys_Printf( "Storing all lightmaps externally\n" );
2351 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2353 lmLimitSize = atoi( argv[ i + 1 ] );
2356 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2359 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2361 lmCustomDir = argv[i + 1];
2363 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2364 externalLightmaps = qtrue;
2365 Sys_Printf( "Storing all lightmaps externally\n" );
2368 /* ydnar: add this to suppress warnings */
2369 else if( !strcmp( argv[ i ], "-custinfoparms") )
2371 Sys_Printf( "Custom info parms enabled\n" );
2372 useCustomInfoParms = qtrue;
2375 else if( !strcmp( argv[ i ], "-wolf" ) )
2377 /* -game should already be set */
2379 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2382 else if( !strcmp( argv[ i ], "-q3" ) )
2384 /* -game should already be set */
2386 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2389 else if( !strcmp( argv[ i ], "-extradist" ) )
2391 extraDist = atof( argv[ i + 1 ] );
2395 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2398 else if( !strcmp( argv[ i ], "-sunonly" ) )
2401 Sys_Printf( "Only computing sunlight\n" );
2404 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2407 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2410 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2413 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2416 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2418 lightmapSearchBlockSize = 1;
2419 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2422 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2424 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2426 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2429 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2431 lightmapSearchBlockSize = atoi(argv[i+1]);
2433 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2436 else if( !strcmp( argv[ i ], "-shade" ) )
2439 Sys_Printf( "Phong shading enabled\n" );
2442 else if( !strcmp( argv[ i ], "-bouncegrid") )
2446 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2449 else if( !strcmp( argv[ i ], "-smooth" ) )
2451 lightSamples = EXTRA_SCALE;
2452 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2455 else if( !strcmp( argv[ i ], "-fast" ) )
2460 Sys_Printf( "Fast mode enabled\n" );
2463 else if( !strcmp( argv[ i ], "-faster" ) )
2469 Sys_Printf( "Faster mode enabled\n" );
2472 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2475 Sys_Printf( "Fast grid lighting enabled\n" );
2478 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2481 Sys_Printf( "Fast bounce mode enabled\n" );
2484 else if( !strcmp( argv[ i ], "-cheap" ) )
2488 Sys_Printf( "Cheap mode enabled\n" );
2491 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2494 Sys_Printf( "Cheap grid mode enabled\n" );
2497 else if( !strcmp( argv[ i ], "-normalmap" ) )
2500 Sys_Printf( "Storing normal map instead of lightmap\n" );
2503 else if( !strcmp( argv[ i ], "-trisoup" ) )
2506 Sys_Printf( "Converting brush faces to triangle soup\n" );
2509 else if( !strcmp( argv[ i ], "-debug" ) )
2512 Sys_Printf( "Lightmap debugging enabled\n" );
2515 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2517 debugSurfaces = qtrue;
2518 Sys_Printf( "Lightmap surface debugging enabled\n" );
2521 else if( !strcmp( argv[ i ], "-debugunused" ) )
2523 debugUnused = qtrue;
2524 Sys_Printf( "Unused luxel debugging enabled\n" );
2527 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2530 Sys_Printf( "Lightmap axis debugging enabled\n" );
2533 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2535 debugCluster = qtrue;
2536 Sys_Printf( "Luxel cluster debugging enabled\n" );
2539 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2541 debugOrigin = qtrue;
2542 Sys_Printf( "Luxel origin debugging enabled\n" );
2545 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2548 debugDeluxemap = qtrue;
2549 Sys_Printf( "Deluxemap debugging enabled\n" );
2552 else if( !strcmp( argv[ i ], "-export" ) )
2554 exportLightmaps = qtrue;
2555 Sys_Printf( "Exporting lightmaps\n" );
2558 else if( !strcmp(argv[ i ], "-notrace" ))
2561 Sys_Printf( "Shadow occlusion disabled\n" );
2563 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2565 patchShadows = qtrue;
2566 Sys_Printf( "Patch shadow casting enabled\n" );
2568 else if( !strcmp( argv[ i ], "-extra" ) )
2570 superSample = EXTRA_SCALE; /* ydnar */
2571 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2573 else if( !strcmp( argv[ i ], "-extrawide" ) )
2575 superSample = EXTRAWIDE_SCALE; /* ydnar */
2576 filter = qtrue; /* ydnar */
2577 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2579 else if( !strcmp( argv[ i ], "-samplesize" ) )
2581 sampleSize = atoi( argv[ i + 1 ] );
2582 if( sampleSize < 1 )
2585 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2587 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2589 minSampleSize = atoi( argv[ i + 1 ] );
2590 if( minSampleSize < 1 )
2593 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2595 else if( !strcmp( argv[ i ], "-samplescale" ) )
2597 sampleScale = atoi( argv[ i + 1 ] );
2599 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2601 else if( !strcmp( argv[ i ], "-novertex" ) )
2603 noVertexLighting = qtrue;
2604 Sys_Printf( "Disabling vertex lighting\n" );
2606 else if( !strcmp( argv[ i ], "-nogrid" ) )
2608 noGridLighting = qtrue;
2609 Sys_Printf( "Disabling grid lighting\n" );
2611 else if( !strcmp( argv[ i ], "-border" ) )
2613 lightmapBorder = qtrue;
2614 Sys_Printf( "Adding debug border to lightmaps\n" );
2616 else if( !strcmp( argv[ i ], "-nosurf" ) )
2619 Sys_Printf( "Not tracing against surfaces\n" );
2621 else if( !strcmp( argv[ i ], "-dump" ) )
2624 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2626 else if( !strcmp( argv[ i ], "-lomem" ) )
2629 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2631 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2633 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2635 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2637 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2639 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2642 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2645 Sys_Printf( "Disabling lightstyles\n" );
2647 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2650 Sys_Printf( "Enabling lightstyles\n" );
2652 else if( !strcmp( argv[ i ], "-keeplights" ))
2655 Sys_Printf( "Leaving light entities on map after compile\n" );
2657 else if( !strcmp( argv[ i ], "-cpma" ) )
2660 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2662 else if( !strcmp( argv[ i ], "-floodlight" ) )
2664 floodlighty = qtrue;
2665 Sys_Printf( "FloodLighting enabled\n" );
2667 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2669 debugnormals = qtrue;
2670 Sys_Printf( "DebugNormals enabled\n" );
2672 else if( !strcmp( argv[ i ], "-lowquality" ) )
2674 floodlight_lowquality = qtrue;
2675 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2678 /* r7: dirtmapping */
2679 else if( !strcmp( argv[ i ], "-dirty" ) )
2682 Sys_Printf( "Dirtmapping enabled\n" );
2684 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2687 Sys_Printf( "Dirtmap debugging enabled\n" );
2689 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2691 dirtMode = atoi( argv[ i + 1 ] );
2692 if( dirtMode != 0 && dirtMode != 1 )
2695 Sys_Printf( "Enabling randomized dirtmapping\n" );
2697 Sys_Printf( "Enabling ordered dir mapping\n" );
2700 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2702 dirtDepth = atof( argv[ i + 1 ] );
2703 if( dirtDepth <= 0.0f )
2705 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2708 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2710 dirtScale = atof( argv[ i + 1 ] );
2711 if( dirtScale <= 0.0f )
2713 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2716 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2718 dirtGain = atof( argv[ i + 1 ] );
2719 if( dirtGain <= 0.0f )
2721 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2724 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2726 lightmapTriangleCheck = qtrue;
2728 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2730 lightmapExtraVisClusterNudge = qtrue;
2732 /* unhandled args */
2735 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2740 /* fix up lightmap search power */
2741 if(lightmapMergeSize)
2743 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2744 if(lightmapSearchBlockSize < 1)
2745 lightmapSearchBlockSize = 1;
2747 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2750 /* clean up map name */
2751 strcpy( source, ExpandArg( argv[ i ] ) );
2752 StripExtension( source );
2753 DefaultExtension( source, ".bsp" );
2754 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2755 StripExtension( mapSource );
2756 DefaultExtension( mapSource, ".map" );
2758 /* ydnar: set default sample size */
2759 SetDefaultSampleSize( sampleSize );
2761 /* ydnar: handle shaders */
2762 BeginMapShaderFile( source );
2766 Sys_Printf( "Loading %s\n", source );
2768 /* ydnar: load surface file */
2769 LoadSurfaceExtraFile( source );
2772 LoadBSPFile( source );
2774 /* parse bsp entities */
2777 /* inject command line parameters */
2778 InjectCommandLine(argv, 0, argc - 1);
2781 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2782 if( value[ 0 ] != '1' )
2783 LoadMapFile( mapSource, qtrue );
2785 /* set the entity/model origins and init yDrawVerts */
2788 /* ydnar: set up optimization */
2792 SetupSurfaceLightmaps();
2794 /* initialize the surface facet tracing */
2797 /* light the world */
2800 /* ydnar: store off lightmaps */
2801 StoreSurfaceLightmaps();
2803 /* write out the bsp */
2805 Sys_Printf( "Writing %s\n", source );
2806 WriteBSPFile( source );
2808 /* ydnar: export lightmaps */
2809 if( exportLightmaps && !externalLightmaps )
2812 /* return to sender */