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;
2056 Sys_Printf( "--- Light ---\n" );
2057 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2059 /* set standard game flags */
2060 wolfLight = game->wolfLight;
2061 if (wolfLight == qtrue)
2062 Sys_Printf( " lightning model: wolf\n" );
2064 Sys_Printf( " lightning model: quake3\n" );
2066 lmCustomSize = game->lightmapSize;
2067 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2069 lightmapGamma = game->lightmapGamma;
2070 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2072 lightmapCompensate = game->lightmapCompensate;
2073 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2075 lightmapExposure = game->lightmapExposure;
2076 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2078 gridScale = game->gridScale;
2079 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2081 gridAmbientScale = game->gridAmbientScale;
2082 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2084 lightAngleHL = game->lightAngleHL;
2086 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2088 noStyles = game->noStyles;
2089 if (noStyles == qtrue)
2090 Sys_Printf( " shader lightstyles hack: disabled\n" );
2092 Sys_Printf( " shader lightstyles hack: enabled\n" );
2094 keepLights = game->keepLights;
2095 if (keepLights == qtrue)
2096 Sys_Printf( " keep lights: enabled\n" );
2098 Sys_Printf( " keep lights: disabled\n" );
2100 patchShadows = game->patchShadows;
2101 if (patchShadows == qtrue)
2102 Sys_Printf( " patch shadows: enabled\n" );
2104 Sys_Printf( " patch shadows: disabled\n" );
2106 deluxemap = game->deluxeMap;
2107 deluxemode = game->deluxeMode;
2108 if (deluxemap == qtrue)
2111 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2113 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2116 Sys_Printf( " deluxemapping: disabled\n" );
2118 Sys_Printf( "--- ProcessCommandLine ---\n" );
2120 /* process commandline arguments */
2121 for( i = 1; i < (argc - 1); i++ )
2123 /* lightsource scaling */
2124 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2126 f = atof( argv[ i + 1 ] );
2128 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2132 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2134 f = atof( argv[ i + 1 ] );
2136 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2140 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2142 f = atof( argv[ i + 1 ] );
2144 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2148 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2150 f = atof( argv[ i + 1 ] );
2152 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2156 else if( !strcmp( argv[ i ], "-scale" ) )
2158 f = atof( argv[ i + 1 ] );
2163 Sys_Printf( "All light scaled by %f\n", f );
2167 else if( !strcmp( argv[ i ], "-gridscale" ) )
2169 f = atof( argv[ i + 1 ] );
2170 Sys_Printf( "Grid lightning scaled by %f\n", f );
2175 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2177 f = atof( argv[ i + 1 ] );
2178 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2179 gridAmbientScale *= f;
2183 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2185 f = atof( argv[ i + 1 ] );
2187 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2188 Sys_Printf( "Grid directionality is %f\n", f );
2189 gridDirectionality *= f;
2193 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2195 f = atof( argv[ i + 1 ] );
2196 if(f > gridDirectionality) f = gridDirectionality;
2198 Sys_Printf( "Grid ambient directionality is %f\n", f );
2199 gridAmbientDirectionality *= f;
2203 else if( !strcmp( argv[ i ], "-gamma" ) )
2205 f = atof( argv[ i + 1 ] );
2207 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2211 else if( !strcmp( argv[ i ], "-exposure" ) )
2213 f = atof( argv[ i + 1 ] );
2214 lightmapExposure = f;
2215 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2219 else if( !strcmp( argv[ i ], "-compensate" ) )
2221 f = atof( argv[ i + 1 ] );
2224 lightmapCompensate = f;
2225 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2229 /* ydnar switches */
2230 else if( !strcmp( argv[ i ], "-bounce" ) )
2232 bounce = atoi( argv[ i + 1 ] );
2235 else if( bounce > 0 )
2236 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2240 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2242 superSample = atoi( argv[ i + 1 ] );
2243 if( superSample < 1 )
2245 else if( superSample > 1 )
2246 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2250 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2252 lightRandomSamples = qtrue;
2253 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2256 else if( !strcmp( argv[ i ], "-samples" ) )
2258 lightSamples = atoi( argv[ i + 1 ] );
2259 if( lightSamples < 1 )
2261 else if( lightSamples > 1 )
2262 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2266 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2268 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2269 if( lightSamplesSearchBoxSize <= 0 )
2270 lightSamplesSearchBoxSize = 1;
2271 if( lightSamplesSearchBoxSize > 4 )
2272 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2273 else if( lightSamplesSearchBoxSize != 1 )
2274 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2278 else if( !strcmp( argv[ i ], "-filter" ) )
2281 Sys_Printf( "Lightmap filtering enabled\n" );
2284 else if( !strcmp( argv[ i ], "-dark" ) )
2287 Sys_Printf( "Dark lightmap seams enabled\n" );
2290 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2292 shadeAngleDegrees = atof( argv[ i + 1 ] );
2293 if( shadeAngleDegrees < 0.0f )
2294 shadeAngleDegrees = 0.0f;
2295 else if( shadeAngleDegrees > 0.0f )
2298 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2303 else if( !strcmp( argv[ i ], "-thresh" ) )
2305 subdivideThreshold = atof( argv[ i + 1 ] );
2306 if( subdivideThreshold < 0 )
2307 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2309 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2313 else if( !strcmp( argv[ i ], "-approx" ) )
2315 approximateTolerance = atoi( argv[ i + 1 ] );
2316 if( approximateTolerance < 0 )
2317 approximateTolerance = 0;
2318 else if( approximateTolerance > 0 )
2319 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2322 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2325 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2327 else if( !strcmp( argv[ i ], "-deluxemode" ))
2329 deluxemode = atoi( argv[ i + 1 ] );
2330 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2332 Sys_Printf( "Generating modelspace deluxemaps\n" );
2336 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2339 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2342 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2344 else if( !strcmp( argv[ i ], "-external" ) )
2346 externalLightmaps = qtrue;
2347 Sys_Printf( "Storing all lightmaps externally\n" );
2350 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2352 lmCustomSize = atoi( argv[ i + 1 ] );
2354 /* must be a power of 2 and greater than 2 */
2355 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2357 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2358 lmCustomSize = game->lightmapSize;
2361 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2363 /* enable external lightmaps */
2364 if( lmCustomSize != game->lightmapSize )
2366 externalLightmaps = qtrue;
2367 Sys_Printf( "Storing all lightmaps externally\n" );
2371 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2373 lmLimitSize = atoi( argv[ i + 1 ] );
2376 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2379 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2381 lmCustomDir = argv[i + 1];
2383 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2384 externalLightmaps = qtrue;
2385 Sys_Printf( "Storing all lightmaps externally\n" );
2388 /* ydnar: add this to suppress warnings */
2389 else if( !strcmp( argv[ i ], "-custinfoparms") )
2391 Sys_Printf( "Custom info parms enabled\n" );
2392 useCustomInfoParms = qtrue;
2395 else if( !strcmp( argv[ i ], "-wolf" ) )
2397 /* -game should already be set */
2399 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2402 else if( !strcmp( argv[ i ], "-q3" ) )
2404 /* -game should already be set */
2406 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2409 else if( !strcmp( argv[ i ], "-extradist" ) )
2411 extraDist = atof( argv[ i + 1 ] );
2415 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2418 else if( !strcmp( argv[ i ], "-sunonly" ) )
2421 Sys_Printf( "Only computing sunlight\n" );
2424 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2427 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2430 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2433 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2436 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2438 lightmapSearchBlockSize = 1;
2439 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2442 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2444 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2446 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2449 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2451 lightmapSearchBlockSize = atoi(argv[i+1]);
2453 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2456 else if( !strcmp( argv[ i ], "-shade" ) )
2459 Sys_Printf( "Phong shading enabled\n" );
2462 else if( !strcmp( argv[ i ], "-bouncegrid") )
2466 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2469 else if( !strcmp( argv[ i ], "-smooth" ) )
2471 lightSamples = EXTRA_SCALE;
2472 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2475 else if( !strcmp( argv[ i ], "-fast" ) )
2480 Sys_Printf( "Fast mode enabled\n" );
2483 else if( !strcmp( argv[ i ], "-faster" ) )
2489 Sys_Printf( "Faster mode enabled\n" );
2492 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2495 Sys_Printf( "Fast grid lighting enabled\n" );
2498 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2501 Sys_Printf( "Fast bounce mode enabled\n" );
2504 else if( !strcmp( argv[ i ], "-cheap" ) )
2508 Sys_Printf( "Cheap mode enabled\n" );
2511 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2514 Sys_Printf( "Cheap grid mode enabled\n" );
2517 else if( !strcmp( argv[ i ], "-normalmap" ) )
2520 Sys_Printf( "Storing normal map instead of lightmap\n" );
2523 else if( !strcmp( argv[ i ], "-trisoup" ) )
2526 Sys_Printf( "Converting brush faces to triangle soup\n" );
2529 else if( !strcmp( argv[ i ], "-debug" ) )
2532 Sys_Printf( "Lightmap debugging enabled\n" );
2535 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2537 debugSurfaces = qtrue;
2538 Sys_Printf( "Lightmap surface debugging enabled\n" );
2541 else if( !strcmp( argv[ i ], "-debugunused" ) )
2543 debugUnused = qtrue;
2544 Sys_Printf( "Unused luxel debugging enabled\n" );
2547 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2550 Sys_Printf( "Lightmap axis debugging enabled\n" );
2553 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2555 debugCluster = qtrue;
2556 Sys_Printf( "Luxel cluster debugging enabled\n" );
2559 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2561 debugOrigin = qtrue;
2562 Sys_Printf( "Luxel origin debugging enabled\n" );
2565 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2568 debugDeluxemap = qtrue;
2569 Sys_Printf( "Deluxemap debugging enabled\n" );
2572 else if( !strcmp( argv[ i ], "-export" ) )
2574 exportLightmaps = qtrue;
2575 Sys_Printf( "Exporting lightmaps\n" );
2578 else if( !strcmp(argv[ i ], "-notrace" ))
2581 Sys_Printf( "Shadow occlusion disabled\n" );
2583 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2585 patchShadows = qtrue;
2586 Sys_Printf( "Patch shadow casting enabled\n" );
2588 else if( !strcmp( argv[ i ], "-extra" ) )
2590 superSample = EXTRA_SCALE; /* ydnar */
2591 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2593 else if( !strcmp( argv[ i ], "-extrawide" ) )
2595 superSample = EXTRAWIDE_SCALE; /* ydnar */
2596 filter = qtrue; /* ydnar */
2597 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2599 else if( !strcmp( argv[ i ], "-samplesize" ) )
2601 sampleSize = atoi( argv[ i + 1 ] );
2602 if( sampleSize < 1 )
2605 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2607 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2609 minSampleSize = atoi( argv[ i + 1 ] );
2610 if( minSampleSize < 1 )
2613 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2615 else if( !strcmp( argv[ i ], "-samplescale" ) )
2617 sampleScale = atoi( argv[ i + 1 ] );
2619 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2621 else if( !strcmp( argv[ i ], "-novertex" ) )
2623 noVertexLighting = qtrue;
2624 Sys_Printf( "Disabling vertex lighting\n" );
2626 else if( !strcmp( argv[ i ], "-nogrid" ) )
2628 noGridLighting = qtrue;
2629 Sys_Printf( "Disabling grid lighting\n" );
2631 else if( !strcmp( argv[ i ], "-border" ) )
2633 lightmapBorder = qtrue;
2634 Sys_Printf( "Adding debug border to lightmaps\n" );
2636 else if( !strcmp( argv[ i ], "-nosurf" ) )
2639 Sys_Printf( "Not tracing against surfaces\n" );
2641 else if( !strcmp( argv[ i ], "-dump" ) )
2644 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2646 else if( !strcmp( argv[ i ], "-lomem" ) )
2649 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2651 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2653 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2655 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2657 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2659 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2662 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2665 Sys_Printf( "Disabling lightstyles\n" );
2667 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2670 Sys_Printf( "Enabling lightstyles\n" );
2672 else if( !strcmp( argv[ i ], "-keeplights" ))
2675 Sys_Printf( "Leaving light entities on map after compile\n" );
2677 else if( !strcmp( argv[ i ], "-cpma" ) )
2680 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2682 else if( !strcmp( argv[ i ], "-floodlight" ) )
2684 floodlighty = qtrue;
2685 Sys_Printf( "FloodLighting enabled\n" );
2687 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2689 debugnormals = qtrue;
2690 Sys_Printf( "DebugNormals enabled\n" );
2692 else if( !strcmp( argv[ i ], "-lowquality" ) )
2694 floodlight_lowquality = qtrue;
2695 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2698 /* r7: dirtmapping */
2699 else if( !strcmp( argv[ i ], "-dirty" ) )
2702 Sys_Printf( "Dirtmapping enabled\n" );
2704 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2707 Sys_Printf( "Dirtmap debugging enabled\n" );
2709 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2711 dirtMode = atoi( argv[ i + 1 ] );
2712 if( dirtMode != 0 && dirtMode != 1 )
2715 Sys_Printf( "Enabling randomized dirtmapping\n" );
2717 Sys_Printf( "Enabling ordered dir mapping\n" );
2720 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2722 dirtDepth = atof( argv[ i + 1 ] );
2723 if( dirtDepth <= 0.0f )
2725 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2728 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2730 dirtScale = atof( argv[ i + 1 ] );
2731 if( dirtScale <= 0.0f )
2733 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2736 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2738 dirtGain = atof( argv[ i + 1 ] );
2739 if( dirtGain <= 0.0f )
2741 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2744 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2746 lightmapTriangleCheck = qtrue;
2748 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2750 lightmapExtraVisClusterNudge = qtrue;
2752 /* unhandled args */
2755 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2760 /* fix up lightmap search power */
2761 if(lightmapMergeSize)
2763 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2764 if(lightmapSearchBlockSize < 1)
2765 lightmapSearchBlockSize = 1;
2767 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2770 /* clean up map name */
2771 strcpy( source, ExpandArg( argv[ i ] ) );
2772 StripExtension( source );
2773 DefaultExtension( source, ".bsp" );
2774 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2775 StripExtension( mapSource );
2776 DefaultExtension( mapSource, ".map" );
2778 /* ydnar: set default sample size */
2779 SetDefaultSampleSize( sampleSize );
2781 /* ydnar: handle shaders */
2782 BeginMapShaderFile( source );
2786 Sys_Printf( "Loading %s\n", source );
2788 /* ydnar: load surface file */
2789 LoadSurfaceExtraFile( source );
2792 LoadBSPFile( source );
2794 /* parse bsp entities */
2797 /* inject command line parameters */
2798 InjectCommandLine(argv, 0, argc - 1);
2801 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2802 if( value[ 0 ] != '1' )
2803 LoadMapFile( mapSource, qtrue );
2805 /* set the entity/model origins and init yDrawVerts */
2808 /* ydnar: set up optimization */
2812 SetupSurfaceLightmaps();
2814 /* initialize the surface facet tracing */
2817 /* light the world */
2820 /* ydnar: store off lightmaps */
2821 StoreSurfaceLightmaps();
2823 /* write out the bsp */
2825 Sys_Printf( "Writing %s\n", source );
2826 WriteBSPFile( source );
2828 /* ydnar: export lightmaps */
2829 if( exportLightmaps && !externalLightmaps )
2832 /* return to sender */