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 VectorClear( trace->color );
762 VectorClear( trace->colorNoShadow );
763 VectorClear( trace->directionContribution );
765 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
767 /* ydnar: early out */
768 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
771 /* do some culling checks */
772 if( light->type != EMIT_SUN )
774 /* MrE: if the light is behind the surface */
775 if( trace->twoSided == qfalse )
776 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
779 /* ydnar: test pvs */
780 if( !ClusterVisible( trace->cluster, light->cluster ) )
784 /* exact point to polygon form factor */
785 if( light->type == EMIT_AREA )
791 /* project sample point into light plane */
792 d = DotProduct( trace->origin, light->normal ) - light->dist;
795 /* sample point behind plane? */
796 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
799 /* sample plane coincident? */
800 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
804 /* nudge the point so that it is clearly forward of the light */
805 /* so that surfaces meeting a light emitter don't get black edges */
806 if( d > -8.0f && d < 8.0f )
807 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
809 VectorCopy( trace->origin, pushedOrigin );
811 /* get direction and distance */
812 VectorCopy( light->origin, trace->end );
813 dist = SetupTrace( trace );
814 if( dist >= light->envelope )
817 /* ptpff approximation */
820 /* angle attenuation */
821 angle = DotProduct( trace->normal, trace->direction );
823 /* twosided lighting */
824 if( trace->twoSided )
828 /* no deluxemap contribution from "other side" light */
829 doAddDeluxe = qfalse;
833 angle *= -DotProduct( light->normal, trace->direction );
836 else if( angle < 0.0f &&
837 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
840 /* clamp the distance to prevent super hot spots */
841 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
845 add = light->photons / (dist * dist) * angle;
850 addDeluxe = light->photons / (dist * dist) * angle;
852 addDeluxe = light->photons / (dist * dist);
857 /* calculate the contribution */
858 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
861 else if( factor < 0.0f )
863 /* twosided lighting */
864 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
868 /* push light origin to other side of the plane */
869 VectorMA( light->origin, -2.0f, light->normal, trace->end );
870 dist = SetupTrace( trace );
871 if( dist >= light->envelope )
874 /* no deluxemap contribution from "other side" light */
875 doAddDeluxe = qfalse;
881 /* ydnar: moved to here */
882 add = factor * light->add;
889 /* point/spot lights */
890 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
892 /* get direction and distance */
893 VectorCopy( light->origin, trace->end );
894 dist = SetupTrace( trace );
895 if( dist >= light->envelope )
898 /* clamp the distance to prevent super hot spots */
899 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
903 /* angle attenuation */
904 if( light->flags & LIGHT_ATTEN_ANGLE )
906 /* standard Lambert attenuation */
907 float dot = DotProduct( trace->normal, trace->direction );
909 /* twosided lighting */
910 if( trace->twoSided && dot < 0 )
914 /* no deluxemap contribution from "other side" light */
915 doAddDeluxe = qfalse;
918 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
921 if( dot > 0.001f ) // skip coplanar
923 if( dot > 1.0f ) dot = 1.0f;
924 dot = ( dot * 0.5f ) + 0.5f;
936 if( light->angleScale != 0.0f )
938 angle /= light->angleScale;
944 if( light->flags & LIGHT_ATTEN_LINEAR )
946 add = angle * light->photons * linearScale - (dist * light->fade);
953 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
955 addDeluxe = light->photons * linearScale - (dist * light->fade);
957 if( addDeluxe < 0.0f )
963 add = (light->photons / (dist * dist)) * angle;
970 addDeluxe = (light->photons / (dist * dist)) * angle;
972 addDeluxe = (light->photons / (dist * dist));
975 if( addDeluxe < 0.0f )
979 /* handle spotlights */
980 if( light->type == EMIT_SPOT )
982 float distByNormal, radiusAtDist, sampleRadius;
983 vec3_t pointAtDist, distToSample;
985 /* do cone calculation */
986 distByNormal = -DotProduct( trace->displacement, light->normal );
987 if( distByNormal < 0.0f )
989 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
990 radiusAtDist = light->radiusByDist * distByNormal;
991 VectorSubtract( trace->origin, pointAtDist, distToSample );
992 sampleRadius = VectorLength( distToSample );
994 /* outside the cone */
995 if( sampleRadius >= radiusAtDist )
999 if( sampleRadius > (radiusAtDist - 32.0f) )
1001 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1005 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1007 if( addDeluxe < 0.0f )
1013 /* ydnar: sunlight */
1014 else if( light->type == EMIT_SUN )
1016 /* get origin and direction */
1017 VectorAdd( trace->origin, light->origin, trace->end );
1018 dist = SetupTrace( trace );
1020 /* angle attenuation */
1021 if( light->flags & LIGHT_ATTEN_ANGLE )
1023 /* standard Lambert attenuation */
1024 float dot = DotProduct( trace->normal, trace->direction );
1026 /* twosided lighting */
1027 if( trace->twoSided && dot < 0 )
1031 /* no deluxemap contribution from "other side" light */
1032 doAddDeluxe = qfalse;
1035 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1038 if( dot > 0.001f ) // skip coplanar
1040 if( dot > 1.0f ) dot = 1.0f;
1041 dot = ( dot * 0.5f ) + 0.5f;
1054 add = light->photons * angle;
1059 addDeluxe = light->photons * angle;
1061 addDeluxe = light->photons;
1063 if( addDeluxe < 0.0f )
1070 /* VorteX: set noShadow color */
1071 VectorScale(light->color, add, trace->colorNoShadow);
1073 addDeluxe *= colorBrightness;
1077 addDeluxe *= addDeluxeBounceScale;
1078 if( addDeluxe < 0.00390625f )
1079 addDeluxe = 0.00390625f;
1082 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1085 trace->testAll = qtrue;
1086 VectorScale( light->color, add, trace->color );
1088 /* trace to point */
1089 if( trace->testOcclusion && !trace->forceSunlight )
1093 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1095 VectorClear( trace->color );
1096 VectorClear( trace->directionContribution );
1102 /* return to sender */
1106 /* VorteX: set noShadow color */
1107 VectorScale(light->color, add, trace->colorNoShadow);
1109 /* ydnar: changed to a variable number */
1110 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1113 addDeluxe *= colorBrightness;
1115 /* hack land: scale down the radiosity contribution to light directionality.
1116 Deluxemaps fusion many light directions into one. In a rtl process all lights
1117 would contribute individually to the bump map, so several light sources together
1118 would make it more directional (example: a yellow and red lights received from
1119 opposing sides would light one side in red and the other in blue, adding
1120 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1121 neutralize each other making it look like having no direction.
1122 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1123 is modifying the direction applied from directional lights, making it go closer and closer
1124 to the surface normal the bigger is the amount of radiosity received.
1125 So, for preserving the directional lights contributions, we scale down the radiosity
1126 contribution. It's a hack, but there's a reason behind it */
1129 addDeluxe *= addDeluxeBounceScale;
1130 /* better NOT increase it beyond the original value
1131 if( addDeluxe < 0.00390625f )
1132 addDeluxe = 0.00390625f;
1138 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1142 trace->testAll = qfalse;
1143 VectorScale( light->color, add, trace->color );
1147 if( trace->passSolid || trace->opaque )
1149 VectorClear( trace->color );
1150 VectorClear( trace->directionContribution );
1155 /* return to sender */
1163 determines the amount of light reaching a sample (luxel or vertex)
1166 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1172 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1173 VectorClear( colors[ lightmapNum ] );
1175 /* ydnar: normalmap */
1178 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1179 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1180 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1184 /* ydnar: don't bounce ambient all the time */
1186 VectorCopy( ambientColor, colors[ 0 ] );
1188 /* ydnar: trace to all the list of lights pre-stored in tw */
1189 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1192 trace->light = trace->lights[ i ];
1195 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1197 if( styles[ lightmapNum ] == trace->light->style ||
1198 styles[ lightmapNum ] == LS_NONE )
1202 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1203 if( lightmapNum >= MAX_LIGHTMAPS )
1207 LightContributionToSample( trace );
1208 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1211 /* handle negative light */
1212 if( trace->light->flags & LIGHT_NEGATIVE )
1213 VectorScale( trace->color, -1.0f, trace->color );
1216 styles[ lightmapNum ] = trace->light->style;
1219 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1223 colors[ 0 ][ 0 ] >= 255.0f &&
1224 colors[ 0 ][ 1 ] >= 255.0f &&
1225 colors[ 0 ][ 2 ] >= 255.0f )
1233 LightContributionToPoint()
1234 for a given light, how much light/color reaches a given point in space (with no facing)
1235 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1238 int LightContributionToPoint( trace_t *trace )
1245 light = trace->light;
1248 VectorClear( trace->color );
1250 /* ydnar: early out */
1251 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1254 /* is this a sun? */
1255 if( light->type != EMIT_SUN )
1262 if( !ClusterVisible( trace->cluster, light->cluster ) )
1266 /* ydnar: check origin against light's pvs envelope */
1267 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1268 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1269 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1275 /* set light origin */
1276 if( light->type == EMIT_SUN )
1277 VectorAdd( trace->origin, light->origin, trace->end );
1279 VectorCopy( light->origin, trace->end );
1282 dist = SetupTrace( trace );
1285 if( dist > light->envelope )
1287 gridEnvelopeCulled++;
1291 /* ptpff approximation */
1292 if( light->type == EMIT_AREA && faster )
1294 /* clamp the distance to prevent super hot spots */
1295 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1300 add = light->photons / (dist * dist);
1303 /* exact point to polygon form factor */
1304 else if( light->type == EMIT_AREA )
1307 vec3_t pushedOrigin;
1310 /* see if the point is behind the light */
1311 d = DotProduct( trace->origin, light->normal ) - light->dist;
1312 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1315 /* nudge the point so that it is clearly forward of the light */
1316 /* so that surfaces meeting a light emiter don't get black edges */
1317 if( d > -8.0f && d < 8.0f )
1318 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1320 VectorCopy( trace->origin, pushedOrigin );
1322 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1323 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1324 if( factor == 0.0f )
1326 else if( factor < 0.0f )
1328 if( light->flags & LIGHT_TWOSIDED )
1334 /* ydnar: moved to here */
1335 add = factor * light->add;
1338 /* point/spot lights */
1339 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1341 /* clamp the distance to prevent super hot spots */
1342 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1347 if( light->flags & LIGHT_ATTEN_LINEAR )
1349 add = light->photons * linearScale - (dist * light->fade);
1354 add = light->photons / (dist * dist);
1356 /* handle spotlights */
1357 if( light->type == EMIT_SPOT )
1359 float distByNormal, radiusAtDist, sampleRadius;
1360 vec3_t pointAtDist, distToSample;
1363 /* do cone calculation */
1364 distByNormal = -DotProduct( trace->displacement, light->normal );
1365 if( distByNormal < 0.0f )
1367 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1368 radiusAtDist = light->radiusByDist * distByNormal;
1369 VectorSubtract( trace->origin, pointAtDist, distToSample );
1370 sampleRadius = VectorLength( distToSample );
1372 /* outside the cone */
1373 if( sampleRadius >= radiusAtDist )
1377 if( sampleRadius > (radiusAtDist - 32.0f) )
1378 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1382 /* ydnar: sunlight */
1383 else if( light->type == EMIT_SUN )
1386 add = light->photons;
1391 trace->testAll = qtrue;
1392 VectorScale( light->color, add, trace->color );
1394 /* trace to point */
1395 if( trace->testOcclusion && !trace->forceSunlight )
1399 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1401 VectorClear( trace->color );
1406 /* return to sender */
1410 /* unknown light type */
1414 /* ydnar: changed to a variable number */
1415 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1419 trace->testAll = qfalse;
1420 VectorScale( light->color, add, trace->color );
1424 if( trace->passSolid )
1426 VectorClear( trace->color );
1430 /* we have a valid sample */
1438 grid samples are for quickly determining the lighting
1439 of dynamically placed entities in the world
1442 #define MAX_CONTRIBUTIONS 32768
1453 void TraceGrid( int num )
1455 int i, j, x, y, z, mod, numCon, numStyles;
1457 vec3_t baseOrigin, cheapColor, color, thisdir;
1459 bspGridPoint_t *bgp;
1460 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1463 /* get grid points */
1464 gp = &rawGridPoints[ num ];
1465 bgp = &bspGridPoints[ num ];
1467 /* get grid origin */
1469 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1470 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1471 y = mod / gridBounds[ 0 ];
1472 mod -= y * gridBounds[ 0 ];
1475 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1476 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1477 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1479 /* set inhibit sphere */
1480 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1481 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1482 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1483 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1485 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1487 /* find point cluster */
1488 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1489 if( trace.cluster < 0 )
1491 /* try to nudge the origin around to find a valid point */
1492 VectorCopy( trace.origin, baseOrigin );
1493 for( step = 0; (step += 0.005) <= 1.0; )
1495 VectorCopy( baseOrigin, trace.origin );
1496 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1497 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1498 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1500 /* ydnar: changed to find cluster num */
1501 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1502 if( trace.cluster >= 0 )
1506 /* can't find a valid point at all */
1512 trace.testOcclusion = !noTrace;
1513 trace.forceSunlight = qfalse;
1514 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1515 trace.numSurfaces = 0;
1516 trace.surfaces = NULL;
1517 trace.numLights = 0;
1518 trace.lights = NULL;
1522 VectorClear( cheapColor );
1524 /* trace to all the lights, find the major light direction, and divide the
1525 total light between that along the direction and the remaining in the ambient */
1526 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1532 if( !LightContributionToPoint( &trace ) )
1535 /* handle negative light */
1536 if( trace.light->flags & LIGHT_NEGATIVE )
1537 VectorScale( trace.color, -1.0f, trace.color );
1539 /* add a contribution */
1540 VectorCopy( trace.color, contributions[ numCon ].color );
1541 VectorCopy( trace.direction, contributions[ numCon ].dir );
1542 VectorClear( contributions[ numCon ].ambient );
1543 contributions[ numCon ].style = trace.light->style;
1546 /* push average direction around */
1547 addSize = VectorLength( trace.color );
1548 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1550 /* stop after a while */
1551 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1554 /* ydnar: cheap mode */
1555 VectorAdd( cheapColor, trace.color, cheapColor );
1556 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1560 /////// Floodlighting for point //////////////////
1561 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1566 vec3_t dir = { 0, 0, 1 };
1567 float ambientFrac = 0.25f;
1569 trace.testOcclusion = qtrue;
1570 trace.forceSunlight = qfalse;
1571 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1572 trace.testAll = qtrue;
1574 for( k = 0; k < 2; k++ )
1576 if( k == 0 ) // upper hemisphere
1578 trace.normal[0] = 0;
1579 trace.normal[1] = 0;
1580 trace.normal[2] = 1;
1582 else //lower hemisphere
1584 trace.normal[0] = 0;
1585 trace.normal[1] = 0;
1586 trace.normal[2] = -1;
1589 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1591 /* add a fraction as pure ambient, half as top-down direction */
1592 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1593 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1594 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1596 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1597 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1598 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1600 contributions[ numCon ].dir[0] = dir[0];
1601 contributions[ numCon ].dir[1] = dir[1];
1602 contributions[ numCon ].dir[2] = dir[2];
1604 contributions[ numCon ].style = 0;
1606 /* push average direction around */
1607 addSize = VectorLength( contributions[ numCon ].color );
1608 VectorMA( gp->dir, addSize, dir, gp->dir );
1613 /////////////////////
1615 /* normalize to get primary light direction */
1616 VectorNormalize( gp->dir, thisdir );
1618 /* now that we have identified the primary light direction,
1619 go back and separate all the light into directed and ambient */
1622 for( i = 0; i < numCon; i++ )
1624 /* get relative directed strength */
1625 d = DotProduct( contributions[ i ].dir, thisdir );
1626 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1627 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1631 /* find appropriate style */
1632 for( j = 0; j < numStyles; j++ )
1634 if( gp->styles[ j ] == contributions[ i ].style )
1638 /* style not found? */
1639 if( j >= numStyles )
1641 /* add a new style */
1642 if( numStyles < MAX_LIGHTMAPS )
1644 gp->styles[ numStyles ] = contributions[ i ].style;
1645 bgp->styles[ numStyles ] = contributions[ i ].style;
1647 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1655 /* add the directed color */
1656 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1658 /* ambient light will be at 1/4 the value of directed light */
1659 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1660 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1662 /* (Hobbes: always setting it to .25 is hardly any better) */
1663 d = 0.25f * (1.0f - d);
1664 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1666 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1670 * the total light average = ambient value + 0.25 * sum of all directional values
1671 * we can also get the total light average as 0.25 * the sum of all contributions
1673 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1676 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1678 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1683 /* store off sample */
1684 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1687 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1689 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1692 /* set minimum light and copy off to bytes */
1693 VectorCopy( gp->ambient[ i ], color );
1694 for( j = 0; j < 3; j++ )
1695 if( color[ j ] < minGridLight[ j ] )
1696 color[ j ] = minGridLight[ j ];
1698 /* vortex: apply gridscale and gridambientscale here */
1699 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1700 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1705 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1706 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1708 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1709 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1712 /* store direction */
1713 NormalToLatLong( thisdir, bgp->latLong );
1720 calculates the size of the lightgrid and allocates memory
1723 void SetupGrid( void )
1726 vec3_t maxs, oldGridSize;
1731 /* don't do this if not grid lighting */
1732 if( noGridLighting )
1735 /* ydnar: set grid size */
1736 value = ValueForKey( &entities[ 0 ], "gridsize" );
1737 if( value[ 0 ] != '\0' )
1738 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1741 VectorCopy( gridSize, oldGridSize );
1742 for( i = 0; i < 3; i++ )
1743 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1745 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1746 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1748 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1750 /* get world bounds */
1751 for( i = 0; i < 3; i++ )
1753 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1754 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1755 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1759 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1761 /* increase grid size a bit */
1762 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1763 gridSize[ j++ % 3 ] += 16.0f;
1767 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1770 if( !VectorCompare( gridSize, oldGridSize ) )
1772 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1773 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1774 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1777 /* 2nd variable. fixme: is this silly? */
1778 numBSPGridPoints = numRawGridPoints;
1780 /* allocate lightgrid */
1781 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1782 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1784 if( bspGridPoints != NULL )
1785 free( bspGridPoints );
1786 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1787 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1789 /* clear lightgrid */
1790 for( i = 0; i < numRawGridPoints; i++ )
1792 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1793 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1794 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1795 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1797 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1798 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1803 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1810 does what it says...
1813 void LightWorld( void )
1818 qboolean minVertex, minGrid, ps;
1822 /* ydnar: smooth normals */
1825 Sys_Printf( "--- SmoothNormals ---\n" );
1829 /* determine the number of grid points */
1830 Sys_Printf( "--- SetupGrid ---\n" );
1833 /* find the optional minimum lighting values */
1834 GetVectorForKey( &entities[ 0 ], "_color", color );
1835 if( VectorLength( color ) == 0.0f )
1836 VectorSet( color, 1.0, 1.0, 1.0 );
1839 f = FloatForKey( &entities[ 0 ], "_ambient" );
1841 f = FloatForKey( &entities[ 0 ], "ambient" );
1842 VectorScale( color, f, ambientColor );
1844 /* minvertexlight */
1846 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1847 if( value[ 0 ] != '\0' )
1851 VectorScale( color, f, minVertexLight );
1856 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1857 if( value[ 0 ] != '\0' )
1861 VectorScale( color, f, minGridLight );
1865 value = ValueForKey( &entities[ 0 ], "_minlight" );
1866 if( value[ 0 ] != '\0' )
1869 VectorScale( color, f, minLight );
1870 if( minVertex == qfalse )
1871 VectorScale( color, f, minVertexLight );
1872 if( minGrid == qfalse )
1873 VectorScale( color, f, minGridLight );
1876 /* create world lights */
1877 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1878 CreateEntityLights();
1879 CreateSurfaceLights();
1880 Sys_Printf( "%9d point lights\n", numPointLights );
1881 Sys_Printf( "%9d spotlights\n", numSpotLights );
1882 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1883 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1885 /* calculate lightgrid */
1886 if( !noGridLighting )
1888 /* ydnar: set up light envelopes */
1889 SetupEnvelopes( qtrue, fastgrid );
1891 Sys_Printf( "--- TraceGrid ---\n" );
1893 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1895 Sys_Printf( "%d x %d x %d = %d grid\n",
1896 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1898 /* ydnar: emit statistics on light culling */
1899 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1900 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1903 /* slight optimization to remove a sqrt */
1904 subdivideThreshold *= subdivideThreshold;
1906 /* map the world luxels */
1907 Sys_Printf( "--- MapRawLightmap ---\n" );
1908 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1909 Sys_Printf( "%9d luxels\n", numLuxels );
1910 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1911 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1916 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1917 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1920 /* floodlight pass */
1921 FloodlightRawLightmaps();
1923 /* ydnar: set up light envelopes */
1924 SetupEnvelopes( qfalse, fast );
1926 /* light up my world */
1927 lightsPlaneCulled = 0;
1928 lightsEnvelopeCulled = 0;
1929 lightsBoundsCulled = 0;
1930 lightsClusterCulled = 0;
1932 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1933 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1934 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1936 StitchSurfaceLightmaps();
1938 Sys_Printf( "--- IlluminateVertexes ---\n" );
1939 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1940 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1942 /* ydnar: emit statistics on light culling */
1943 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1944 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1945 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1946 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1953 /* store off the bsp between bounces */
1954 StoreSurfaceLightmaps();
1956 Sys_Printf( "Writing %s\n", source );
1957 WriteBSPFile( source );
1960 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1964 VectorClear( ambientColor );
1965 floodlighty = qfalse;
1967 /* generate diffuse lights */
1969 RadCreateDiffuseLights();
1971 /* setup light envelopes */
1972 SetupEnvelopes( qfalse, fastbounce );
1973 if( numLights == 0 )
1975 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1979 /* add to lightgrid */
1982 gridEnvelopeCulled = 0;
1983 gridBoundsCulled = 0;
1985 Sys_Printf( "--- BounceGrid ---\n" );
1987 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1989 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1990 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1993 /* light up my world */
1994 lightsPlaneCulled = 0;
1995 lightsEnvelopeCulled = 0;
1996 lightsBoundsCulled = 0;
1997 lightsClusterCulled = 0;
1999 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2000 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2001 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2002 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2004 StitchSurfaceLightmaps();
2006 Sys_Printf( "--- IlluminateVertexes ---\n" );
2007 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2008 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2010 /* ydnar: emit statistics on light culling */
2011 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2012 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2013 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2014 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2026 main routine for light processing
2029 int LightMain( int argc, char **argv )
2033 char mapSource[ 1024 ];
2035 int lightmapMergeSize = 0;
2039 Sys_Printf( "--- Light ---\n" );
2040 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2042 /* set standard game flags */
2043 wolfLight = game->wolfLight;
2044 if (wolfLight == qtrue)
2045 Sys_Printf( " lightning model: wolf\n" );
2047 Sys_Printf( " lightning model: quake3\n" );
2049 lmCustomSize = game->lightmapSize;
2050 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2052 lightmapGamma = game->lightmapGamma;
2053 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2055 lightmapCompensate = game->lightmapCompensate;
2056 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2058 lightmapExposure = game->lightmapExposure;
2059 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2061 gridScale = game->gridScale;
2062 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2064 gridAmbientScale = game->gridAmbientScale;
2065 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2067 lightAngleHL = game->lightAngleHL;
2069 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2071 noStyles = game->noStyles;
2072 if (noStyles == qtrue)
2073 Sys_Printf( " shader lightstyles hack: disabled\n" );
2075 Sys_Printf( " shader lightstyles hack: enabled\n" );
2077 keepLights = game->keepLights;
2078 if (keepLights == qtrue)
2079 Sys_Printf( " keep lights: enabled\n" );
2081 Sys_Printf( " keep lights: disabled\n" );
2083 patchShadows = game->patchShadows;
2084 if (patchShadows == qtrue)
2085 Sys_Printf( " patch shadows: enabled\n" );
2087 Sys_Printf( " patch shadows: disabled\n" );
2089 deluxemap = game->deluxeMap;
2090 deluxemode = game->deluxeMode;
2091 if (deluxemap == qtrue)
2094 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2096 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2099 Sys_Printf( " deluxemapping: disabled\n" );
2101 Sys_Printf( "--- ProcessCommandLine ---\n" );
2103 /* process commandline arguments */
2104 for( i = 1; i < (argc - 1); i++ )
2106 /* lightsource scaling */
2107 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2109 f = atof( argv[ i + 1 ] );
2111 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2115 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2117 f = atof( argv[ i + 1 ] );
2119 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2123 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2125 f = atof( argv[ i + 1 ] );
2127 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2131 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2133 f = atof( argv[ i + 1 ] );
2135 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2139 else if( !strcmp( argv[ i ], "-scale" ) )
2141 f = atof( argv[ i + 1 ] );
2146 Sys_Printf( "All light scaled by %f\n", f );
2150 else if( !strcmp( argv[ i ], "-gridscale" ) )
2152 f = atof( argv[ i + 1 ] );
2153 Sys_Printf( "Grid lightning scaled by %f\n", f );
2158 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2160 f = atof( argv[ i + 1 ] );
2161 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2162 gridAmbientScale *= f;
2166 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2168 f = atof( argv[ i + 1 ] );
2170 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2171 Sys_Printf( "Grid directionality is %f\n", f );
2172 gridDirectionality *= f;
2176 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2178 f = atof( argv[ i + 1 ] );
2179 if(f > gridDirectionality) f = gridDirectionality;
2181 Sys_Printf( "Grid ambient directionality is %f\n", f );
2182 gridAmbientDirectionality *= f;
2186 else if( !strcmp( argv[ i ], "-gamma" ) )
2188 f = atof( argv[ i + 1 ] );
2190 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2194 else if( !strcmp( argv[ i ], "-exposure" ) )
2196 f = atof( argv[ i + 1 ] );
2197 lightmapExposure = f;
2198 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2202 else if( !strcmp( argv[ i ], "-compensate" ) )
2204 f = atof( argv[ i + 1 ] );
2207 lightmapCompensate = f;
2208 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2212 /* ydnar switches */
2213 else if( !strcmp( argv[ i ], "-bounce" ) )
2215 bounce = atoi( argv[ i + 1 ] );
2218 else if( bounce > 0 )
2219 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2223 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2225 superSample = atoi( argv[ i + 1 ] );
2226 if( superSample < 1 )
2228 else if( superSample > 1 )
2229 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2233 else if( !strcmp( argv[ i ], "-samples" ) )
2235 lightSamples = atoi( argv[ i + 1 ] );
2236 if( lightSamples < 1 )
2238 else if( lightSamples > 1 )
2239 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2243 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2245 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2246 if( lightSamplesSearchBoxSize <= 0 )
2247 lightSamplesSearchBoxSize = 1;
2248 if( lightSamplesSearchBoxSize > 4 )
2249 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2250 else if( lightSamplesSearchBoxSize != 1 )
2251 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2255 else if( !strcmp( argv[ i ], "-filter" ) )
2258 Sys_Printf( "Lightmap filtering enabled\n" );
2261 else if( !strcmp( argv[ i ], "-dark" ) )
2264 Sys_Printf( "Dark lightmap seams enabled\n" );
2267 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2269 shadeAngleDegrees = atof( argv[ i + 1 ] );
2270 if( shadeAngleDegrees < 0.0f )
2271 shadeAngleDegrees = 0.0f;
2272 else if( shadeAngleDegrees > 0.0f )
2275 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2280 else if( !strcmp( argv[ i ], "-thresh" ) )
2282 subdivideThreshold = atof( argv[ i + 1 ] );
2283 if( subdivideThreshold < 0 )
2284 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2286 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2290 else if( !strcmp( argv[ i ], "-approx" ) )
2292 approximateTolerance = atoi( argv[ i + 1 ] );
2293 if( approximateTolerance < 0 )
2294 approximateTolerance = 0;
2295 else if( approximateTolerance > 0 )
2296 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2299 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2302 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2304 else if( !strcmp( argv[ i ], "-deluxemode" ))
2306 deluxemode = atoi( argv[ i + 1 ] );
2307 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2309 Sys_Printf( "Generating modelspace deluxemaps\n" );
2313 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2316 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2319 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2321 else if( !strcmp( argv[ i ], "-external" ) )
2323 externalLightmaps = qtrue;
2324 Sys_Printf( "Storing all lightmaps externally\n" );
2327 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2329 lmCustomSize = atoi( argv[ i + 1 ] );
2331 /* must be a power of 2 and greater than 2 */
2332 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2334 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2335 lmCustomSize = game->lightmapSize;
2338 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2340 /* enable external lightmaps */
2341 if( lmCustomSize != game->lightmapSize )
2343 externalLightmaps = qtrue;
2344 Sys_Printf( "Storing all lightmaps externally\n" );
2348 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2350 lmLimitSize = atoi( argv[ i + 1 ] );
2353 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2356 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2358 lmCustomDir = argv[i + 1];
2360 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2361 externalLightmaps = qtrue;
2362 Sys_Printf( "Storing all lightmaps externally\n" );
2365 /* ydnar: add this to suppress warnings */
2366 else if( !strcmp( argv[ i ], "-custinfoparms") )
2368 Sys_Printf( "Custom info parms enabled\n" );
2369 useCustomInfoParms = qtrue;
2372 else if( !strcmp( argv[ i ], "-wolf" ) )
2374 /* -game should already be set */
2376 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2379 else if( !strcmp( argv[ i ], "-q3" ) )
2381 /* -game should already be set */
2383 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2386 else if( !strcmp( argv[ i ], "-extradist" ) )
2388 extraDist = atof( argv[ i + 1 ] );
2392 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2395 else if( !strcmp( argv[ i ], "-sunonly" ) )
2398 Sys_Printf( "Only computing sunlight\n" );
2401 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2404 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2407 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2410 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2413 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2415 lightmapSearchBlockSize = 1;
2416 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2419 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2421 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2423 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2426 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2428 lightmapSearchBlockSize = atoi(argv[i+1]);
2430 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2433 else if( !strcmp( argv[ i ], "-shade" ) )
2436 Sys_Printf( "Phong shading enabled\n" );
2439 else if( !strcmp( argv[ i ], "-bouncegrid") )
2443 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2446 else if( !strcmp( argv[ i ], "-smooth" ) )
2448 lightSamples = EXTRA_SCALE;
2449 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2452 else if( !strcmp( argv[ i ], "-fast" ) )
2457 Sys_Printf( "Fast mode enabled\n" );
2460 else if( !strcmp( argv[ i ], "-faster" ) )
2466 Sys_Printf( "Faster mode enabled\n" );
2469 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2472 Sys_Printf( "Fast grid lighting enabled\n" );
2475 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2478 Sys_Printf( "Fast bounce mode enabled\n" );
2481 else if( !strcmp( argv[ i ], "-cheap" ) )
2485 Sys_Printf( "Cheap mode enabled\n" );
2488 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2491 Sys_Printf( "Cheap grid mode enabled\n" );
2494 else if( !strcmp( argv[ i ], "-normalmap" ) )
2497 Sys_Printf( "Storing normal map instead of lightmap\n" );
2500 else if( !strcmp( argv[ i ], "-trisoup" ) )
2503 Sys_Printf( "Converting brush faces to triangle soup\n" );
2506 else if( !strcmp( argv[ i ], "-debug" ) )
2509 Sys_Printf( "Lightmap debugging enabled\n" );
2512 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2514 debugSurfaces = qtrue;
2515 Sys_Printf( "Lightmap surface debugging enabled\n" );
2518 else if( !strcmp( argv[ i ], "-debugunused" ) )
2520 debugUnused = qtrue;
2521 Sys_Printf( "Unused luxel debugging enabled\n" );
2524 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2527 Sys_Printf( "Lightmap axis debugging enabled\n" );
2530 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2532 debugCluster = qtrue;
2533 Sys_Printf( "Luxel cluster debugging enabled\n" );
2536 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2538 debugOrigin = qtrue;
2539 Sys_Printf( "Luxel origin debugging enabled\n" );
2542 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2545 debugDeluxemap = qtrue;
2546 Sys_Printf( "Deluxemap debugging enabled\n" );
2549 else if( !strcmp( argv[ i ], "-export" ) )
2551 exportLightmaps = qtrue;
2552 Sys_Printf( "Exporting lightmaps\n" );
2555 else if( !strcmp(argv[ i ], "-notrace" ))
2558 Sys_Printf( "Shadow occlusion disabled\n" );
2560 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2562 patchShadows = qtrue;
2563 Sys_Printf( "Patch shadow casting enabled\n" );
2565 else if( !strcmp( argv[ i ], "-extra" ) )
2567 superSample = EXTRA_SCALE; /* ydnar */
2568 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2570 else if( !strcmp( argv[ i ], "-extrawide" ) )
2572 superSample = EXTRAWIDE_SCALE; /* ydnar */
2573 filter = qtrue; /* ydnar */
2574 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2576 else if( !strcmp( argv[ i ], "-samplesize" ) )
2578 sampleSize = atoi( argv[ i + 1 ] );
2579 if( sampleSize < 1 )
2582 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2584 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2586 minSampleSize = atoi( argv[ i + 1 ] );
2587 if( minSampleSize < 1 )
2590 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2592 else if( !strcmp( argv[ i ], "-samplescale" ) )
2594 sampleScale = atoi( argv[ i + 1 ] );
2596 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2598 else if( !strcmp( argv[ i ], "-novertex" ) )
2600 noVertexLighting = qtrue;
2601 Sys_Printf( "Disabling vertex lighting\n" );
2603 else if( !strcmp( argv[ i ], "-nogrid" ) )
2605 noGridLighting = qtrue;
2606 Sys_Printf( "Disabling grid lighting\n" );
2608 else if( !strcmp( argv[ i ], "-border" ) )
2610 lightmapBorder = qtrue;
2611 Sys_Printf( "Adding debug border to lightmaps\n" );
2613 else if( !strcmp( argv[ i ], "-nosurf" ) )
2616 Sys_Printf( "Not tracing against surfaces\n" );
2618 else if( !strcmp( argv[ i ], "-dump" ) )
2621 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2623 else if( !strcmp( argv[ i ], "-lomem" ) )
2626 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2628 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2630 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2632 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2634 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2636 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2639 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2642 Sys_Printf( "Disabling lightstyles\n" );
2644 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2647 Sys_Printf( "Enabling lightstyles\n" );
2649 else if( !strcmp( argv[ i ], "-keeplights" ))
2652 Sys_Printf( "Leaving light entities on map after compile\n" );
2654 else if( !strcmp( argv[ i ], "-cpma" ) )
2657 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2659 else if( !strcmp( argv[ i ], "-floodlight" ) )
2661 floodlighty = qtrue;
2662 Sys_Printf( "FloodLighting enabled\n" );
2664 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2666 debugnormals = qtrue;
2667 Sys_Printf( "DebugNormals enabled\n" );
2669 else if( !strcmp( argv[ i ], "-lowquality" ) )
2671 floodlight_lowquality = qtrue;
2672 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2675 /* r7: dirtmapping */
2676 else if( !strcmp( argv[ i ], "-dirty" ) )
2679 Sys_Printf( "Dirtmapping enabled\n" );
2681 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2684 Sys_Printf( "Dirtmap debugging enabled\n" );
2686 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2688 dirtMode = atoi( argv[ i + 1 ] );
2689 if( dirtMode != 0 && dirtMode != 1 )
2692 Sys_Printf( "Enabling randomized dirtmapping\n" );
2694 Sys_Printf( "Enabling ordered dir mapping\n" );
2697 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2699 dirtDepth = atof( argv[ i + 1 ] );
2700 if( dirtDepth <= 0.0f )
2702 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2705 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2707 dirtScale = atof( argv[ i + 1 ] );
2708 if( dirtScale <= 0.0f )
2710 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2713 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2715 dirtGain = atof( argv[ i + 1 ] );
2716 if( dirtGain <= 0.0f )
2718 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2721 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2723 lightmapTriangleCheck = qtrue;
2725 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2727 lightmapExtraVisClusterNudge = qtrue;
2729 /* unhandled args */
2732 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2737 /* fix up lightmap search power */
2738 if(lightmapMergeSize)
2740 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2741 if(lightmapSearchBlockSize < 1)
2742 lightmapSearchBlockSize = 1;
2744 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2747 /* clean up map name */
2748 strcpy( source, ExpandArg( argv[ i ] ) );
2749 StripExtension( source );
2750 DefaultExtension( source, ".bsp" );
2751 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2752 StripExtension( mapSource );
2753 DefaultExtension( mapSource, ".map" );
2755 /* ydnar: set default sample size */
2756 SetDefaultSampleSize( sampleSize );
2758 /* ydnar: handle shaders */
2759 BeginMapShaderFile( source );
2763 Sys_Printf( "Loading %s\n", source );
2765 /* ydnar: load surface file */
2766 LoadSurfaceExtraFile( source );
2769 LoadBSPFile( source );
2771 /* parse bsp entities */
2774 /* inject command line parameters */
2775 InjectCommandLine(argv, 0, argc - 1);
2778 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2779 if( value[ 0 ] != '1' )
2780 LoadMapFile( mapSource, qtrue );
2782 /* set the entity/model origins and init yDrawVerts */
2785 /* ydnar: set up optimization */
2789 SetupSurfaceLightmaps();
2791 /* initialize the surface facet tracing */
2794 /* light the world */
2797 /* ydnar: store off lightmaps */
2798 StoreSurfaceLightmaps();
2800 /* write out the bsp */
2802 Sys_Printf( "Writing %s\n", source );
2803 WriteBSPFile( source );
2805 /* ydnar: export lightmaps */
2806 if( exportLightmaps && !externalLightmaps )
2809 /* return to sender */