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;
\r
753 qboolean angledDeluxe = qfalse;
\r
754 float colorBrightness;
757 light = trace->light;
760 VectorClear( trace->color );
761 VectorClear( trace->colorNoShadow );
762 VectorClear( trace->directionContribution );
\r
764 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
766 /* ydnar: early out */
767 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
770 /* do some culling checks */
771 if( light->type != EMIT_SUN )
773 /* MrE: if the light is behind the surface */
774 if( trace->twoSided == qfalse )
775 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
778 /* ydnar: test pvs */
779 if( !ClusterVisible( trace->cluster, light->cluster ) )
783 /* exact point to polygon form factor */
784 if( light->type == EMIT_AREA )
790 /* project sample point into light plane */
791 d = DotProduct( trace->origin, light->normal ) - light->dist;
794 /* sample point behind plane? */
795 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
798 /* sample plane coincident? */
799 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
803 /* nudge the point so that it is clearly forward of the light */
804 /* so that surfaces meeting a light emitter don't get black edges */
805 if( d > -8.0f && d < 8.0f )
806 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
808 VectorCopy( trace->origin, pushedOrigin );
810 /* get direction and distance */
811 VectorCopy( light->origin, trace->end );
812 dist = SetupTrace( trace );
813 if( dist >= light->envelope )
816 /* ptpff approximation */
819 /* angle attenuation */
820 angle = DotProduct( trace->normal, trace->direction );
822 /* twosided lighting */
823 if( trace->twoSided )
824 angle = fabs( angle );
827 angle *= -DotProduct( light->normal, trace->direction );
830 else if( angle < 0.0f &&
831 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
834 /* clamp the distance to prevent super hot spots */
835 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
839 add = light->photons / (dist * dist) * angle;
844 addDeluxe = light->photons / (dist * dist) * angle;
\r
846 addDeluxe = light->photons / (dist * dist);
\r
851 /* calculate the contribution */
852 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
855 else if( factor < 0.0f )
857 /* twosided lighting */
858 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
862 /* push light origin to other side of the plane */
863 VectorMA( light->origin, -2.0f, light->normal, trace->end );
864 dist = SetupTrace( trace );
865 if( dist >= light->envelope )
872 /* ydnar: moved to here */
873 add = factor * light->add;
880 /* point/spot lights */
881 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
883 /* get direction and distance */
884 VectorCopy( light->origin, trace->end );
885 dist = SetupTrace( trace );
886 if( dist >= light->envelope )
889 /* clamp the distance to prevent super hot spots */
890 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
894 /* angle attenuation */
895 if( light->flags & LIGHT_ATTEN_ANGLE )
897 /* standard Lambert attenuation */
898 float dot = DotProduct( trace->normal, trace->direction );
900 /* twosided lighting */
901 if( trace->twoSided )
904 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
907 if( dot > 0.001f ) // skip coplanar
909 if( dot > 1.0f ) dot = 1.0f;
910 dot = ( dot * 0.5f ) + 0.5f;
922 if( light->angleScale != 0.0f )
924 angle /= light->angleScale;
930 if( light->flags & LIGHT_ATTEN_LINEAR )
932 add = angle * light->photons * linearScale - (dist * light->fade);
939 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
\r
941 addDeluxe = light->photons * linearScale - (dist * light->fade);
\r
943 if( addDeluxe < 0.0f )
\r
949 add = (light->photons / (dist * dist)) * angle;
956 addDeluxe = (light->photons / (dist * dist)) * angle;
\r
958 addDeluxe = (light->photons / (dist * dist));
\r
961 if( addDeluxe < 0.0f )
\r
965 /* handle spotlights */
966 if( light->type == EMIT_SPOT )
968 float distByNormal, radiusAtDist, sampleRadius;
969 vec3_t pointAtDist, distToSample;
971 /* do cone calculation */
972 distByNormal = -DotProduct( trace->displacement, light->normal );
973 if( distByNormal < 0.0f )
975 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
976 radiusAtDist = light->radiusByDist * distByNormal;
977 VectorSubtract( trace->origin, pointAtDist, distToSample );
978 sampleRadius = VectorLength( distToSample );
980 /* outside the cone */
981 if( sampleRadius >= radiusAtDist )
985 if( sampleRadius > (radiusAtDist - 32.0f) )
987 add *= ((radiusAtDist - sampleRadius) / 32.0f);
991 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
\r
993 if( addDeluxe < 0.0f )
\r
999 /* ydnar: sunlight */
1000 else if( light->type == EMIT_SUN )
1002 /* get origin and direction */
1003 VectorAdd( trace->origin, light->origin, trace->end );
1004 dist = SetupTrace( trace );
1006 /* angle attenuation */
1007 if( light->flags & LIGHT_ATTEN_ANGLE )
1009 /* standard Lambert attenuation */
1010 float dot = DotProduct( trace->normal, trace->direction );
1012 /* twosided lighting */
1013 if( trace->twoSided )
1016 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1019 if( dot > 0.001f ) // skip coplanar
1021 if( dot > 1.0f ) dot = 1.0f;
1022 dot = ( dot * 0.5f ) + 0.5f;
1035 add = light->photons * angle;
1039 if( angledDeluxe )
\r
1040 addDeluxe = light->photons * angle;
\r
1042 addDeluxe = light->photons;
\r
1044 if( addDeluxe < 0.0f )
\r
1051 /* VorteX: set noShadow color */
1052 VectorScale(light->color, add, trace->colorNoShadow);
1054 addDeluxe *= colorBrightness;
\r
1058 addDeluxe *= addDeluxeBounceScale;
\r
1059 if( addDeluxe < 0.00390625f )
\r
1060 addDeluxe = 0.00390625f;
\r
1063 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1066 trace->testAll = qtrue;
1067 VectorScale( light->color, add, trace->color );
1069 /* trace to point */
1070 if( trace->testOcclusion && !trace->forceSunlight )
1074 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1076 VectorClear( trace->color );
1077 VectorClear( trace->directionContribution );
1083 /* return to sender */
1087 /* VorteX: set noShadow color */
1088 VectorScale(light->color, add, trace->colorNoShadow);
1090 /* ydnar: changed to a variable number */
1091 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1094 addDeluxe *= colorBrightness;
\r
1096 /* hack land: scale down the radiosity contribution to light directionality.
\r
1097 Deluxemaps fusion many light directions into one. In a rtl process all lights
\r
1098 would contribute individually to the bump map, so several light sources together
\r
1099 would make it more directional (example: a yellow and red lights received from
\r
1100 opposing sides would light one side in red and the other in blue, adding
\r
1101 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
\r
1102 neutralize each other making it look like having no direction.
\r
1103 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
\r
1104 is modifying the direction applied from directional lights, making it go closer and closer
\r
1105 to the surface normal the bigger is the amount of radiosity received.
\r
1106 So, for preserving the directional lights contributions, we scale down the radiosity
\r
1107 contribution. It's a hack, but there's a reason behind it */
\r
1110 addDeluxe *= addDeluxeBounceScale;
\r
1111 if( addDeluxe < 0.00390625f )
\r
1112 addDeluxe = 0.00390625f;
\r
1115 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1118 trace->testAll = qfalse;
1119 VectorScale( light->color, add, trace->color );
1123 if( trace->passSolid || trace->opaque )
1125 VectorClear( trace->color );
1126 VectorClear( trace->directionContribution );
\r
1131 /* return to sender */
1139 determines the amount of light reaching a sample (luxel or vertex)
1142 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1148 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1149 VectorClear( colors[ lightmapNum ] );
1151 /* ydnar: normalmap */
1154 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1155 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1156 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1160 /* ydnar: don't bounce ambient all the time */
1162 VectorCopy( ambientColor, colors[ 0 ] );
1164 /* ydnar: trace to all the list of lights pre-stored in tw */
1165 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1168 trace->light = trace->lights[ i ];
1171 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1173 if( styles[ lightmapNum ] == trace->light->style ||
1174 styles[ lightmapNum ] == LS_NONE )
1178 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1179 if( lightmapNum >= MAX_LIGHTMAPS )
1183 LightContributionToSample( trace );
1184 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1187 /* handle negative light */
1188 if( trace->light->flags & LIGHT_NEGATIVE )
1189 VectorScale( trace->color, -1.0f, trace->color );
1192 styles[ lightmapNum ] = trace->light->style;
1195 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1199 colors[ 0 ][ 0 ] >= 255.0f &&
1200 colors[ 0 ][ 1 ] >= 255.0f &&
1201 colors[ 0 ][ 2 ] >= 255.0f )
1209 LightContributionToPoint()
1210 for a given light, how much light/color reaches a given point in space (with no facing)
1211 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1214 int LightContributionToPoint( trace_t *trace )
1221 light = trace->light;
1224 VectorClear( trace->color );
1226 /* ydnar: early out */
1227 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1230 /* is this a sun? */
1231 if( light->type != EMIT_SUN )
1238 if( !ClusterVisible( trace->cluster, light->cluster ) )
1242 /* ydnar: check origin against light's pvs envelope */
1243 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1244 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1245 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1251 /* set light origin */
1252 if( light->type == EMIT_SUN )
1253 VectorAdd( trace->origin, light->origin, trace->end );
1255 VectorCopy( light->origin, trace->end );
1258 dist = SetupTrace( trace );
1261 if( dist > light->envelope )
1263 gridEnvelopeCulled++;
1267 /* ptpff approximation */
1268 if( light->type == EMIT_AREA && faster )
1270 /* clamp the distance to prevent super hot spots */
1271 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1276 add = light->photons / (dist * dist);
1279 /* exact point to polygon form factor */
1280 else if( light->type == EMIT_AREA )
1283 vec3_t pushedOrigin;
1286 /* see if the point is behind the light */
1287 d = DotProduct( trace->origin, light->normal ) - light->dist;
1288 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1291 /* nudge the point so that it is clearly forward of the light */
1292 /* so that surfaces meeting a light emiter don't get black edges */
1293 if( d > -8.0f && d < 8.0f )
1294 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1296 VectorCopy( trace->origin, pushedOrigin );
1298 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1299 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1300 if( factor == 0.0f )
1302 else if( factor < 0.0f )
1304 if( light->flags & LIGHT_TWOSIDED )
1310 /* ydnar: moved to here */
1311 add = factor * light->add;
1314 /* point/spot lights */
1315 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1317 /* clamp the distance to prevent super hot spots */
1318 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1323 if( light->flags & LIGHT_ATTEN_LINEAR )
1325 add = light->photons * linearScale - (dist * light->fade);
1330 add = light->photons / (dist * dist);
1332 /* handle spotlights */
1333 if( light->type == EMIT_SPOT )
1335 float distByNormal, radiusAtDist, sampleRadius;
1336 vec3_t pointAtDist, distToSample;
1339 /* do cone calculation */
1340 distByNormal = -DotProduct( trace->displacement, light->normal );
1341 if( distByNormal < 0.0f )
1343 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1344 radiusAtDist = light->radiusByDist * distByNormal;
1345 VectorSubtract( trace->origin, pointAtDist, distToSample );
1346 sampleRadius = VectorLength( distToSample );
1348 /* outside the cone */
1349 if( sampleRadius >= radiusAtDist )
1353 if( sampleRadius > (radiusAtDist - 32.0f) )
1354 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1358 /* ydnar: sunlight */
1359 else if( light->type == EMIT_SUN )
1362 add = light->photons;
1367 trace->testAll = qtrue;
1368 VectorScale( light->color, add, trace->color );
1370 /* trace to point */
1371 if( trace->testOcclusion && !trace->forceSunlight )
1375 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1377 VectorClear( trace->color );
1382 /* return to sender */
1386 /* unknown light type */
1390 /* ydnar: changed to a variable number */
1391 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1395 trace->testAll = qfalse;
1396 VectorScale( light->color, add, trace->color );
1400 if( trace->passSolid )
1402 VectorClear( trace->color );
1406 /* we have a valid sample */
1414 grid samples are for quickly determining the lighting
1415 of dynamically placed entities in the world
1418 #define MAX_CONTRIBUTIONS 32768
1428 void TraceGrid( int num )
1430 int i, j, x, y, z, mod, numCon, numStyles;
1432 vec3_t baseOrigin, cheapColor, color, thisdir;
1434 bspGridPoint_t *bgp;
1435 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1438 /* get grid points */
1439 gp = &rawGridPoints[ num ];
1440 bgp = &bspGridPoints[ num ];
1442 /* get grid origin */
1444 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1445 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1446 y = mod / gridBounds[ 0 ];
1447 mod -= y * gridBounds[ 0 ];
1450 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1451 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1452 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1454 /* set inhibit sphere */
1455 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1456 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1457 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1458 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1460 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1462 /* find point cluster */
1463 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1464 if( trace.cluster < 0 )
1466 /* try to nudge the origin around to find a valid point */
1467 VectorCopy( trace.origin, baseOrigin );
1468 for( step = 0; (step += 0.005) <= 1.0; )
1470 VectorCopy( baseOrigin, trace.origin );
1471 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1472 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1473 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1475 /* ydnar: changed to find cluster num */
1476 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1477 if( trace.cluster >= 0 )
1481 /* can't find a valid point at all */
1487 trace.testOcclusion = !noTrace;
1488 trace.forceSunlight = qfalse;
1489 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1490 trace.numSurfaces = 0;
1491 trace.surfaces = NULL;
1492 trace.numLights = 0;
1493 trace.lights = NULL;
1497 VectorClear( cheapColor );
1499 /* trace to all the lights, find the major light direction, and divide the
1500 total light between that along the direction and the remaining in the ambient */
1501 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1507 if( !LightContributionToPoint( &trace ) )
1510 /* handle negative light */
1511 if( trace.light->flags & LIGHT_NEGATIVE )
1512 VectorScale( trace.color, -1.0f, trace.color );
1514 /* add a contribution */
1515 VectorCopy( trace.color, contributions[ numCon ].color );
1516 VectorCopy( trace.direction, contributions[ numCon ].dir );
1517 contributions[ numCon ].style = trace.light->style;
1520 /* push average direction around */
1521 addSize = VectorLength( trace.color );
1522 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1524 /* stop after a while */
1525 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1528 /* ydnar: cheap mode */
1529 VectorAdd( cheapColor, trace.color, cheapColor );
1530 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1534 /////// Floodlighting for point //////////////////
1535 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1541 col[0]=col[1]=col[2]=floodlightIntensity;
1545 trace.testOcclusion = qtrue;
1546 trace.forceSunlight = qfalse;
1547 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1548 trace.testAll = qtrue;
1552 if (q==0) //upper hemisphere
1558 else //lower hemisphere
1565 f = FloodLightForSample(&trace, floodlightDistance, floodlight_lowquality);
1567 contributions[ numCon ].color[0]=col[0]*f;
1568 contributions[ numCon ].color[1]=col[1]*f;
1569 contributions[ numCon ].color[2]=col[2]*f;
1571 contributions[ numCon ].dir[0]=dir[0];
1572 contributions[ numCon ].dir[1]=dir[1];
1573 contributions[ numCon ].dir[2]=dir[2];
1575 contributions[ numCon ].style = 0;
1577 /* push average direction around */
1578 addSize = VectorLength( col );
1579 VectorMA( gp->dir, addSize, dir, gp->dir );
1582 /////////////////////
1584 /* normalize to get primary light direction */
1585 VectorNormalize( gp->dir, thisdir );
1587 /* now that we have identified the primary light direction,
1588 go back and separate all the light into directed and ambient */
1591 for( i = 0; i < numCon; i++ )
1593 /* get relative directed strength */
1594 d = DotProduct( contributions[ i ].dir, thisdir );
1595 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1596 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1600 /* find appropriate style */
1601 for( j = 0; j < numStyles; j++ )
1603 if( gp->styles[ j ] == contributions[ i ].style )
1607 /* style not found? */
1608 if( j >= numStyles )
1610 /* add a new style */
1611 if( numStyles < MAX_LIGHTMAPS )
1613 gp->styles[ numStyles ] = contributions[ i ].style;
1614 bgp->styles[ numStyles ] = contributions[ i ].style;
1616 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1624 /* add the directed color */
1625 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1627 /* ambient light will be at 1/4 the value of directed light */
1628 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1629 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1631 /* (Hobbes: always setting it to .25 is hardly any better) */
1632 d = 0.25f * (1.0f - d);
1633 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1637 * the total light average = ambient value + 0.25 * sum of all directional values
1638 * we can also get the total light average as 0.25 * the sum of all contributions
1640 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1643 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1645 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1650 /* store off sample */
1651 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1654 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1656 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1659 /* set minimum light and copy off to bytes */
1660 VectorCopy( gp->ambient[ i ], color );
1661 for( j = 0; j < 3; j++ )
1662 if( color[ j ] < minGridLight[ j ] )
1663 color[ j ] = minGridLight[ j ];
1665 /* vortex: apply gridscale and gridambientscale here */
1666 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1667 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1672 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1673 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1675 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1676 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1679 /* store direction */
1680 NormalToLatLong( thisdir, bgp->latLong );
1687 calculates the size of the lightgrid and allocates memory
1690 void SetupGrid( void )
1693 vec3_t maxs, oldGridSize;
1698 /* don't do this if not grid lighting */
1699 if( noGridLighting )
1702 /* ydnar: set grid size */
1703 value = ValueForKey( &entities[ 0 ], "gridsize" );
1704 if( value[ 0 ] != '\0' )
1705 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1708 VectorCopy( gridSize, oldGridSize );
1709 for( i = 0; i < 3; i++ )
1710 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1712 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1713 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1715 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1717 /* get world bounds */
1718 for( i = 0; i < 3; i++ )
1720 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1721 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1722 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1726 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1728 /* increase grid size a bit */
1729 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1730 gridSize[ j++ % 3 ] += 16.0f;
1734 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1737 if( !VectorCompare( gridSize, oldGridSize ) )
1739 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1740 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1741 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1744 /* 2nd variable. fixme: is this silly? */
1745 numBSPGridPoints = numRawGridPoints;
1747 /* allocate lightgrid */
1748 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1749 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1751 if( bspGridPoints != NULL )
1752 free( bspGridPoints );
1753 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1754 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1756 /* clear lightgrid */
1757 for( i = 0; i < numRawGridPoints; i++ )
1759 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1760 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1761 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1762 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1764 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1765 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1770 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1777 does what it says...
1780 void LightWorld( void )
1785 qboolean minVertex, minGrid, ps;
1789 /* ydnar: smooth normals */
1792 Sys_Printf( "--- SmoothNormals ---\n" );
1796 /* determine the number of grid points */
1797 Sys_Printf( "--- SetupGrid ---\n" );
1800 /* find the optional minimum lighting values */
1801 GetVectorForKey( &entities[ 0 ], "_color", color );
1802 if( VectorLength( color ) == 0.0f )
1803 VectorSet( color, 1.0, 1.0, 1.0 );
1806 f = FloatForKey( &entities[ 0 ], "_ambient" );
1808 f = FloatForKey( &entities[ 0 ], "ambient" );
1809 VectorScale( color, f, ambientColor );
1811 /* minvertexlight */
1813 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1814 if( value[ 0 ] != '\0' )
1818 VectorScale( color, f, minVertexLight );
1823 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1824 if( value[ 0 ] != '\0' )
1828 VectorScale( color, f, minGridLight );
1832 value = ValueForKey( &entities[ 0 ], "_minlight" );
1833 if( value[ 0 ] != '\0' )
1836 VectorScale( color, f, minLight );
1837 if( minVertex == qfalse )
1838 VectorScale( color, f, minVertexLight );
1839 if( minGrid == qfalse )
1840 VectorScale( color, f, minGridLight );
1843 /* create world lights */
1844 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1845 CreateEntityLights();
1846 CreateSurfaceLights();
1847 Sys_Printf( "%9d point lights\n", numPointLights );
1848 Sys_Printf( "%9d spotlights\n", numSpotLights );
1849 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1850 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1852 /* calculate lightgrid */
1853 if( !noGridLighting )
1855 /* ydnar: set up light envelopes */
1856 SetupEnvelopes( qtrue, fastgrid );
1858 Sys_Printf( "--- TraceGrid ---\n" );
1860 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1862 Sys_Printf( "%d x %d x %d = %d grid\n",
1863 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1865 /* ydnar: emit statistics on light culling */
1866 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1867 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1870 /* slight optimization to remove a sqrt */
1871 subdivideThreshold *= subdivideThreshold;
1873 /* map the world luxels */
1874 Sys_Printf( "--- MapRawLightmap ---\n" );
1875 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1876 Sys_Printf( "%9d luxels\n", numLuxels );
1877 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1878 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1883 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1884 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1887 /* floodlight pass */
1888 FloodlightRawLightmaps();
1890 /* ydnar: set up light envelopes */
1891 SetupEnvelopes( qfalse, fast );
1893 /* light up my world */
1894 lightsPlaneCulled = 0;
1895 lightsEnvelopeCulled = 0;
1896 lightsBoundsCulled = 0;
1897 lightsClusterCulled = 0;
1899 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1900 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1901 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1903 StitchSurfaceLightmaps();
1905 Sys_Printf( "--- IlluminateVertexes ---\n" );
1906 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1907 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1909 /* ydnar: emit statistics on light culling */
1910 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1911 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1912 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1913 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1920 /* store off the bsp between bounces */
1921 StoreSurfaceLightmaps();
1923 Sys_Printf( "Writing %s\n", source );
1924 WriteBSPFile( source );
1927 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1931 VectorClear( ambientColor );
1932 floodlighty = qfalse;
1934 /* generate diffuse lights */
1936 RadCreateDiffuseLights();
1938 /* setup light envelopes */
1939 SetupEnvelopes( qfalse, fastbounce );
1940 if( numLights == 0 )
1942 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1946 /* add to lightgrid */
1949 gridEnvelopeCulled = 0;
1950 gridBoundsCulled = 0;
1952 Sys_Printf( "--- BounceGrid ---\n" );
1954 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1956 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1957 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1960 /* light up my world */
1961 lightsPlaneCulled = 0;
1962 lightsEnvelopeCulled = 0;
1963 lightsBoundsCulled = 0;
1964 lightsClusterCulled = 0;
1966 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1967 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1968 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1969 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1971 StitchSurfaceLightmaps();
1973 Sys_Printf( "--- IlluminateVertexes ---\n" );
1974 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1975 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1977 /* ydnar: emit statistics on light culling */
1978 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1979 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1980 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1981 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1993 main routine for light processing
1996 int LightMain( int argc, char **argv )
2000 char mapSource[ 1024 ];
2002 int lightmapMergeSize = 0;
2006 Sys_Printf( "--- Light ---\n" );
2007 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2009 /* set standard game flags */
2010 wolfLight = game->wolfLight;
2011 if (wolfLight == qtrue)
2012 Sys_Printf( " lightning model: wolf\n" );
2014 Sys_Printf( " lightning model: quake3\n" );
2016 lmCustomSize = game->lightmapSize;
2017 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2019 lightmapGamma = game->lightmapGamma;
2020 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2022 lightmapCompensate = game->lightmapCompensate;
2023 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2025 lightmapExposure = game->lightmapExposure;
2026 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2028 gridScale = game->gridScale;
2029 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2031 gridAmbientScale = game->gridAmbientScale;
2032 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2034 lightAngleHL = game->lightAngleHL;
2036 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2038 noStyles = game->noStyles;
2039 if (noStyles == qtrue)
2040 Sys_Printf( " shader lightstyles hack: disabled\n" );
2042 Sys_Printf( " shader lightstyles hack: enabled\n" );
2044 keepLights = game->keepLights;
2045 if (keepLights == qtrue)
2046 Sys_Printf( " keep lights: enabled\n" );
2048 Sys_Printf( " keep lights: disabled\n" );
2050 patchShadows = game->patchShadows;
2051 if (patchShadows == qtrue)
2052 Sys_Printf( " patch shadows: enabled\n" );
2054 Sys_Printf( " patch shadows: disabled\n" );
2056 deluxemap = game->deluxeMap;
2057 deluxemode = game->deluxeMode;
2058 if (deluxemap == qtrue)
2061 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2063 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2066 Sys_Printf( " deluxemapping: disabled\n" );
2068 Sys_Printf( "--- ProcessCommandLine ---\n" );
2070 /* process commandline arguments */
2071 for( i = 1; i < (argc - 1); i++ )
2073 /* lightsource scaling */
2074 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2076 f = atof( argv[ i + 1 ] );
2078 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2082 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2084 f = atof( argv[ i + 1 ] );
2086 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2090 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2092 f = atof( argv[ i + 1 ] );
2094 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2098 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2100 f = atof( argv[ i + 1 ] );
2102 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2106 else if( !strcmp( argv[ i ], "-scale" ) )
2108 f = atof( argv[ i + 1 ] );
2113 Sys_Printf( "All light scaled by %f\n", f );
2117 else if( !strcmp( argv[ i ], "-gridscale" ) )
2119 f = atof( argv[ i + 1 ] );
2120 Sys_Printf( "Grid lightning scaled by %f\n", f );
2125 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2127 f = atof( argv[ i + 1 ] );
2128 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2129 gridAmbientScale *= f;
2133 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2135 f = atof( argv[ i + 1 ] );
2137 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2138 Sys_Printf( "Grid directionality is %f\n", f );
2139 gridDirectionality *= f;
2143 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2145 f = atof( argv[ i + 1 ] );
2146 if(f > gridDirectionality) f = gridDirectionality;
2148 Sys_Printf( "Grid ambient directionality is %f\n", f );
2149 gridAmbientDirectionality *= f;
2153 else if( !strcmp( argv[ i ], "-gamma" ) )
2155 f = atof( argv[ i + 1 ] );
2157 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2161 else if( !strcmp( argv[ i ], "-exposure" ) )
2163 f = atof( argv[ i + 1 ] );
2164 lightmapExposure = f;
2165 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2169 else if( !strcmp( argv[ i ], "-compensate" ) )
2171 f = atof( argv[ i + 1 ] );
2174 lightmapCompensate = f;
2175 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2179 /* ydnar switches */
2180 else if( !strcmp( argv[ i ], "-bounce" ) )
2182 bounce = atoi( argv[ i + 1 ] );
2185 else if( bounce > 0 )
2186 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2190 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2192 superSample = atoi( argv[ i + 1 ] );
2193 if( superSample < 1 )
2195 else if( superSample > 1 )
2196 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2200 else if( !strcmp( argv[ i ], "-samples" ) )
2202 lightSamples = atoi( argv[ i + 1 ] );
2203 if( lightSamples < 1 )
2205 else if( lightSamples > 1 )
2206 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2210 else if( !strcmp( argv[ i ], "-filter" ) )
2213 Sys_Printf( "Lightmap filtering enabled\n" );
2216 else if( !strcmp( argv[ i ], "-dark" ) )
2219 Sys_Printf( "Dark lightmap seams enabled\n" );
2222 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2224 shadeAngleDegrees = atof( argv[ i + 1 ] );
2225 if( shadeAngleDegrees < 0.0f )
2226 shadeAngleDegrees = 0.0f;
2227 else if( shadeAngleDegrees > 0.0f )
2230 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2235 else if( !strcmp( argv[ i ], "-thresh" ) )
2237 subdivideThreshold = atof( argv[ i + 1 ] );
2238 if( subdivideThreshold < 0 )
2239 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2241 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2245 else if( !strcmp( argv[ i ], "-approx" ) )
2247 approximateTolerance = atoi( argv[ i + 1 ] );
2248 if( approximateTolerance < 0 )
2249 approximateTolerance = 0;
2250 else if( approximateTolerance > 0 )
2251 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2254 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2257 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2259 else if( !strcmp( argv[ i ], "-deluxemode" ))
2261 deluxemode = atoi( argv[ i + 1 ] );
2262 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2264 Sys_Printf( "Generating modelspace deluxemaps\n" );
2268 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2271 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2274 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2276 else if( !strcmp( argv[ i ], "-external" ) )
2278 externalLightmaps = qtrue;
2279 Sys_Printf( "Storing all lightmaps externally\n" );
2282 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2284 lmCustomSize = atoi( argv[ i + 1 ] );
2286 /* must be a power of 2 and greater than 2 */
2287 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2289 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2290 lmCustomSize = game->lightmapSize;
2293 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2295 /* enable external lightmaps */
2296 if( lmCustomSize != game->lightmapSize )
2298 externalLightmaps = qtrue;
2299 Sys_Printf( "Storing all lightmaps externally\n" );
2303 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2305 lmLimitSize = atoi( argv[ i + 1 ] );
2308 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2311 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2313 lmCustomDir = argv[i + 1];
2315 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2316 externalLightmaps = qtrue;
2317 Sys_Printf( "Storing all lightmaps externally\n" );
2320 /* ydnar: add this to suppress warnings */
2321 else if( !strcmp( argv[ i ], "-custinfoparms") )
2323 Sys_Printf( "Custom info parms enabled\n" );
2324 useCustomInfoParms = qtrue;
2327 else if( !strcmp( argv[ i ], "-wolf" ) )
2329 /* -game should already be set */
2331 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2334 else if( !strcmp( argv[ i ], "-q3" ) )
2336 /* -game should already be set */
2338 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2341 else if( !strcmp( argv[ i ], "-extradist" ) )
2343 extraDist = atof( argv[ i + 1 ] );
2347 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2350 else if( !strcmp( argv[ i ], "-sunonly" ) )
2353 Sys_Printf( "Only computing sunlight\n" );
2356 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2359 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2362 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2365 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2368 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2370 lightmapSearchBlockSize = 1;
2371 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2374 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2376 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2378 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2381 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2383 lightmapSearchBlockSize = atoi(argv[i+1]);
2385 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2388 else if( !strcmp( argv[ i ], "-shade" ) )
2391 Sys_Printf( "Phong shading enabled\n" );
2394 else if( !strcmp( argv[ i ], "-bouncegrid") )
2398 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2401 else if( !strcmp( argv[ i ], "-smooth" ) )
2403 lightSamples = EXTRA_SCALE;
2404 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2407 else if( !strcmp( argv[ i ], "-fast" ) )
2412 Sys_Printf( "Fast mode enabled\n" );
2415 else if( !strcmp( argv[ i ], "-faster" ) )
2421 Sys_Printf( "Faster mode enabled\n" );
2424 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2427 Sys_Printf( "Fast grid lighting enabled\n" );
2430 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2433 Sys_Printf( "Fast bounce mode enabled\n" );
2436 else if( !strcmp( argv[ i ], "-cheap" ) )
2440 Sys_Printf( "Cheap mode enabled\n" );
2443 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2446 Sys_Printf( "Cheap grid mode enabled\n" );
2449 else if( !strcmp( argv[ i ], "-normalmap" ) )
2452 Sys_Printf( "Storing normal map instead of lightmap\n" );
2455 else if( !strcmp( argv[ i ], "-trisoup" ) )
2458 Sys_Printf( "Converting brush faces to triangle soup\n" );
2461 else if( !strcmp( argv[ i ], "-debug" ) )
2464 Sys_Printf( "Lightmap debugging enabled\n" );
2467 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2469 debugSurfaces = qtrue;
2470 Sys_Printf( "Lightmap surface debugging enabled\n" );
2473 else if( !strcmp( argv[ i ], "-debugunused" ) )
2475 debugUnused = qtrue;
2476 Sys_Printf( "Unused luxel debugging enabled\n" );
2479 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2482 Sys_Printf( "Lightmap axis debugging enabled\n" );
2485 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2487 debugCluster = qtrue;
2488 Sys_Printf( "Luxel cluster debugging enabled\n" );
2491 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2493 debugOrigin = qtrue;
2494 Sys_Printf( "Luxel origin debugging enabled\n" );
2497 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2500 debugDeluxemap = qtrue;
2501 Sys_Printf( "Deluxemap debugging enabled\n" );
2504 else if( !strcmp( argv[ i ], "-export" ) )
2506 exportLightmaps = qtrue;
2507 Sys_Printf( "Exporting lightmaps\n" );
2510 else if( !strcmp(argv[ i ], "-notrace" ))
2513 Sys_Printf( "Shadow occlusion disabled\n" );
2515 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2517 patchShadows = qtrue;
2518 Sys_Printf( "Patch shadow casting enabled\n" );
2520 else if( !strcmp( argv[ i ], "-extra" ) )
2522 superSample = EXTRA_SCALE; /* ydnar */
2523 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2525 else if( !strcmp( argv[ i ], "-extrawide" ) )
2527 superSample = EXTRAWIDE_SCALE; /* ydnar */
2528 filter = qtrue; /* ydnar */
2529 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2531 else if( !strcmp( argv[ i ], "-samplesize" ) )
2533 sampleSize = atoi( argv[ i + 1 ] );
2534 if( sampleSize < 1 )
2537 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2539 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2541 minSampleSize = atoi( argv[ i + 1 ] );
2542 if( minSampleSize < 1 )
2545 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2547 else if( !strcmp( argv[ i ], "-samplescale" ) )
2549 sampleScale = atoi( argv[ i + 1 ] );
2551 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2553 else if( !strcmp( argv[ i ], "-novertex" ) )
2555 noVertexLighting = qtrue;
2556 Sys_Printf( "Disabling vertex lighting\n" );
2558 else if( !strcmp( argv[ i ], "-nogrid" ) )
2560 noGridLighting = qtrue;
2561 Sys_Printf( "Disabling grid lighting\n" );
2563 else if( !strcmp( argv[ i ], "-border" ) )
2565 lightmapBorder = qtrue;
2566 Sys_Printf( "Adding debug border to lightmaps\n" );
2568 else if( !strcmp( argv[ i ], "-nosurf" ) )
2571 Sys_Printf( "Not tracing against surfaces\n" );
2573 else if( !strcmp( argv[ i ], "-dump" ) )
2576 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2578 else if( !strcmp( argv[ i ], "-lomem" ) )
2581 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2583 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2585 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2587 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2589 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2591 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2594 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2597 Sys_Printf( "Disabling lightstyles\n" );
2599 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2602 Sys_Printf( "Enabling lightstyles\n" );
2604 else if( !strcmp( argv[ i ], "-keeplights" ))
2607 Sys_Printf( "Leaving light entities on map after compile\n" );
2609 else if( !strcmp( argv[ i ], "-cpma" ) )
2612 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2614 else if( !strcmp( argv[ i ], "-floodlight" ) )
2616 floodlighty = qtrue;
2617 Sys_Printf( "FloodLighting enabled\n" );
2619 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2621 debugnormals = qtrue;
2622 Sys_Printf( "DebugNormals enabled\n" );
2624 else if( !strcmp( argv[ i ], "-lowquality" ) )
2626 floodlight_lowquality = qtrue;
2627 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2630 /* r7: dirtmapping */
2631 else if( !strcmp( argv[ i ], "-dirty" ) )
2634 Sys_Printf( "Dirtmapping enabled\n" );
2636 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2639 Sys_Printf( "Dirtmap debugging enabled\n" );
2641 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2643 dirtMode = atoi( argv[ i + 1 ] );
2644 if( dirtMode != 0 && dirtMode != 1 )
2647 Sys_Printf( "Enabling randomized dirtmapping\n" );
2649 Sys_Printf( "Enabling ordered dir mapping\n" );
2652 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2654 dirtDepth = atof( argv[ i + 1 ] );
2655 if( dirtDepth <= 0.0f )
2657 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2660 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2662 dirtScale = atof( argv[ i + 1 ] );
2663 if( dirtScale <= 0.0f )
2665 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2668 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2670 dirtGain = atof( argv[ i + 1 ] );
2671 if( dirtGain <= 0.0f )
2673 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2676 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2678 lightmapTriangleCheck = qtrue;
2680 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2682 lightmapExtraVisClusterNudge = qtrue;
2684 /* unhandled args */
2687 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2692 /* fix up lightmap search power */
2693 if(lightmapMergeSize)
2695 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2696 if(lightmapSearchBlockSize < 1)
2697 lightmapSearchBlockSize = 1;
2699 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2702 /* clean up map name */
2703 strcpy( source, ExpandArg( argv[ i ] ) );
2704 StripExtension( source );
2705 DefaultExtension( source, ".bsp" );
2706 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2707 StripExtension( mapSource );
2708 DefaultExtension( mapSource, ".map" );
2710 /* ydnar: set default sample size */
2711 SetDefaultSampleSize( sampleSize );
2713 /* ydnar: handle shaders */
2714 BeginMapShaderFile( source );
2718 Sys_Printf( "Loading %s\n", source );
2720 /* ydnar: load surface file */
2721 LoadSurfaceExtraFile( source );
2724 LoadBSPFile( source );
2726 /* parse bsp entities */
2729 /* inject command line parameters */
2730 InjectCommandLine(argv, 0, argc - 1);
2733 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2734 if( value[ 0 ] != '1' )
2735 LoadMapFile( mapSource, qtrue );
2737 /* set the entity/model origins and init yDrawVerts */
2740 /* ydnar: set up optimization */
2744 SetupSurfaceLightmaps();
2746 /* initialize the surface facet tracing */
2749 /* light the world */
2752 /* ydnar: store off lightmaps */
2753 StoreSurfaceLightmaps();
2755 /* write out the bsp */
2757 Sys_Printf( "Writing %s\n", source );
2758 WriteBSPFile( source );
2760 /* ydnar: export lightmaps */
2761 if( exportLightmaps && !externalLightmaps )
2764 /* return to sender */