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 && angle < 0 )
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)) )
842 /* no deluxemap contribution from "other side" light */
843 doAddDeluxe = qfalse;
846 /* clamp the distance to prevent super hot spots */
847 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
851 add = light->photons / (dist * dist) * angle;
856 addDeluxe = light->photons / (dist * dist) * angle;
858 addDeluxe = light->photons / (dist * dist);
863 /* calculate the contribution */
864 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
867 else if( factor < 0.0f )
869 /* twosided lighting */
870 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
874 /* push light origin to other side of the plane */
875 VectorMA( light->origin, -2.0f, light->normal, trace->end );
876 dist = SetupTrace( trace );
877 if( dist >= light->envelope )
880 /* no deluxemap contribution from "other side" light */
881 doAddDeluxe = qfalse;
887 /* also don't deluxe if the direction is on the wrong side */
888 if(DotProduct(trace->normal, trace->direction) < 0)
890 /* no deluxemap contribution from "other side" light */
891 doAddDeluxe = qfalse;
894 /* ydnar: moved to here */
895 add = factor * light->add;
902 /* point/spot lights */
903 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
905 /* get direction and distance */
906 VectorCopy( light->origin, trace->end );
907 dist = SetupTrace( trace );
908 if( dist >= light->envelope )
911 /* clamp the distance to prevent super hot spots */
912 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
916 /* angle attenuation */
917 if( light->flags & LIGHT_ATTEN_ANGLE )
919 /* standard Lambert attenuation */
920 float dot = DotProduct( trace->normal, trace->direction );
922 /* twosided lighting */
923 if( trace->twoSided && dot < 0 )
927 /* no deluxemap contribution from "other side" light */
928 doAddDeluxe = qfalse;
931 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
934 if( dot > 0.001f ) // skip coplanar
936 if( dot > 1.0f ) dot = 1.0f;
937 dot = ( dot * 0.5f ) + 0.5f;
949 if( light->angleScale != 0.0f )
951 angle /= light->angleScale;
957 if( light->flags & LIGHT_ATTEN_LINEAR )
959 add = angle * light->photons * linearScale - (dist * light->fade);
966 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
968 addDeluxe = light->photons * linearScale - (dist * light->fade);
970 if( addDeluxe < 0.0f )
976 add = (light->photons / (dist * dist)) * angle;
983 addDeluxe = (light->photons / (dist * dist)) * angle;
985 addDeluxe = (light->photons / (dist * dist));
988 if( addDeluxe < 0.0f )
992 /* handle spotlights */
993 if( light->type == EMIT_SPOT )
995 float distByNormal, radiusAtDist, sampleRadius;
996 vec3_t pointAtDist, distToSample;
998 /* do cone calculation */
999 distByNormal = -DotProduct( trace->displacement, light->normal );
1000 if( distByNormal < 0.0f )
1002 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1003 radiusAtDist = light->radiusByDist * distByNormal;
1004 VectorSubtract( trace->origin, pointAtDist, distToSample );
1005 sampleRadius = VectorLength( distToSample );
1007 /* outside the cone */
1008 if( sampleRadius >= radiusAtDist )
1012 if( sampleRadius > (radiusAtDist - 32.0f) )
1014 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1018 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1020 if( addDeluxe < 0.0f )
1026 /* ydnar: sunlight */
1027 else if( light->type == EMIT_SUN )
1029 /* get origin and direction */
1030 VectorAdd( trace->origin, light->origin, trace->end );
1031 dist = SetupTrace( trace );
1033 /* angle attenuation */
1034 if( light->flags & LIGHT_ATTEN_ANGLE )
1036 /* standard Lambert attenuation */
1037 float dot = DotProduct( trace->normal, trace->direction );
1039 /* twosided lighting */
1040 if( trace->twoSided && dot < 0 )
1044 /* no deluxemap contribution from "other side" light */
1045 doAddDeluxe = qfalse;
1048 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1051 if( dot > 0.001f ) // skip coplanar
1053 if( dot > 1.0f ) dot = 1.0f;
1054 dot = ( dot * 0.5f ) + 0.5f;
1067 add = light->photons * angle;
1072 addDeluxe = light->photons * angle;
1074 addDeluxe = light->photons;
1076 if( addDeluxe < 0.0f )
1083 /* VorteX: set noShadow color */
1084 VectorScale(light->color, add, trace->colorNoShadow);
1086 addDeluxe *= colorBrightness;
1090 addDeluxe *= addDeluxeBounceScale;
1091 if( addDeluxe < 0.00390625f )
1092 addDeluxe = 0.00390625f;
1095 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1098 trace->testAll = qtrue;
1099 VectorScale( light->color, add, trace->color );
1101 /* trace to point */
1102 if( trace->testOcclusion && !trace->forceSunlight )
1106 trace->forceSubsampling *= add;
1107 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1109 VectorClear( trace->color );
1110 VectorClear( trace->directionContribution );
1116 /* return to sender */
1120 Error("Light of undefined type!");
1122 /* VorteX: set noShadow color */
1123 VectorScale(light->color, add, trace->colorNoShadow);
1125 /* ydnar: changed to a variable number */
1126 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1129 addDeluxe *= colorBrightness;
1131 /* hack land: scale down the radiosity contribution to light directionality.
1132 Deluxemaps fusion many light directions into one. In a rtl process all lights
1133 would contribute individually to the bump map, so several light sources together
1134 would make it more directional (example: a yellow and red lights received from
1135 opposing sides would light one side in red and the other in blue, adding
1136 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1137 neutralize each other making it look like having no direction.
1138 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1139 is modifying the direction applied from directional lights, making it go closer and closer
1140 to the surface normal the bigger is the amount of radiosity received.
1141 So, for preserving the directional lights contributions, we scale down the radiosity
1142 contribution. It's a hack, but there's a reason behind it */
1145 addDeluxe *= addDeluxeBounceScale;
1146 /* better NOT increase it beyond the original value
1147 if( addDeluxe < 0.00390625f )
1148 addDeluxe = 0.00390625f;
1154 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1158 trace->testAll = qfalse;
1159 VectorScale( light->color, add, trace->color );
1163 trace->forceSubsampling *= add;
1164 if( trace->passSolid || trace->opaque )
1166 VectorClear( trace->color );
1167 VectorClear( trace->directionContribution );
1172 /* return to sender */
1180 determines the amount of light reaching a sample (luxel or vertex)
1183 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1189 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1190 VectorClear( colors[ lightmapNum ] );
1192 /* ydnar: normalmap */
1195 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1196 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1197 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1201 /* ydnar: don't bounce ambient all the time */
1203 VectorCopy( ambientColor, colors[ 0 ] );
1205 /* ydnar: trace to all the list of lights pre-stored in tw */
1206 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1209 trace->light = trace->lights[ i ];
1212 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1214 if( styles[ lightmapNum ] == trace->light->style ||
1215 styles[ lightmapNum ] == LS_NONE )
1219 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1220 if( lightmapNum >= MAX_LIGHTMAPS )
1224 LightContributionToSample( trace );
1225 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1228 /* handle negative light */
1229 if( trace->light->flags & LIGHT_NEGATIVE )
1230 VectorScale( trace->color, -1.0f, trace->color );
1233 styles[ lightmapNum ] = trace->light->style;
1236 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1240 colors[ 0 ][ 0 ] >= 255.0f &&
1241 colors[ 0 ][ 1 ] >= 255.0f &&
1242 colors[ 0 ][ 2 ] >= 255.0f )
1250 LightContributionToPoint()
1251 for a given light, how much light/color reaches a given point in space (with no facing)
1252 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1255 int LightContributionToPoint( trace_t *trace )
1262 light = trace->light;
1265 VectorClear( trace->color );
1267 /* ydnar: early out */
1268 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1271 /* is this a sun? */
1272 if( light->type != EMIT_SUN )
1279 if( !ClusterVisible( trace->cluster, light->cluster ) )
1283 /* ydnar: check origin against light's pvs envelope */
1284 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1285 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1286 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1292 /* set light origin */
1293 if( light->type == EMIT_SUN )
1294 VectorAdd( trace->origin, light->origin, trace->end );
1296 VectorCopy( light->origin, trace->end );
1299 dist = SetupTrace( trace );
1302 if( dist > light->envelope )
1304 gridEnvelopeCulled++;
1308 /* ptpff approximation */
1309 if( light->type == EMIT_AREA && faster )
1311 /* clamp the distance to prevent super hot spots */
1312 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1317 add = light->photons / (dist * dist);
1320 /* exact point to polygon form factor */
1321 else if( light->type == EMIT_AREA )
1324 vec3_t pushedOrigin;
1327 /* see if the point is behind the light */
1328 d = DotProduct( trace->origin, light->normal ) - light->dist;
1329 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1332 /* nudge the point so that it is clearly forward of the light */
1333 /* so that surfaces meeting a light emiter don't get black edges */
1334 if( d > -8.0f && d < 8.0f )
1335 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1337 VectorCopy( trace->origin, pushedOrigin );
1339 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1340 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1341 if( factor == 0.0f )
1343 else if( factor < 0.0f )
1345 if( light->flags & LIGHT_TWOSIDED )
1351 /* ydnar: moved to here */
1352 add = factor * light->add;
1355 /* point/spot lights */
1356 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1358 /* clamp the distance to prevent super hot spots */
1359 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1364 if( light->flags & LIGHT_ATTEN_LINEAR )
1366 add = light->photons * linearScale - (dist * light->fade);
1371 add = light->photons / (dist * dist);
1373 /* handle spotlights */
1374 if( light->type == EMIT_SPOT )
1376 float distByNormal, radiusAtDist, sampleRadius;
1377 vec3_t pointAtDist, distToSample;
1380 /* do cone calculation */
1381 distByNormal = -DotProduct( trace->displacement, light->normal );
1382 if( distByNormal < 0.0f )
1384 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1385 radiusAtDist = light->radiusByDist * distByNormal;
1386 VectorSubtract( trace->origin, pointAtDist, distToSample );
1387 sampleRadius = VectorLength( distToSample );
1389 /* outside the cone */
1390 if( sampleRadius >= radiusAtDist )
1394 if( sampleRadius > (radiusAtDist - 32.0f) )
1395 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1399 /* ydnar: sunlight */
1400 else if( light->type == EMIT_SUN )
1403 add = light->photons;
1408 trace->testAll = qtrue;
1409 VectorScale( light->color, add, trace->color );
1411 /* trace to point */
1412 if( trace->testOcclusion && !trace->forceSunlight )
1416 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1418 VectorClear( trace->color );
1423 /* return to sender */
1427 /* unknown light type */
1431 /* ydnar: changed to a variable number */
1432 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1436 trace->testAll = qfalse;
1437 VectorScale( light->color, add, trace->color );
1441 if( trace->passSolid )
1443 VectorClear( trace->color );
1447 /* we have a valid sample */
1455 grid samples are for quickly determining the lighting
1456 of dynamically placed entities in the world
1459 #define MAX_CONTRIBUTIONS 32768
1470 void TraceGrid( int num )
1472 int i, j, x, y, z, mod, numCon, numStyles;
1474 vec3_t baseOrigin, cheapColor, color, thisdir;
1476 bspGridPoint_t *bgp;
1477 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1480 /* get grid points */
1481 gp = &rawGridPoints[ num ];
1482 bgp = &bspGridPoints[ num ];
1484 /* get grid origin */
1486 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1487 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1488 y = mod / gridBounds[ 0 ];
1489 mod -= y * gridBounds[ 0 ];
1492 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1493 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1494 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1496 /* set inhibit sphere */
1497 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1498 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1499 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1500 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1502 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1504 /* find point cluster */
1505 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1506 if( trace.cluster < 0 )
1508 /* try to nudge the origin around to find a valid point */
1509 VectorCopy( trace.origin, baseOrigin );
1510 for( step = 0; (step += 0.005) <= 1.0; )
1512 VectorCopy( baseOrigin, trace.origin );
1513 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1514 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1515 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1517 /* ydnar: changed to find cluster num */
1518 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1519 if( trace.cluster >= 0 )
1523 /* can't find a valid point at all */
1529 trace.testOcclusion = !noTrace;
1530 trace.forceSunlight = qfalse;
1531 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1532 trace.numSurfaces = 0;
1533 trace.surfaces = NULL;
1534 trace.numLights = 0;
1535 trace.lights = NULL;
1539 VectorClear( cheapColor );
1541 /* trace to all the lights, find the major light direction, and divide the
1542 total light between that along the direction and the remaining in the ambient */
1543 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1549 if( !LightContributionToPoint( &trace ) )
1552 /* handle negative light */
1553 if( trace.light->flags & LIGHT_NEGATIVE )
1554 VectorScale( trace.color, -1.0f, trace.color );
1556 /* add a contribution */
1557 VectorCopy( trace.color, contributions[ numCon ].color );
1558 VectorCopy( trace.direction, contributions[ numCon ].dir );
1559 VectorClear( contributions[ numCon ].ambient );
1560 contributions[ numCon ].style = trace.light->style;
1563 /* push average direction around */
1564 addSize = VectorLength( trace.color );
1565 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1567 /* stop after a while */
1568 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1571 /* ydnar: cheap mode */
1572 VectorAdd( cheapColor, trace.color, cheapColor );
1573 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1577 /////// Floodlighting for point //////////////////
1578 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1583 vec3_t dir = { 0, 0, 1 };
1584 float ambientFrac = 0.25f;
1586 trace.testOcclusion = qtrue;
1587 trace.forceSunlight = qfalse;
1588 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1589 trace.testAll = qtrue;
1591 for( k = 0; k < 2; k++ )
1593 if( k == 0 ) // upper hemisphere
1595 trace.normal[0] = 0;
1596 trace.normal[1] = 0;
1597 trace.normal[2] = 1;
1599 else //lower hemisphere
1601 trace.normal[0] = 0;
1602 trace.normal[1] = 0;
1603 trace.normal[2] = -1;
1606 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1608 /* add a fraction as pure ambient, half as top-down direction */
1609 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1610 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1611 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1613 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1614 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1615 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1617 contributions[ numCon ].dir[0] = dir[0];
1618 contributions[ numCon ].dir[1] = dir[1];
1619 contributions[ numCon ].dir[2] = dir[2];
1621 contributions[ numCon ].style = 0;
1623 /* push average direction around */
1624 addSize = VectorLength( contributions[ numCon ].color );
1625 VectorMA( gp->dir, addSize, dir, gp->dir );
1630 /////////////////////
1632 /* normalize to get primary light direction */
1633 VectorNormalize( gp->dir, thisdir );
1635 /* now that we have identified the primary light direction,
1636 go back and separate all the light into directed and ambient */
1639 for( i = 0; i < numCon; i++ )
1641 /* get relative directed strength */
1642 d = DotProduct( contributions[ i ].dir, thisdir );
1643 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1644 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1648 /* find appropriate style */
1649 for( j = 0; j < numStyles; j++ )
1651 if( gp->styles[ j ] == contributions[ i ].style )
1655 /* style not found? */
1656 if( j >= numStyles )
1658 /* add a new style */
1659 if( numStyles < MAX_LIGHTMAPS )
1661 gp->styles[ numStyles ] = contributions[ i ].style;
1662 bgp->styles[ numStyles ] = contributions[ i ].style;
1664 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1672 /* add the directed color */
1673 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1675 /* ambient light will be at 1/4 the value of directed light */
1676 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1677 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1679 /* (Hobbes: always setting it to .25 is hardly any better) */
1680 d = 0.25f * (1.0f - d);
1681 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1683 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1687 * the total light average = ambient value + 0.25 * sum of all directional values
1688 * we can also get the total light average as 0.25 * the sum of all contributions
1690 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1693 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1695 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1700 /* store off sample */
1701 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1704 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1706 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1709 /* set minimum light and copy off to bytes */
1710 VectorCopy( gp->ambient[ i ], color );
1711 for( j = 0; j < 3; j++ )
1712 if( color[ j ] < minGridLight[ j ] )
1713 color[ j ] = minGridLight[ j ];
1715 /* vortex: apply gridscale and gridambientscale here */
1716 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1717 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1722 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1723 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1725 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1726 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1729 /* store direction */
1730 NormalToLatLong( thisdir, bgp->latLong );
1737 calculates the size of the lightgrid and allocates memory
1740 void SetupGrid( void )
1743 vec3_t maxs, oldGridSize;
1748 /* don't do this if not grid lighting */
1749 if( noGridLighting )
1752 /* ydnar: set grid size */
1753 value = ValueForKey( &entities[ 0 ], "gridsize" );
1754 if( value[ 0 ] != '\0' )
1755 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1758 VectorCopy( gridSize, oldGridSize );
1759 for( i = 0; i < 3; i++ )
1760 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1762 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1763 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1765 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1767 /* get world bounds */
1768 for( i = 0; i < 3; i++ )
1770 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1771 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1772 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1776 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1778 /* increase grid size a bit */
1779 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1780 gridSize[ j++ % 3 ] += 16.0f;
1784 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1787 if( !VectorCompare( gridSize, oldGridSize ) )
1789 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1790 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1791 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1794 /* 2nd variable. fixme: is this silly? */
1795 numBSPGridPoints = numRawGridPoints;
1797 /* allocate lightgrid */
1798 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1799 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1801 if( bspGridPoints != NULL )
1802 free( bspGridPoints );
1803 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1804 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1806 /* clear lightgrid */
1807 for( i = 0; i < numRawGridPoints; i++ )
1809 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1810 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1811 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1812 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1814 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1815 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1820 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1827 does what it says...
1830 void LightWorld( void )
1835 qboolean minVertex, minGrid;
1839 /* ydnar: smooth normals */
1842 Sys_Printf( "--- SmoothNormals ---\n" );
1846 /* determine the number of grid points */
1847 Sys_Printf( "--- SetupGrid ---\n" );
1850 /* find the optional minimum lighting values */
1851 GetVectorForKey( &entities[ 0 ], "_color", color );
1852 if( VectorLength( color ) == 0.0f )
1853 VectorSet( color, 1.0, 1.0, 1.0 );
1856 f = FloatForKey( &entities[ 0 ], "_ambient" );
1858 f = FloatForKey( &entities[ 0 ], "ambient" );
1859 VectorScale( color, f, ambientColor );
1861 /* minvertexlight */
1863 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1864 if( value[ 0 ] != '\0' )
1868 VectorScale( color, f, minVertexLight );
1873 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1874 if( value[ 0 ] != '\0' )
1878 VectorScale( color, f, minGridLight );
1882 value = ValueForKey( &entities[ 0 ], "_minlight" );
1883 if( value[ 0 ] != '\0' )
1886 VectorScale( color, f, minLight );
1887 if( minVertex == qfalse )
1888 VectorScale( color, f, minVertexLight );
1889 if( minGrid == qfalse )
1890 VectorScale( color, f, minGridLight );
1893 /* create world lights */
1894 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1895 CreateEntityLights();
1896 CreateSurfaceLights();
1897 Sys_Printf( "%9d point lights\n", numPointLights );
1898 Sys_Printf( "%9d spotlights\n", numSpotLights );
1899 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1900 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1902 /* calculate lightgrid */
1903 if( !noGridLighting )
1905 /* ydnar: set up light envelopes */
1906 SetupEnvelopes( qtrue, fastgrid );
1908 Sys_Printf( "--- TraceGrid ---\n" );
1910 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1912 Sys_Printf( "%d x %d x %d = %d grid\n",
1913 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1915 /* ydnar: emit statistics on light culling */
1916 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1917 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1920 /* slight optimization to remove a sqrt */
1921 subdivideThreshold *= subdivideThreshold;
1923 /* map the world luxels */
1924 Sys_Printf( "--- MapRawLightmap ---\n" );
1925 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1926 Sys_Printf( "%9d luxels\n", numLuxels );
1927 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1928 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1933 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1934 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1937 /* floodlight pass */
1938 FloodlightRawLightmaps();
1940 /* ydnar: set up light envelopes */
1941 SetupEnvelopes( qfalse, fast );
1943 /* light up my world */
1944 lightsPlaneCulled = 0;
1945 lightsEnvelopeCulled = 0;
1946 lightsBoundsCulled = 0;
1947 lightsClusterCulled = 0;
1949 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1950 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1951 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1953 StitchSurfaceLightmaps();
1955 Sys_Printf( "--- IlluminateVertexes ---\n" );
1956 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1957 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1959 /* ydnar: emit statistics on light culling */
1960 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1961 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1962 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1963 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1970 /* store off the bsp between bounces */
1971 StoreSurfaceLightmaps();
1973 Sys_Printf( "Writing %s\n", source );
1974 WriteBSPFile( source );
1977 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1981 VectorClear( ambientColor );
1982 floodlighty = qfalse;
1984 /* generate diffuse lights */
1986 RadCreateDiffuseLights();
1988 /* setup light envelopes */
1989 SetupEnvelopes( qfalse, fastbounce );
1990 if( numLights == 0 )
1992 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1996 /* add to lightgrid */
1999 gridEnvelopeCulled = 0;
2000 gridBoundsCulled = 0;
2002 Sys_Printf( "--- BounceGrid ---\n" );
2004 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2006 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2007 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2010 /* light up my world */
2011 lightsPlaneCulled = 0;
2012 lightsEnvelopeCulled = 0;
2013 lightsBoundsCulled = 0;
2014 lightsClusterCulled = 0;
2016 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2017 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2018 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2019 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2021 StitchSurfaceLightmaps();
2023 Sys_Printf( "--- IlluminateVertexes ---\n" );
2024 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2025 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2027 /* ydnar: emit statistics on light culling */
2028 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2029 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2030 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2031 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2043 main routine for light processing
2046 int LightMain( int argc, char **argv )
2050 char mapSource[ 1024 ];
2052 int lightmapMergeSize = 0;
2053 qboolean lightSamplesInsist = qfalse;
2057 Sys_Printf( "--- Light ---\n" );
2058 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2060 /* set standard game flags */
2061 wolfLight = game->wolfLight;
2062 if (wolfLight == qtrue)
2063 Sys_Printf( " lightning model: wolf\n" );
2065 Sys_Printf( " lightning model: quake3\n" );
2067 lmCustomSize = game->lightmapSize;
2068 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2070 lightmapGamma = game->lightmapGamma;
2071 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2073 lightmapCompensate = game->lightmapCompensate;
2074 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2076 lightmapExposure = game->lightmapExposure;
2077 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2079 gridScale = game->gridScale;
2080 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2082 gridAmbientScale = game->gridAmbientScale;
2083 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2085 lightAngleHL = game->lightAngleHL;
2087 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2089 noStyles = game->noStyles;
2090 if (noStyles == qtrue)
2091 Sys_Printf( " shader lightstyles hack: disabled\n" );
2093 Sys_Printf( " shader lightstyles hack: enabled\n" );
2095 keepLights = game->keepLights;
2096 if (keepLights == qtrue)
2097 Sys_Printf( " keep lights: enabled\n" );
2099 Sys_Printf( " keep lights: disabled\n" );
2101 patchShadows = game->patchShadows;
2102 if (patchShadows == qtrue)
2103 Sys_Printf( " patch shadows: enabled\n" );
2105 Sys_Printf( " patch shadows: disabled\n" );
2107 deluxemap = game->deluxeMap;
2108 deluxemode = game->deluxeMode;
2109 if (deluxemap == qtrue)
2112 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2114 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2117 Sys_Printf( " deluxemapping: disabled\n" );
2119 Sys_Printf( "--- ProcessCommandLine ---\n" );
2121 /* process commandline arguments */
2122 for( i = 1; i < (argc - 1); i++ )
2124 /* lightsource scaling */
2125 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2127 f = atof( argv[ i + 1 ] );
2129 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2133 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2135 f = atof( argv[ i + 1 ] );
2137 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2141 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2143 f = atof( argv[ i + 1 ] );
2145 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2149 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2151 f = atof( argv[ i + 1 ] );
2153 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2157 else if( !strcmp( argv[ i ], "-scale" ) )
2159 f = atof( argv[ i + 1 ] );
2164 Sys_Printf( "All light scaled by %f\n", f );
2168 else if( !strcmp( argv[ i ], "-gridscale" ) )
2170 f = atof( argv[ i + 1 ] );
2171 Sys_Printf( "Grid lightning scaled by %f\n", f );
2176 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2178 f = atof( argv[ i + 1 ] );
2179 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2180 gridAmbientScale *= f;
2184 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2186 f = atof( argv[ i + 1 ] );
2188 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2189 Sys_Printf( "Grid directionality is %f\n", f );
2190 gridDirectionality *= f;
2194 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2196 f = atof( argv[ i + 1 ] );
2197 if(f > gridDirectionality) f = gridDirectionality;
2199 Sys_Printf( "Grid ambient directionality is %f\n", f );
2200 gridAmbientDirectionality *= f;
2204 else if( !strcmp( argv[ i ], "-gamma" ) )
2206 f = atof( argv[ i + 1 ] );
2208 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2212 else if( !strcmp( argv[ i ], "-exposure" ) )
2214 f = atof( argv[ i + 1 ] );
2215 lightmapExposure = f;
2216 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2220 else if( !strcmp( argv[ i ], "-compensate" ) )
2222 f = atof( argv[ i + 1 ] );
2225 lightmapCompensate = f;
2226 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2230 /* ydnar switches */
2231 else if( !strcmp( argv[ i ], "-bounce" ) )
2233 bounce = atoi( argv[ i + 1 ] );
2236 else if( bounce > 0 )
2237 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2241 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2243 superSample = atoi( argv[ i + 1 ] );
2244 if( superSample < 1 )
2246 else if( superSample > 1 )
2247 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2251 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2253 lightRandomSamples = qtrue;
2254 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2257 else if( !strcmp( argv[ i ], "-samples" ) )
2259 if(*argv[i+1] == '+')
2260 lightSamplesInsist = qtrue;
2261 lightSamples = atoi( argv[ i + 1 ] );
2262 if( lightSamples < 1 )
2264 else if( lightSamples > 1 )
2265 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2269 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2271 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2272 if( lightSamplesSearchBoxSize <= 0 )
2273 lightSamplesSearchBoxSize = 1;
2274 if( lightSamplesSearchBoxSize > 4 )
2275 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2276 else if( lightSamplesSearchBoxSize != 1 )
2277 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2281 else if( !strcmp( argv[ i ], "-filter" ) )
2284 Sys_Printf( "Lightmap filtering enabled\n" );
2287 else if( !strcmp( argv[ i ], "-dark" ) )
2290 Sys_Printf( "Dark lightmap seams enabled\n" );
2293 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2295 shadeAngleDegrees = atof( argv[ i + 1 ] );
2296 if( shadeAngleDegrees < 0.0f )
2297 shadeAngleDegrees = 0.0f;
2298 else if( shadeAngleDegrees > 0.0f )
2301 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2306 else if( !strcmp( argv[ i ], "-thresh" ) )
2308 subdivideThreshold = atof( argv[ i + 1 ] );
2309 if( subdivideThreshold < 0 )
2310 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2312 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2316 else if( !strcmp( argv[ i ], "-approx" ) )
2318 approximateTolerance = atoi( argv[ i + 1 ] );
2319 if( approximateTolerance < 0 )
2320 approximateTolerance = 0;
2321 else if( approximateTolerance > 0 )
2322 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2325 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2328 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2330 else if( !strcmp( argv[ i ], "-deluxemode" ))
2332 deluxemode = atoi( argv[ i + 1 ] );
2333 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2335 Sys_Printf( "Generating modelspace deluxemaps\n" );
2339 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2342 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2345 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2347 else if( !strcmp( argv[ i ], "-external" ) )
2349 externalLightmaps = qtrue;
2350 Sys_Printf( "Storing all lightmaps externally\n" );
2353 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2355 lmCustomSize = atoi( argv[ i + 1 ] );
2357 /* must be a power of 2 and greater than 2 */
2358 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2360 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2361 lmCustomSize = game->lightmapSize;
2364 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2366 /* enable external lightmaps */
2367 if( lmCustomSize != game->lightmapSize )
2369 externalLightmaps = qtrue;
2370 Sys_Printf( "Storing all lightmaps externally\n" );
2374 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2376 lmLimitSize = atoi( argv[ i + 1 ] );
2379 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2382 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2384 lmCustomDir = argv[i + 1];
2386 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2387 externalLightmaps = qtrue;
2388 Sys_Printf( "Storing all lightmaps externally\n" );
2391 /* ydnar: add this to suppress warnings */
2392 else if( !strcmp( argv[ i ], "-custinfoparms") )
2394 Sys_Printf( "Custom info parms enabled\n" );
2395 useCustomInfoParms = qtrue;
2398 else if( !strcmp( argv[ i ], "-wolf" ) )
2400 /* -game should already be set */
2402 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2405 else if( !strcmp( argv[ i ], "-q3" ) )
2407 /* -game should already be set */
2409 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2412 else if( !strcmp( argv[ i ], "-extradist" ) )
2414 extraDist = atof( argv[ i + 1 ] );
2418 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2421 else if( !strcmp( argv[ i ], "-sunonly" ) )
2424 Sys_Printf( "Only computing sunlight\n" );
2427 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2430 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2433 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2436 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2439 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2441 lightmapSearchBlockSize = 1;
2442 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2445 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2447 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2449 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2452 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2454 lightmapSearchBlockSize = atoi(argv[i+1]);
2456 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2459 else if( !strcmp( argv[ i ], "-shade" ) )
2462 Sys_Printf( "Phong shading enabled\n" );
2465 else if( !strcmp( argv[ i ], "-bouncegrid") )
2469 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2472 else if( !strcmp( argv[ i ], "-smooth" ) )
2474 lightSamples = EXTRA_SCALE;
2475 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2478 else if( !strcmp( argv[ i ], "-fast" ) )
2483 Sys_Printf( "Fast mode enabled\n" );
2486 else if( !strcmp( argv[ i ], "-faster" ) )
2492 Sys_Printf( "Faster mode enabled\n" );
2495 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2498 Sys_Printf( "Fast grid lighting enabled\n" );
2501 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2504 Sys_Printf( "Fast bounce mode enabled\n" );
2507 else if( !strcmp( argv[ i ], "-cheap" ) )
2511 Sys_Printf( "Cheap mode enabled\n" );
2514 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2517 Sys_Printf( "Cheap grid mode enabled\n" );
2520 else if( !strcmp( argv[ i ], "-normalmap" ) )
2523 Sys_Printf( "Storing normal map instead of lightmap\n" );
2526 else if( !strcmp( argv[ i ], "-trisoup" ) )
2529 Sys_Printf( "Converting brush faces to triangle soup\n" );
2532 else if( !strcmp( argv[ i ], "-debug" ) )
2535 Sys_Printf( "Lightmap debugging enabled\n" );
2538 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2540 debugSurfaces = qtrue;
2541 Sys_Printf( "Lightmap surface debugging enabled\n" );
2544 else if( !strcmp( argv[ i ], "-debugunused" ) )
2546 debugUnused = qtrue;
2547 Sys_Printf( "Unused luxel debugging enabled\n" );
2550 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2553 Sys_Printf( "Lightmap axis debugging enabled\n" );
2556 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2558 debugCluster = qtrue;
2559 Sys_Printf( "Luxel cluster debugging enabled\n" );
2562 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2564 debugOrigin = qtrue;
2565 Sys_Printf( "Luxel origin debugging enabled\n" );
2568 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2571 debugDeluxemap = qtrue;
2572 Sys_Printf( "Deluxemap debugging enabled\n" );
2575 else if( !strcmp( argv[ i ], "-export" ) )
2577 exportLightmaps = qtrue;
2578 Sys_Printf( "Exporting lightmaps\n" );
2581 else if( !strcmp(argv[ i ], "-notrace" ))
2584 Sys_Printf( "Shadow occlusion disabled\n" );
2586 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2588 patchShadows = qtrue;
2589 Sys_Printf( "Patch shadow casting enabled\n" );
2591 else if( !strcmp( argv[ i ], "-extra" ) )
2593 superSample = EXTRA_SCALE; /* ydnar */
2594 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2596 else if( !strcmp( argv[ i ], "-extrawide" ) )
2598 superSample = EXTRAWIDE_SCALE; /* ydnar */
2599 filter = qtrue; /* ydnar */
2600 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2602 else if( !strcmp( argv[ i ], "-samplesize" ) )
2604 sampleSize = atoi( argv[ i + 1 ] );
2605 if( sampleSize < 1 )
2608 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2610 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2612 minSampleSize = atoi( argv[ i + 1 ] );
2613 if( minSampleSize < 1 )
2616 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2618 else if( !strcmp( argv[ i ], "-samplescale" ) )
2620 sampleScale = atoi( argv[ i + 1 ] );
2622 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2624 else if( !strcmp( argv[ i ], "-novertex" ) )
2626 noVertexLighting = qtrue;
2627 Sys_Printf( "Disabling vertex lighting\n" );
2629 else if( !strcmp( argv[ i ], "-nogrid" ) )
2631 noGridLighting = qtrue;
2632 Sys_Printf( "Disabling grid lighting\n" );
2634 else if( !strcmp( argv[ i ], "-border" ) )
2636 lightmapBorder = qtrue;
2637 Sys_Printf( "Adding debug border to lightmaps\n" );
2639 else if( !strcmp( argv[ i ], "-nosurf" ) )
2642 Sys_Printf( "Not tracing against surfaces\n" );
2644 else if( !strcmp( argv[ i ], "-dump" ) )
2647 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2649 else if( !strcmp( argv[ i ], "-lomem" ) )
2652 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2654 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2656 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2658 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2660 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2662 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2665 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2668 Sys_Printf( "Disabling lightstyles\n" );
2670 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2673 Sys_Printf( "Enabling lightstyles\n" );
2675 else if( !strcmp( argv[ i ], "-keeplights" ))
2678 Sys_Printf( "Leaving light entities on map after compile\n" );
2680 else if( !strcmp( argv[ i ], "-cpma" ) )
2683 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2685 else if( !strcmp( argv[ i ], "-floodlight" ) )
2687 floodlighty = qtrue;
2688 Sys_Printf( "FloodLighting enabled\n" );
2690 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2692 debugnormals = qtrue;
2693 Sys_Printf( "DebugNormals enabled\n" );
2695 else if( !strcmp( argv[ i ], "-lowquality" ) )
2697 floodlight_lowquality = qtrue;
2698 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2701 /* r7: dirtmapping */
2702 else if( !strcmp( argv[ i ], "-dirty" ) )
2705 Sys_Printf( "Dirtmapping enabled\n" );
2707 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2710 Sys_Printf( "Dirtmap debugging enabled\n" );
2712 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2714 dirtMode = atoi( argv[ i + 1 ] );
2715 if( dirtMode != 0 && dirtMode != 1 )
2718 Sys_Printf( "Enabling randomized dirtmapping\n" );
2720 Sys_Printf( "Enabling ordered dir mapping\n" );
2723 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2725 dirtDepth = atof( argv[ i + 1 ] );
2726 if( dirtDepth <= 0.0f )
2728 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2731 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2733 dirtScale = atof( argv[ i + 1 ] );
2734 if( dirtScale <= 0.0f )
2736 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2739 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2741 dirtGain = atof( argv[ i + 1 ] );
2742 if( dirtGain <= 0.0f )
2744 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2747 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2749 lightmapTriangleCheck = qtrue;
2751 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2753 lightmapExtraVisClusterNudge = qtrue;
2755 /* unhandled args */
2758 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2763 /* fix up samples count */
2764 if(lightRandomSamples)
2766 if(!lightSamplesInsist)
2768 /* approximately match -samples in quality */
2769 switch(lightSamples)
2773 case 2: lightSamples = 16; break;
2776 case 3: lightSamples = 64; break;
2779 case 4: lightSamples = 256; break;
2786 /* fix up lightmap search power */
2787 if(lightmapMergeSize)
2789 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2790 if(lightmapSearchBlockSize < 1)
2791 lightmapSearchBlockSize = 1;
2793 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2796 /* clean up map name */
2797 strcpy( source, ExpandArg( argv[ i ] ) );
2798 StripExtension( source );
2799 DefaultExtension( source, ".bsp" );
2800 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2801 StripExtension( mapSource );
2802 DefaultExtension( mapSource, ".map" );
2804 /* ydnar: set default sample size */
2805 SetDefaultSampleSize( sampleSize );
2807 /* ydnar: handle shaders */
2808 BeginMapShaderFile( source );
2812 Sys_Printf( "Loading %s\n", source );
2814 /* ydnar: load surface file */
2815 LoadSurfaceExtraFile( source );
2818 LoadBSPFile( source );
2820 /* parse bsp entities */
2823 /* inject command line parameters */
2824 InjectCommandLine(argv, 0, argc - 1);
2827 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2828 if( value[ 0 ] != '1' )
2829 LoadMapFile( mapSource, qtrue, qfalse );
2831 /* set the entity/model origins and init yDrawVerts */
2834 /* ydnar: set up optimization */
2838 SetupSurfaceLightmaps();
2840 /* initialize the surface facet tracing */
2843 /* light the world */
2846 /* ydnar: store off lightmaps */
2847 StoreSurfaceLightmaps();
2849 /* write out the bsp */
2851 Sys_Printf( "Writing %s\n", source );
2852 WriteBSPFile( source );
2854 /* ydnar: export lightmaps */
2855 if( exportLightmaps && !externalLightmaps )
2858 /* return to sender */