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 /* VorteX: set noShadow color */
1121 VectorScale(light->color, add, trace->colorNoShadow);
1123 /* ydnar: changed to a variable number */
1124 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1127 addDeluxe *= colorBrightness;
1129 /* hack land: scale down the radiosity contribution to light directionality.
1130 Deluxemaps fusion many light directions into one. In a rtl process all lights
1131 would contribute individually to the bump map, so several light sources together
1132 would make it more directional (example: a yellow and red lights received from
1133 opposing sides would light one side in red and the other in blue, adding
1134 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1135 neutralize each other making it look like having no direction.
1136 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1137 is modifying the direction applied from directional lights, making it go closer and closer
1138 to the surface normal the bigger is the amount of radiosity received.
1139 So, for preserving the directional lights contributions, we scale down the radiosity
1140 contribution. It's a hack, but there's a reason behind it */
1143 addDeluxe *= addDeluxeBounceScale;
1144 /* better NOT increase it beyond the original value
1145 if( addDeluxe < 0.00390625f )
1146 addDeluxe = 0.00390625f;
1152 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1156 trace->testAll = qfalse;
1157 VectorScale( light->color, add, trace->color );
1161 trace->forceSubsampling *= add;
1162 if( trace->passSolid || trace->opaque )
1164 VectorClear( trace->color );
1165 VectorClear( trace->directionContribution );
1170 /* return to sender */
1178 determines the amount of light reaching a sample (luxel or vertex)
1181 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1187 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1188 VectorClear( colors[ lightmapNum ] );
1190 /* ydnar: normalmap */
1193 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1194 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1195 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1199 /* ydnar: don't bounce ambient all the time */
1201 VectorCopy( ambientColor, colors[ 0 ] );
1203 /* ydnar: trace to all the list of lights pre-stored in tw */
1204 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1207 trace->light = trace->lights[ i ];
1210 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1212 if( styles[ lightmapNum ] == trace->light->style ||
1213 styles[ lightmapNum ] == LS_NONE )
1217 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1218 if( lightmapNum >= MAX_LIGHTMAPS )
1222 LightContributionToSample( trace );
1223 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1226 /* handle negative light */
1227 if( trace->light->flags & LIGHT_NEGATIVE )
1228 VectorScale( trace->color, -1.0f, trace->color );
1231 styles[ lightmapNum ] = trace->light->style;
1234 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1238 colors[ 0 ][ 0 ] >= 255.0f &&
1239 colors[ 0 ][ 1 ] >= 255.0f &&
1240 colors[ 0 ][ 2 ] >= 255.0f )
1248 LightContributionToPoint()
1249 for a given light, how much light/color reaches a given point in space (with no facing)
1250 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1253 int LightContributionToPoint( trace_t *trace )
1260 light = trace->light;
1263 VectorClear( trace->color );
1265 /* ydnar: early out */
1266 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1269 /* is this a sun? */
1270 if( light->type != EMIT_SUN )
1277 if( !ClusterVisible( trace->cluster, light->cluster ) )
1281 /* ydnar: check origin against light's pvs envelope */
1282 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1283 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1284 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1290 /* set light origin */
1291 if( light->type == EMIT_SUN )
1292 VectorAdd( trace->origin, light->origin, trace->end );
1294 VectorCopy( light->origin, trace->end );
1297 dist = SetupTrace( trace );
1300 if( dist > light->envelope )
1302 gridEnvelopeCulled++;
1306 /* ptpff approximation */
1307 if( light->type == EMIT_AREA && faster )
1309 /* clamp the distance to prevent super hot spots */
1310 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1315 add = light->photons / (dist * dist);
1318 /* exact point to polygon form factor */
1319 else if( light->type == EMIT_AREA )
1322 vec3_t pushedOrigin;
1325 /* see if the point is behind the light */
1326 d = DotProduct( trace->origin, light->normal ) - light->dist;
1327 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1330 /* nudge the point so that it is clearly forward of the light */
1331 /* so that surfaces meeting a light emiter don't get black edges */
1332 if( d > -8.0f && d < 8.0f )
1333 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1335 VectorCopy( trace->origin, pushedOrigin );
1337 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1338 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1339 if( factor == 0.0f )
1341 else if( factor < 0.0f )
1343 if( light->flags & LIGHT_TWOSIDED )
1349 /* ydnar: moved to here */
1350 add = factor * light->add;
1353 /* point/spot lights */
1354 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1356 /* clamp the distance to prevent super hot spots */
1357 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1362 if( light->flags & LIGHT_ATTEN_LINEAR )
1364 add = light->photons * linearScale - (dist * light->fade);
1369 add = light->photons / (dist * dist);
1371 /* handle spotlights */
1372 if( light->type == EMIT_SPOT )
1374 float distByNormal, radiusAtDist, sampleRadius;
1375 vec3_t pointAtDist, distToSample;
1378 /* do cone calculation */
1379 distByNormal = -DotProduct( trace->displacement, light->normal );
1380 if( distByNormal < 0.0f )
1382 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1383 radiusAtDist = light->radiusByDist * distByNormal;
1384 VectorSubtract( trace->origin, pointAtDist, distToSample );
1385 sampleRadius = VectorLength( distToSample );
1387 /* outside the cone */
1388 if( sampleRadius >= radiusAtDist )
1392 if( sampleRadius > (radiusAtDist - 32.0f) )
1393 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1397 /* ydnar: sunlight */
1398 else if( light->type == EMIT_SUN )
1401 add = light->photons;
1406 trace->testAll = qtrue;
1407 VectorScale( light->color, add, trace->color );
1409 /* trace to point */
1410 if( trace->testOcclusion && !trace->forceSunlight )
1414 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1416 VectorClear( trace->color );
1421 /* return to sender */
1425 /* unknown light type */
1429 /* ydnar: changed to a variable number */
1430 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1434 trace->testAll = qfalse;
1435 VectorScale( light->color, add, trace->color );
1439 if( trace->passSolid )
1441 VectorClear( trace->color );
1445 /* we have a valid sample */
1453 grid samples are for quickly determining the lighting
1454 of dynamically placed entities in the world
1457 #define MAX_CONTRIBUTIONS 32768
1468 void TraceGrid( int num )
1470 int i, j, x, y, z, mod, numCon, numStyles;
1472 vec3_t baseOrigin, cheapColor, color, thisdir;
1474 bspGridPoint_t *bgp;
1475 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1478 /* get grid points */
1479 gp = &rawGridPoints[ num ];
1480 bgp = &bspGridPoints[ num ];
1482 /* get grid origin */
1484 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1485 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1486 y = mod / gridBounds[ 0 ];
1487 mod -= y * gridBounds[ 0 ];
1490 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1491 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1492 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1494 /* set inhibit sphere */
1495 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1496 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1497 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1498 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1500 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1502 /* find point cluster */
1503 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1504 if( trace.cluster < 0 )
1506 /* try to nudge the origin around to find a valid point */
1507 VectorCopy( trace.origin, baseOrigin );
1508 for( step = 0; (step += 0.005) <= 1.0; )
1510 VectorCopy( baseOrigin, trace.origin );
1511 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1512 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1513 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1515 /* ydnar: changed to find cluster num */
1516 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1517 if( trace.cluster >= 0 )
1521 /* can't find a valid point at all */
1527 trace.testOcclusion = !noTrace;
1528 trace.forceSunlight = qfalse;
1529 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1530 trace.numSurfaces = 0;
1531 trace.surfaces = NULL;
1532 trace.numLights = 0;
1533 trace.lights = NULL;
1537 VectorClear( cheapColor );
1539 /* trace to all the lights, find the major light direction, and divide the
1540 total light between that along the direction and the remaining in the ambient */
1541 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1547 if( !LightContributionToPoint( &trace ) )
1550 /* handle negative light */
1551 if( trace.light->flags & LIGHT_NEGATIVE )
1552 VectorScale( trace.color, -1.0f, trace.color );
1554 /* add a contribution */
1555 VectorCopy( trace.color, contributions[ numCon ].color );
1556 VectorCopy( trace.direction, contributions[ numCon ].dir );
1557 VectorClear( contributions[ numCon ].ambient );
1558 contributions[ numCon ].style = trace.light->style;
1561 /* push average direction around */
1562 addSize = VectorLength( trace.color );
1563 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1565 /* stop after a while */
1566 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1569 /* ydnar: cheap mode */
1570 VectorAdd( cheapColor, trace.color, cheapColor );
1571 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1575 /////// Floodlighting for point //////////////////
1576 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1581 vec3_t dir = { 0, 0, 1 };
1582 float ambientFrac = 0.25f;
1584 trace.testOcclusion = qtrue;
1585 trace.forceSunlight = qfalse;
1586 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1587 trace.testAll = qtrue;
1589 for( k = 0; k < 2; k++ )
1591 if( k == 0 ) // upper hemisphere
1593 trace.normal[0] = 0;
1594 trace.normal[1] = 0;
1595 trace.normal[2] = 1;
1597 else //lower hemisphere
1599 trace.normal[0] = 0;
1600 trace.normal[1] = 0;
1601 trace.normal[2] = -1;
1604 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1606 /* add a fraction as pure ambient, half as top-down direction */
1607 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1608 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1609 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1611 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1612 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1613 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1615 contributions[ numCon ].dir[0] = dir[0];
1616 contributions[ numCon ].dir[1] = dir[1];
1617 contributions[ numCon ].dir[2] = dir[2];
1619 contributions[ numCon ].style = 0;
1621 /* push average direction around */
1622 addSize = VectorLength( contributions[ numCon ].color );
1623 VectorMA( gp->dir, addSize, dir, gp->dir );
1628 /////////////////////
1630 /* normalize to get primary light direction */
1631 VectorNormalize( gp->dir, thisdir );
1633 /* now that we have identified the primary light direction,
1634 go back and separate all the light into directed and ambient */
1637 for( i = 0; i < numCon; i++ )
1639 /* get relative directed strength */
1640 d = DotProduct( contributions[ i ].dir, thisdir );
1641 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1642 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1646 /* find appropriate style */
1647 for( j = 0; j < numStyles; j++ )
1649 if( gp->styles[ j ] == contributions[ i ].style )
1653 /* style not found? */
1654 if( j >= numStyles )
1656 /* add a new style */
1657 if( numStyles < MAX_LIGHTMAPS )
1659 gp->styles[ numStyles ] = contributions[ i ].style;
1660 bgp->styles[ numStyles ] = contributions[ i ].style;
1662 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1670 /* add the directed color */
1671 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1673 /* ambient light will be at 1/4 the value of directed light */
1674 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1675 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1677 /* (Hobbes: always setting it to .25 is hardly any better) */
1678 d = 0.25f * (1.0f - d);
1679 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1681 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1685 * the total light average = ambient value + 0.25 * sum of all directional values
1686 * we can also get the total light average as 0.25 * the sum of all contributions
1688 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1691 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1693 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1698 /* store off sample */
1699 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1702 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1704 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1707 /* set minimum light and copy off to bytes */
1708 VectorCopy( gp->ambient[ i ], color );
1709 for( j = 0; j < 3; j++ )
1710 if( color[ j ] < minGridLight[ j ] )
1711 color[ j ] = minGridLight[ j ];
1713 /* vortex: apply gridscale and gridambientscale here */
1714 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1715 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1720 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1721 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1723 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1724 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1727 /* store direction */
1728 NormalToLatLong( thisdir, bgp->latLong );
1735 calculates the size of the lightgrid and allocates memory
1738 void SetupGrid( void )
1741 vec3_t maxs, oldGridSize;
1746 /* don't do this if not grid lighting */
1747 if( noGridLighting )
1750 /* ydnar: set grid size */
1751 value = ValueForKey( &entities[ 0 ], "gridsize" );
1752 if( value[ 0 ] != '\0' )
1753 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1756 VectorCopy( gridSize, oldGridSize );
1757 for( i = 0; i < 3; i++ )
1758 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1760 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1761 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1763 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1765 /* get world bounds */
1766 for( i = 0; i < 3; i++ )
1768 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1769 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1770 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1774 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1776 /* increase grid size a bit */
1777 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1778 gridSize[ j++ % 3 ] += 16.0f;
1782 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1785 if( !VectorCompare( gridSize, oldGridSize ) )
1787 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1788 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1789 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1792 /* 2nd variable. fixme: is this silly? */
1793 numBSPGridPoints = numRawGridPoints;
1795 /* allocate lightgrid */
1796 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1797 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1799 if( bspGridPoints != NULL )
1800 free( bspGridPoints );
1801 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1802 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1804 /* clear lightgrid */
1805 for( i = 0; i < numRawGridPoints; i++ )
1807 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1808 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1809 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1810 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1812 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1813 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1818 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1825 does what it says...
1828 void LightWorld( void )
1833 qboolean minVertex, minGrid, ps;
1837 /* ydnar: smooth normals */
1840 Sys_Printf( "--- SmoothNormals ---\n" );
1844 /* determine the number of grid points */
1845 Sys_Printf( "--- SetupGrid ---\n" );
1848 /* find the optional minimum lighting values */
1849 GetVectorForKey( &entities[ 0 ], "_color", color );
1850 if( VectorLength( color ) == 0.0f )
1851 VectorSet( color, 1.0, 1.0, 1.0 );
1854 f = FloatForKey( &entities[ 0 ], "_ambient" );
1856 f = FloatForKey( &entities[ 0 ], "ambient" );
1857 VectorScale( color, f, ambientColor );
1859 /* minvertexlight */
1861 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1862 if( value[ 0 ] != '\0' )
1866 VectorScale( color, f, minVertexLight );
1871 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1872 if( value[ 0 ] != '\0' )
1876 VectorScale( color, f, minGridLight );
1880 value = ValueForKey( &entities[ 0 ], "_minlight" );
1881 if( value[ 0 ] != '\0' )
1884 VectorScale( color, f, minLight );
1885 if( minVertex == qfalse )
1886 VectorScale( color, f, minVertexLight );
1887 if( minGrid == qfalse )
1888 VectorScale( color, f, minGridLight );
1891 /* create world lights */
1892 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1893 CreateEntityLights();
1894 CreateSurfaceLights();
1895 Sys_Printf( "%9d point lights\n", numPointLights );
1896 Sys_Printf( "%9d spotlights\n", numSpotLights );
1897 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1898 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1900 /* calculate lightgrid */
1901 if( !noGridLighting )
1903 /* ydnar: set up light envelopes */
1904 SetupEnvelopes( qtrue, fastgrid );
1906 Sys_Printf( "--- TraceGrid ---\n" );
1908 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1910 Sys_Printf( "%d x %d x %d = %d grid\n",
1911 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1913 /* ydnar: emit statistics on light culling */
1914 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1915 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1918 /* slight optimization to remove a sqrt */
1919 subdivideThreshold *= subdivideThreshold;
1921 /* map the world luxels */
1922 Sys_Printf( "--- MapRawLightmap ---\n" );
1923 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1924 Sys_Printf( "%9d luxels\n", numLuxels );
1925 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1926 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1931 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1932 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1935 /* floodlight pass */
1936 FloodlightRawLightmaps();
1938 /* ydnar: set up light envelopes */
1939 SetupEnvelopes( qfalse, fast );
1941 /* light up my world */
1942 lightsPlaneCulled = 0;
1943 lightsEnvelopeCulled = 0;
1944 lightsBoundsCulled = 0;
1945 lightsClusterCulled = 0;
1947 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1948 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1949 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1951 StitchSurfaceLightmaps();
1953 Sys_Printf( "--- IlluminateVertexes ---\n" );
1954 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1955 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1957 /* ydnar: emit statistics on light culling */
1958 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1959 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1960 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1961 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1968 /* store off the bsp between bounces */
1969 StoreSurfaceLightmaps();
1971 Sys_Printf( "Writing %s\n", source );
1972 WriteBSPFile( source );
1975 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1979 VectorClear( ambientColor );
1980 floodlighty = qfalse;
1982 /* generate diffuse lights */
1984 RadCreateDiffuseLights();
1986 /* setup light envelopes */
1987 SetupEnvelopes( qfalse, fastbounce );
1988 if( numLights == 0 )
1990 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1994 /* add to lightgrid */
1997 gridEnvelopeCulled = 0;
1998 gridBoundsCulled = 0;
2000 Sys_Printf( "--- BounceGrid ---\n" );
2002 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2004 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2005 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2008 /* light up my world */
2009 lightsPlaneCulled = 0;
2010 lightsEnvelopeCulled = 0;
2011 lightsBoundsCulled = 0;
2012 lightsClusterCulled = 0;
2014 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2015 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2016 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2017 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2019 StitchSurfaceLightmaps();
2021 Sys_Printf( "--- IlluminateVertexes ---\n" );
2022 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2023 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2025 /* ydnar: emit statistics on light culling */
2026 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2027 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2028 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2029 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2041 main routine for light processing
2044 int LightMain( int argc, char **argv )
2048 char mapSource[ 1024 ];
2050 int lightmapMergeSize = 0;
2054 Sys_Printf( "--- Light ---\n" );
2055 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2057 /* set standard game flags */
2058 wolfLight = game->wolfLight;
2059 if (wolfLight == qtrue)
2060 Sys_Printf( " lightning model: wolf\n" );
2062 Sys_Printf( " lightning model: quake3\n" );
2064 lmCustomSize = game->lightmapSize;
2065 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2067 lightmapGamma = game->lightmapGamma;
2068 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2070 lightmapCompensate = game->lightmapCompensate;
2071 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2073 lightmapExposure = game->lightmapExposure;
2074 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2076 gridScale = game->gridScale;
2077 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2079 gridAmbientScale = game->gridAmbientScale;
2080 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2082 lightAngleHL = game->lightAngleHL;
2084 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2086 noStyles = game->noStyles;
2087 if (noStyles == qtrue)
2088 Sys_Printf( " shader lightstyles hack: disabled\n" );
2090 Sys_Printf( " shader lightstyles hack: enabled\n" );
2092 keepLights = game->keepLights;
2093 if (keepLights == qtrue)
2094 Sys_Printf( " keep lights: enabled\n" );
2096 Sys_Printf( " keep lights: disabled\n" );
2098 patchShadows = game->patchShadows;
2099 if (patchShadows == qtrue)
2100 Sys_Printf( " patch shadows: enabled\n" );
2102 Sys_Printf( " patch shadows: disabled\n" );
2104 deluxemap = game->deluxeMap;
2105 deluxemode = game->deluxeMode;
2106 if (deluxemap == qtrue)
2109 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2111 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2114 Sys_Printf( " deluxemapping: disabled\n" );
2116 Sys_Printf( "--- ProcessCommandLine ---\n" );
2118 /* process commandline arguments */
2119 for( i = 1; i < (argc - 1); i++ )
2121 /* lightsource scaling */
2122 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2124 f = atof( argv[ i + 1 ] );
2126 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2130 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2132 f = atof( argv[ i + 1 ] );
2134 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2138 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2140 f = atof( argv[ i + 1 ] );
2142 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2146 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2148 f = atof( argv[ i + 1 ] );
2150 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2154 else if( !strcmp( argv[ i ], "-scale" ) )
2156 f = atof( argv[ i + 1 ] );
2161 Sys_Printf( "All light scaled by %f\n", f );
2165 else if( !strcmp( argv[ i ], "-gridscale" ) )
2167 f = atof( argv[ i + 1 ] );
2168 Sys_Printf( "Grid lightning scaled by %f\n", f );
2173 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2175 f = atof( argv[ i + 1 ] );
2176 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2177 gridAmbientScale *= f;
2181 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2183 f = atof( argv[ i + 1 ] );
2185 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2186 Sys_Printf( "Grid directionality is %f\n", f );
2187 gridDirectionality *= f;
2191 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2193 f = atof( argv[ i + 1 ] );
2194 if(f > gridDirectionality) f = gridDirectionality;
2196 Sys_Printf( "Grid ambient directionality is %f\n", f );
2197 gridAmbientDirectionality *= f;
2201 else if( !strcmp( argv[ i ], "-gamma" ) )
2203 f = atof( argv[ i + 1 ] );
2205 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2209 else if( !strcmp( argv[ i ], "-exposure" ) )
2211 f = atof( argv[ i + 1 ] );
2212 lightmapExposure = f;
2213 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2217 else if( !strcmp( argv[ i ], "-compensate" ) )
2219 f = atof( argv[ i + 1 ] );
2222 lightmapCompensate = f;
2223 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2227 /* ydnar switches */
2228 else if( !strcmp( argv[ i ], "-bounce" ) )
2230 bounce = atoi( argv[ i + 1 ] );
2233 else if( bounce > 0 )
2234 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2238 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2240 superSample = atoi( argv[ i + 1 ] );
2241 if( superSample < 1 )
2243 else if( superSample > 1 )
2244 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2248 else if( !strcmp( argv[ i ], "-samples" ) )
2250 lightSamples = atoi( argv[ i + 1 ] );
2251 if( lightSamples < 1 )
2253 else if( lightSamples > 1 )
2254 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2258 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2260 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2261 if( lightSamplesSearchBoxSize <= 0 )
2262 lightSamplesSearchBoxSize = 1;
2263 if( lightSamplesSearchBoxSize > 4 )
2264 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2265 else if( lightSamplesSearchBoxSize != 1 )
2266 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2270 else if( !strcmp( argv[ i ], "-filter" ) )
2273 Sys_Printf( "Lightmap filtering enabled\n" );
2276 else if( !strcmp( argv[ i ], "-dark" ) )
2279 Sys_Printf( "Dark lightmap seams enabled\n" );
2282 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2284 shadeAngleDegrees = atof( argv[ i + 1 ] );
2285 if( shadeAngleDegrees < 0.0f )
2286 shadeAngleDegrees = 0.0f;
2287 else if( shadeAngleDegrees > 0.0f )
2290 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2295 else if( !strcmp( argv[ i ], "-thresh" ) )
2297 subdivideThreshold = atof( argv[ i + 1 ] );
2298 if( subdivideThreshold < 0 )
2299 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2301 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2305 else if( !strcmp( argv[ i ], "-approx" ) )
2307 approximateTolerance = atoi( argv[ i + 1 ] );
2308 if( approximateTolerance < 0 )
2309 approximateTolerance = 0;
2310 else if( approximateTolerance > 0 )
2311 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2314 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2317 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2319 else if( !strcmp( argv[ i ], "-deluxemode" ))
2321 deluxemode = atoi( argv[ i + 1 ] );
2322 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2324 Sys_Printf( "Generating modelspace deluxemaps\n" );
2328 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2331 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2334 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2336 else if( !strcmp( argv[ i ], "-external" ) )
2338 externalLightmaps = qtrue;
2339 Sys_Printf( "Storing all lightmaps externally\n" );
2342 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2344 lmCustomSize = atoi( argv[ i + 1 ] );
2346 /* must be a power of 2 and greater than 2 */
2347 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2349 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2350 lmCustomSize = game->lightmapSize;
2353 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2355 /* enable external lightmaps */
2356 if( lmCustomSize != game->lightmapSize )
2358 externalLightmaps = qtrue;
2359 Sys_Printf( "Storing all lightmaps externally\n" );
2363 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2365 lmLimitSize = atoi( argv[ i + 1 ] );
2368 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2371 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2373 lmCustomDir = argv[i + 1];
2375 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2376 externalLightmaps = qtrue;
2377 Sys_Printf( "Storing all lightmaps externally\n" );
2380 /* ydnar: add this to suppress warnings */
2381 else if( !strcmp( argv[ i ], "-custinfoparms") )
2383 Sys_Printf( "Custom info parms enabled\n" );
2384 useCustomInfoParms = qtrue;
2387 else if( !strcmp( argv[ i ], "-wolf" ) )
2389 /* -game should already be set */
2391 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2394 else if( !strcmp( argv[ i ], "-q3" ) )
2396 /* -game should already be set */
2398 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2401 else if( !strcmp( argv[ i ], "-extradist" ) )
2403 extraDist = atof( argv[ i + 1 ] );
2407 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2410 else if( !strcmp( argv[ i ], "-sunonly" ) )
2413 Sys_Printf( "Only computing sunlight\n" );
2416 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2419 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2422 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2425 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2428 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2430 lightmapSearchBlockSize = 1;
2431 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2434 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2436 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2438 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2441 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2443 lightmapSearchBlockSize = atoi(argv[i+1]);
2445 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2448 else if( !strcmp( argv[ i ], "-shade" ) )
2451 Sys_Printf( "Phong shading enabled\n" );
2454 else if( !strcmp( argv[ i ], "-bouncegrid") )
2458 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2461 else if( !strcmp( argv[ i ], "-smooth" ) )
2463 lightSamples = EXTRA_SCALE;
2464 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2467 else if( !strcmp( argv[ i ], "-fast" ) )
2472 Sys_Printf( "Fast mode enabled\n" );
2475 else if( !strcmp( argv[ i ], "-faster" ) )
2481 Sys_Printf( "Faster mode enabled\n" );
2484 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2487 Sys_Printf( "Fast grid lighting enabled\n" );
2490 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2493 Sys_Printf( "Fast bounce mode enabled\n" );
2496 else if( !strcmp( argv[ i ], "-cheap" ) )
2500 Sys_Printf( "Cheap mode enabled\n" );
2503 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2506 Sys_Printf( "Cheap grid mode enabled\n" );
2509 else if( !strcmp( argv[ i ], "-normalmap" ) )
2512 Sys_Printf( "Storing normal map instead of lightmap\n" );
2515 else if( !strcmp( argv[ i ], "-trisoup" ) )
2518 Sys_Printf( "Converting brush faces to triangle soup\n" );
2521 else if( !strcmp( argv[ i ], "-debug" ) )
2524 Sys_Printf( "Lightmap debugging enabled\n" );
2527 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2529 debugSurfaces = qtrue;
2530 Sys_Printf( "Lightmap surface debugging enabled\n" );
2533 else if( !strcmp( argv[ i ], "-debugunused" ) )
2535 debugUnused = qtrue;
2536 Sys_Printf( "Unused luxel debugging enabled\n" );
2539 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2542 Sys_Printf( "Lightmap axis debugging enabled\n" );
2545 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2547 debugCluster = qtrue;
2548 Sys_Printf( "Luxel cluster debugging enabled\n" );
2551 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2553 debugOrigin = qtrue;
2554 Sys_Printf( "Luxel origin debugging enabled\n" );
2557 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2560 debugDeluxemap = qtrue;
2561 Sys_Printf( "Deluxemap debugging enabled\n" );
2564 else if( !strcmp( argv[ i ], "-export" ) )
2566 exportLightmaps = qtrue;
2567 Sys_Printf( "Exporting lightmaps\n" );
2570 else if( !strcmp(argv[ i ], "-notrace" ))
2573 Sys_Printf( "Shadow occlusion disabled\n" );
2575 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2577 patchShadows = qtrue;
2578 Sys_Printf( "Patch shadow casting enabled\n" );
2580 else if( !strcmp( argv[ i ], "-extra" ) )
2582 superSample = EXTRA_SCALE; /* ydnar */
2583 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2585 else if( !strcmp( argv[ i ], "-extrawide" ) )
2587 superSample = EXTRAWIDE_SCALE; /* ydnar */
2588 filter = qtrue; /* ydnar */
2589 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2591 else if( !strcmp( argv[ i ], "-samplesize" ) )
2593 sampleSize = atoi( argv[ i + 1 ] );
2594 if( sampleSize < 1 )
2597 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2599 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2601 minSampleSize = atoi( argv[ i + 1 ] );
2602 if( minSampleSize < 1 )
2605 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2607 else if( !strcmp( argv[ i ], "-samplescale" ) )
2609 sampleScale = atoi( argv[ i + 1 ] );
2611 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2613 else if( !strcmp( argv[ i ], "-novertex" ) )
2615 noVertexLighting = qtrue;
2616 Sys_Printf( "Disabling vertex lighting\n" );
2618 else if( !strcmp( argv[ i ], "-nogrid" ) )
2620 noGridLighting = qtrue;
2621 Sys_Printf( "Disabling grid lighting\n" );
2623 else if( !strcmp( argv[ i ], "-border" ) )
2625 lightmapBorder = qtrue;
2626 Sys_Printf( "Adding debug border to lightmaps\n" );
2628 else if( !strcmp( argv[ i ], "-nosurf" ) )
2631 Sys_Printf( "Not tracing against surfaces\n" );
2633 else if( !strcmp( argv[ i ], "-dump" ) )
2636 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2638 else if( !strcmp( argv[ i ], "-lomem" ) )
2641 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2643 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2645 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2647 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2649 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2651 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2654 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2657 Sys_Printf( "Disabling lightstyles\n" );
2659 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2662 Sys_Printf( "Enabling lightstyles\n" );
2664 else if( !strcmp( argv[ i ], "-keeplights" ))
2667 Sys_Printf( "Leaving light entities on map after compile\n" );
2669 else if( !strcmp( argv[ i ], "-cpma" ) )
2672 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2674 else if( !strcmp( argv[ i ], "-floodlight" ) )
2676 floodlighty = qtrue;
2677 Sys_Printf( "FloodLighting enabled\n" );
2679 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2681 debugnormals = qtrue;
2682 Sys_Printf( "DebugNormals enabled\n" );
2684 else if( !strcmp( argv[ i ], "-lowquality" ) )
2686 floodlight_lowquality = qtrue;
2687 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2690 /* r7: dirtmapping */
2691 else if( !strcmp( argv[ i ], "-dirty" ) )
2694 Sys_Printf( "Dirtmapping enabled\n" );
2696 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2699 Sys_Printf( "Dirtmap debugging enabled\n" );
2701 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2703 dirtMode = atoi( argv[ i + 1 ] );
2704 if( dirtMode != 0 && dirtMode != 1 )
2707 Sys_Printf( "Enabling randomized dirtmapping\n" );
2709 Sys_Printf( "Enabling ordered dir mapping\n" );
2712 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2714 dirtDepth = atof( argv[ i + 1 ] );
2715 if( dirtDepth <= 0.0f )
2717 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2720 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2722 dirtScale = atof( argv[ i + 1 ] );
2723 if( dirtScale <= 0.0f )
2725 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2728 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2730 dirtGain = atof( argv[ i + 1 ] );
2731 if( dirtGain <= 0.0f )
2733 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2736 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2738 lightmapTriangleCheck = qtrue;
2740 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2742 lightmapExtraVisClusterNudge = qtrue;
2744 /* unhandled args */
2747 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2752 /* fix up lightmap search power */
2753 if(lightmapMergeSize)
2755 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2756 if(lightmapSearchBlockSize < 1)
2757 lightmapSearchBlockSize = 1;
2759 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2762 /* clean up map name */
2763 strcpy( source, ExpandArg( argv[ i ] ) );
2764 StripExtension( source );
2765 DefaultExtension( source, ".bsp" );
2766 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2767 StripExtension( mapSource );
2768 DefaultExtension( mapSource, ".map" );
2770 /* ydnar: set default sample size */
2771 SetDefaultSampleSize( sampleSize );
2773 /* ydnar: handle shaders */
2774 BeginMapShaderFile( source );
2778 Sys_Printf( "Loading %s\n", source );
2780 /* ydnar: load surface file */
2781 LoadSurfaceExtraFile( source );
2784 LoadBSPFile( source );
2786 /* parse bsp entities */
2789 /* inject command line parameters */
2790 InjectCommandLine(argv, 0, argc - 1);
2793 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2794 if( value[ 0 ] != '1' )
2795 LoadMapFile( mapSource, qtrue );
2797 /* set the entity/model origins and init yDrawVerts */
2800 /* ydnar: set up optimization */
2804 SetupSurfaceLightmaps();
2806 /* initialize the surface facet tracing */
2809 /* light the world */
2812 /* ydnar: store off lightmaps */
2813 StoreSurfaceLightmaps();
2815 /* write out the bsp */
2817 Sys_Printf( "Writing %s\n", source );
2818 WriteBSPFile( source );
2820 /* ydnar: export lightmaps */
2821 if( exportLightmaps && !externalLightmaps )
2824 /* return to sender */