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 = qfalse;
754 float colorBrightness;
757 light = trace->light;
760 VectorClear( trace->color );
761 VectorClear( trace->colorNoShadow );
762 VectorClear( trace->directionContribution );
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;
846 addDeluxe = light->photons / (dist * dist);
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);
941 addDeluxe = light->photons * linearScale - (dist * light->fade);
943 if( addDeluxe < 0.0f )
949 add = (light->photons / (dist * dist)) * angle;
956 addDeluxe = (light->photons / (dist * dist)) * angle;
958 addDeluxe = (light->photons / (dist * dist));
961 if( addDeluxe < 0.0f )
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);
993 if( addDeluxe < 0.0f )
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;
1040 addDeluxe = light->photons * angle;
1042 addDeluxe = light->photons;
1044 if( addDeluxe < 0.0f )
1051 /* VorteX: set noShadow color */
1052 VectorScale(light->color, add, trace->colorNoShadow);
1054 addDeluxe *= colorBrightness;
1058 addDeluxe *= addDeluxeBounceScale;
1059 if( addDeluxe < 0.00390625f )
1060 addDeluxe = 0.00390625f;
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;
1096 /* hack land: scale down the radiosity contribution to light directionality.
1097 Deluxemaps fusion many light directions into one. In a rtl process all lights
1098 would contribute individually to the bump map, so several light sources together
1099 would make it more directional (example: a yellow and red lights received from
1100 opposing sides would light one side in red and the other in blue, adding
1101 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1102 neutralize each other making it look like having no direction.
1103 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1104 is modifying the direction applied from directional lights, making it go closer and closer
1105 to the surface normal the bigger is the amount of radiosity received.
1106 So, for preserving the directional lights contributions, we scale down the radiosity
1107 contribution. It's a hack, but there's a reason behind it */
1110 addDeluxe *= addDeluxeBounceScale;
1111 if( addDeluxe < 0.00390625f )
1112 addDeluxe = 0.00390625f;
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 );
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
1429 void TraceGrid( int num )
1431 int i, j, x, y, z, mod, numCon, numStyles;
1433 vec3_t baseOrigin, cheapColor, color, thisdir;
1435 bspGridPoint_t *bgp;
1436 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1439 /* get grid points */
1440 gp = &rawGridPoints[ num ];
1441 bgp = &bspGridPoints[ num ];
1443 /* get grid origin */
1445 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1446 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1447 y = mod / gridBounds[ 0 ];
1448 mod -= y * gridBounds[ 0 ];
1451 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1452 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1453 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1455 /* set inhibit sphere */
1456 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1457 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1458 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1459 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1461 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1463 /* find point cluster */
1464 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1465 if( trace.cluster < 0 )
1467 /* try to nudge the origin around to find a valid point */
1468 VectorCopy( trace.origin, baseOrigin );
1469 for( step = 0; (step += 0.005) <= 1.0; )
1471 VectorCopy( baseOrigin, trace.origin );
1472 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1473 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1474 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1476 /* ydnar: changed to find cluster num */
1477 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1478 if( trace.cluster >= 0 )
1482 /* can't find a valid point at all */
1488 trace.testOcclusion = !noTrace;
1489 trace.forceSunlight = qfalse;
1490 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1491 trace.numSurfaces = 0;
1492 trace.surfaces = NULL;
1493 trace.numLights = 0;
1494 trace.lights = NULL;
1498 VectorClear( cheapColor );
1500 /* trace to all the lights, find the major light direction, and divide the
1501 total light between that along the direction and the remaining in the ambient */
1502 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1508 if( !LightContributionToPoint( &trace ) )
1511 /* handle negative light */
1512 if( trace.light->flags & LIGHT_NEGATIVE )
1513 VectorScale( trace.color, -1.0f, trace.color );
1515 /* add a contribution */
1516 VectorCopy( trace.color, contributions[ numCon ].color );
1517 VectorCopy( trace.direction, contributions[ numCon ].dir );
1518 VectorClear( contributions[ numCon ].ambient );
1519 contributions[ numCon ].style = trace.light->style;
1522 /* push average direction around */
1523 addSize = VectorLength( trace.color );
1524 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1526 /* stop after a while */
1527 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1530 /* ydnar: cheap mode */
1531 VectorAdd( cheapColor, trace.color, cheapColor );
1532 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1536 /////// Floodlighting for point //////////////////
1537 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1542 vec3_t dir = { 0, 0, 1 };
1543 float ambientFrac = 0.25f;
1545 trace.testOcclusion = qtrue;
1546 trace.forceSunlight = qfalse;
1547 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1548 trace.testAll = qtrue;
1550 for( k = 0; k < 2; k++ )
1552 if( k == 0 ) // upper hemisphere
1554 trace.normal[0] = 0;
1555 trace.normal[1] = 0;
1556 trace.normal[2] = 1;
1558 else //lower hemisphere
1560 trace.normal[0] = 0;
1561 trace.normal[1] = 0;
1562 trace.normal[2] = -1;
1565 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1567 /* add a fraction as pure ambient, half as top-down direction */
1568 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1569 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1570 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1572 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1573 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1574 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1576 contributions[ numCon ].dir[0] = dir[0];
1577 contributions[ numCon ].dir[1] = dir[1];
1578 contributions[ numCon ].dir[2] = dir[2];
1580 contributions[ numCon ].style = 0;
1582 /* push average direction around */
1583 addSize = VectorLength( contributions[ numCon ].color );
1584 VectorMA( gp->dir, addSize, dir, gp->dir );
1589 /////////////////////
1591 /* normalize to get primary light direction */
1592 VectorNormalize( gp->dir, thisdir );
1594 /* now that we have identified the primary light direction,
1595 go back and separate all the light into directed and ambient */
1598 for( i = 0; i < numCon; i++ )
1600 /* get relative directed strength */
1601 d = DotProduct( contributions[ i ].dir, thisdir );
1602 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1603 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1607 /* find appropriate style */
1608 for( j = 0; j < numStyles; j++ )
1610 if( gp->styles[ j ] == contributions[ i ].style )
1614 /* style not found? */
1615 if( j >= numStyles )
1617 /* add a new style */
1618 if( numStyles < MAX_LIGHTMAPS )
1620 gp->styles[ numStyles ] = contributions[ i ].style;
1621 bgp->styles[ numStyles ] = contributions[ i ].style;
1623 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1631 /* add the directed color */
1632 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1634 /* ambient light will be at 1/4 the value of directed light */
1635 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1636 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1638 /* (Hobbes: always setting it to .25 is hardly any better) */
1639 d = 0.25f * (1.0f - d);
1640 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1642 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1646 * the total light average = ambient value + 0.25 * sum of all directional values
1647 * we can also get the total light average as 0.25 * the sum of all contributions
1649 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1652 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1654 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1659 /* store off sample */
1660 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1663 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1665 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1668 /* set minimum light and copy off to bytes */
1669 VectorCopy( gp->ambient[ i ], color );
1670 for( j = 0; j < 3; j++ )
1671 if( color[ j ] < minGridLight[ j ] )
1672 color[ j ] = minGridLight[ j ];
1674 /* vortex: apply gridscale and gridambientscale here */
1675 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1676 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1681 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1682 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1684 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1685 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1688 /* store direction */
1689 NormalToLatLong( thisdir, bgp->latLong );
1696 calculates the size of the lightgrid and allocates memory
1699 void SetupGrid( void )
1702 vec3_t maxs, oldGridSize;
1707 /* don't do this if not grid lighting */
1708 if( noGridLighting )
1711 /* ydnar: set grid size */
1712 value = ValueForKey( &entities[ 0 ], "gridsize" );
1713 if( value[ 0 ] != '\0' )
1714 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1717 VectorCopy( gridSize, oldGridSize );
1718 for( i = 0; i < 3; i++ )
1719 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1721 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1722 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1724 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1726 /* get world bounds */
1727 for( i = 0; i < 3; i++ )
1729 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1730 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1731 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1735 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1737 /* increase grid size a bit */
1738 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1739 gridSize[ j++ % 3 ] += 16.0f;
1743 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1746 if( !VectorCompare( gridSize, oldGridSize ) )
1748 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1749 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1750 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1753 /* 2nd variable. fixme: is this silly? */
1754 numBSPGridPoints = numRawGridPoints;
1756 /* allocate lightgrid */
1757 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1758 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1760 if( bspGridPoints != NULL )
1761 free( bspGridPoints );
1762 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1763 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1765 /* clear lightgrid */
1766 for( i = 0; i < numRawGridPoints; i++ )
1768 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1769 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1770 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1771 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1773 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1774 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1779 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1786 does what it says...
1789 void LightWorld( void )
1794 qboolean minVertex, minGrid, ps;
1798 /* ydnar: smooth normals */
1801 Sys_Printf( "--- SmoothNormals ---\n" );
1805 /* determine the number of grid points */
1806 Sys_Printf( "--- SetupGrid ---\n" );
1809 /* find the optional minimum lighting values */
1810 GetVectorForKey( &entities[ 0 ], "_color", color );
1811 if( VectorLength( color ) == 0.0f )
1812 VectorSet( color, 1.0, 1.0, 1.0 );
1815 f = FloatForKey( &entities[ 0 ], "_ambient" );
1817 f = FloatForKey( &entities[ 0 ], "ambient" );
1818 VectorScale( color, f, ambientColor );
1820 /* minvertexlight */
1822 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1823 if( value[ 0 ] != '\0' )
1827 VectorScale( color, f, minVertexLight );
1832 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1833 if( value[ 0 ] != '\0' )
1837 VectorScale( color, f, minGridLight );
1841 value = ValueForKey( &entities[ 0 ], "_minlight" );
1842 if( value[ 0 ] != '\0' )
1845 VectorScale( color, f, minLight );
1846 if( minVertex == qfalse )
1847 VectorScale( color, f, minVertexLight );
1848 if( minGrid == qfalse )
1849 VectorScale( color, f, minGridLight );
1852 /* create world lights */
1853 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1854 CreateEntityLights();
1855 CreateSurfaceLights();
1856 Sys_Printf( "%9d point lights\n", numPointLights );
1857 Sys_Printf( "%9d spotlights\n", numSpotLights );
1858 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1859 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1861 /* calculate lightgrid */
1862 if( !noGridLighting )
1864 /* ydnar: set up light envelopes */
1865 SetupEnvelopes( qtrue, fastgrid );
1867 Sys_Printf( "--- TraceGrid ---\n" );
1869 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1871 Sys_Printf( "%d x %d x %d = %d grid\n",
1872 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1874 /* ydnar: emit statistics on light culling */
1875 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1876 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1879 /* slight optimization to remove a sqrt */
1880 subdivideThreshold *= subdivideThreshold;
1882 /* map the world luxels */
1883 Sys_Printf( "--- MapRawLightmap ---\n" );
1884 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1885 Sys_Printf( "%9d luxels\n", numLuxels );
1886 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1887 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1892 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1893 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1896 /* floodlight pass */
1897 FloodlightRawLightmaps();
1899 /* ydnar: set up light envelopes */
1900 SetupEnvelopes( qfalse, fast );
1902 /* light up my world */
1903 lightsPlaneCulled = 0;
1904 lightsEnvelopeCulled = 0;
1905 lightsBoundsCulled = 0;
1906 lightsClusterCulled = 0;
1908 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1909 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1910 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1912 StitchSurfaceLightmaps();
1914 Sys_Printf( "--- IlluminateVertexes ---\n" );
1915 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1916 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1918 /* ydnar: emit statistics on light culling */
1919 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1920 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1921 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1922 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1929 /* store off the bsp between bounces */
1930 StoreSurfaceLightmaps();
1932 Sys_Printf( "Writing %s\n", source );
1933 WriteBSPFile( source );
1936 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1940 VectorClear( ambientColor );
1941 floodlighty = qfalse;
1943 /* generate diffuse lights */
1945 RadCreateDiffuseLights();
1947 /* setup light envelopes */
1948 SetupEnvelopes( qfalse, fastbounce );
1949 if( numLights == 0 )
1951 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1955 /* add to lightgrid */
1958 gridEnvelopeCulled = 0;
1959 gridBoundsCulled = 0;
1961 Sys_Printf( "--- BounceGrid ---\n" );
1963 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1965 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1966 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1969 /* light up my world */
1970 lightsPlaneCulled = 0;
1971 lightsEnvelopeCulled = 0;
1972 lightsBoundsCulled = 0;
1973 lightsClusterCulled = 0;
1975 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1976 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1977 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1978 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1980 StitchSurfaceLightmaps();
1982 Sys_Printf( "--- IlluminateVertexes ---\n" );
1983 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1984 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1986 /* ydnar: emit statistics on light culling */
1987 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1988 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1989 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1990 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2002 main routine for light processing
2005 int LightMain( int argc, char **argv )
2009 char mapSource[ 1024 ];
2011 int lightmapMergeSize = 0;
2015 Sys_Printf( "--- Light ---\n" );
2016 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2018 /* set standard game flags */
2019 wolfLight = game->wolfLight;
2020 if (wolfLight == qtrue)
2021 Sys_Printf( " lightning model: wolf\n" );
2023 Sys_Printf( " lightning model: quake3\n" );
2025 lmCustomSize = game->lightmapSize;
2026 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2028 lightmapGamma = game->lightmapGamma;
2029 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2031 lightmapCompensate = game->lightmapCompensate;
2032 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2034 lightmapExposure = game->lightmapExposure;
2035 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2037 gridScale = game->gridScale;
2038 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2040 gridAmbientScale = game->gridAmbientScale;
2041 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2043 lightAngleHL = game->lightAngleHL;
2045 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2047 noStyles = game->noStyles;
2048 if (noStyles == qtrue)
2049 Sys_Printf( " shader lightstyles hack: disabled\n" );
2051 Sys_Printf( " shader lightstyles hack: enabled\n" );
2053 keepLights = game->keepLights;
2054 if (keepLights == qtrue)
2055 Sys_Printf( " keep lights: enabled\n" );
2057 Sys_Printf( " keep lights: disabled\n" );
2059 patchShadows = game->patchShadows;
2060 if (patchShadows == qtrue)
2061 Sys_Printf( " patch shadows: enabled\n" );
2063 Sys_Printf( " patch shadows: disabled\n" );
2065 deluxemap = game->deluxeMap;
2066 deluxemode = game->deluxeMode;
2067 if (deluxemap == qtrue)
2070 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2072 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2075 Sys_Printf( " deluxemapping: disabled\n" );
2077 Sys_Printf( "--- ProcessCommandLine ---\n" );
2079 /* process commandline arguments */
2080 for( i = 1; i < (argc - 1); i++ )
2082 /* lightsource scaling */
2083 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2085 f = atof( argv[ i + 1 ] );
2087 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
2091 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2093 f = atof( argv[ i + 1 ] );
2095 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2099 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2101 f = atof( argv[ i + 1 ] );
2103 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2107 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2109 f = atof( argv[ i + 1 ] );
2111 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2115 else if( !strcmp( argv[ i ], "-scale" ) )
2117 f = atof( argv[ i + 1 ] );
2122 Sys_Printf( "All light scaled by %f\n", f );
2126 else if( !strcmp( argv[ i ], "-gridscale" ) )
2128 f = atof( argv[ i + 1 ] );
2129 Sys_Printf( "Grid lightning scaled by %f\n", f );
2134 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2136 f = atof( argv[ i + 1 ] );
2137 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2138 gridAmbientScale *= f;
2142 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2144 f = atof( argv[ i + 1 ] );
2146 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2147 Sys_Printf( "Grid directionality is %f\n", f );
2148 gridDirectionality *= f;
2152 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2154 f = atof( argv[ i + 1 ] );
2155 if(f > gridDirectionality) f = gridDirectionality;
2157 Sys_Printf( "Grid ambient directionality is %f\n", f );
2158 gridAmbientDirectionality *= f;
2162 else if( !strcmp( argv[ i ], "-gamma" ) )
2164 f = atof( argv[ i + 1 ] );
2166 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2170 else if( !strcmp( argv[ i ], "-exposure" ) )
2172 f = atof( argv[ i + 1 ] );
2173 lightmapExposure = f;
2174 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2178 else if( !strcmp( argv[ i ], "-compensate" ) )
2180 f = atof( argv[ i + 1 ] );
2183 lightmapCompensate = f;
2184 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2188 /* ydnar switches */
2189 else if( !strcmp( argv[ i ], "-bounce" ) )
2191 bounce = atoi( argv[ i + 1 ] );
2194 else if( bounce > 0 )
2195 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2199 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2201 superSample = atoi( argv[ i + 1 ] );
2202 if( superSample < 1 )
2204 else if( superSample > 1 )
2205 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2209 else if( !strcmp( argv[ i ], "-samples" ) )
2211 lightSamples = atoi( argv[ i + 1 ] );
2212 if( lightSamples < 1 )
2214 else if( lightSamples > 1 )
2215 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2219 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2221 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2222 if( lightSamplesSearchBoxSize <= 0 )
2223 lightSamplesSearchBoxSize = 1;
2224 if( lightSamplesSearchBoxSize > 4 )
2225 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2226 else if( lightSamplesSearchBoxSize != 1 )
2227 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2231 else if( !strcmp( argv[ i ], "-filter" ) )
2234 Sys_Printf( "Lightmap filtering enabled\n" );
2237 else if( !strcmp( argv[ i ], "-dark" ) )
2240 Sys_Printf( "Dark lightmap seams enabled\n" );
2243 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2245 shadeAngleDegrees = atof( argv[ i + 1 ] );
2246 if( shadeAngleDegrees < 0.0f )
2247 shadeAngleDegrees = 0.0f;
2248 else if( shadeAngleDegrees > 0.0f )
2251 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2256 else if( !strcmp( argv[ i ], "-thresh" ) )
2258 subdivideThreshold = atof( argv[ i + 1 ] );
2259 if( subdivideThreshold < 0 )
2260 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2262 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2266 else if( !strcmp( argv[ i ], "-approx" ) )
2268 approximateTolerance = atoi( argv[ i + 1 ] );
2269 if( approximateTolerance < 0 )
2270 approximateTolerance = 0;
2271 else if( approximateTolerance > 0 )
2272 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2275 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2278 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2280 else if( !strcmp( argv[ i ], "-deluxemode" ))
2282 deluxemode = atoi( argv[ i + 1 ] );
2283 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2285 Sys_Printf( "Generating modelspace deluxemaps\n" );
2289 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2292 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2295 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2297 else if( !strcmp( argv[ i ], "-external" ) )
2299 externalLightmaps = qtrue;
2300 Sys_Printf( "Storing all lightmaps externally\n" );
2303 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2305 lmCustomSize = atoi( argv[ i + 1 ] );
2307 /* must be a power of 2 and greater than 2 */
2308 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2310 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2311 lmCustomSize = game->lightmapSize;
2314 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2316 /* enable external lightmaps */
2317 if( lmCustomSize != game->lightmapSize )
2319 externalLightmaps = qtrue;
2320 Sys_Printf( "Storing all lightmaps externally\n" );
2324 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2326 lmLimitSize = atoi( argv[ i + 1 ] );
2329 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2332 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2334 lmCustomDir = argv[i + 1];
2336 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2337 externalLightmaps = qtrue;
2338 Sys_Printf( "Storing all lightmaps externally\n" );
2341 /* ydnar: add this to suppress warnings */
2342 else if( !strcmp( argv[ i ], "-custinfoparms") )
2344 Sys_Printf( "Custom info parms enabled\n" );
2345 useCustomInfoParms = qtrue;
2348 else if( !strcmp( argv[ i ], "-wolf" ) )
2350 /* -game should already be set */
2352 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2355 else if( !strcmp( argv[ i ], "-q3" ) )
2357 /* -game should already be set */
2359 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2362 else if( !strcmp( argv[ i ], "-extradist" ) )
2364 extraDist = atof( argv[ i + 1 ] );
2368 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2371 else if( !strcmp( argv[ i ], "-sunonly" ) )
2374 Sys_Printf( "Only computing sunlight\n" );
2377 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2380 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2383 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2386 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2389 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2391 lightmapSearchBlockSize = 1;
2392 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2395 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2397 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2399 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2402 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2404 lightmapSearchBlockSize = atoi(argv[i+1]);
2406 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2409 else if( !strcmp( argv[ i ], "-shade" ) )
2412 Sys_Printf( "Phong shading enabled\n" );
2415 else if( !strcmp( argv[ i ], "-bouncegrid") )
2419 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2422 else if( !strcmp( argv[ i ], "-smooth" ) )
2424 lightSamples = EXTRA_SCALE;
2425 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2428 else if( !strcmp( argv[ i ], "-fast" ) )
2433 Sys_Printf( "Fast mode enabled\n" );
2436 else if( !strcmp( argv[ i ], "-faster" ) )
2442 Sys_Printf( "Faster mode enabled\n" );
2445 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2448 Sys_Printf( "Fast grid lighting enabled\n" );
2451 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2454 Sys_Printf( "Fast bounce mode enabled\n" );
2457 else if( !strcmp( argv[ i ], "-cheap" ) )
2461 Sys_Printf( "Cheap mode enabled\n" );
2464 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2467 Sys_Printf( "Cheap grid mode enabled\n" );
2470 else if( !strcmp( argv[ i ], "-normalmap" ) )
2473 Sys_Printf( "Storing normal map instead of lightmap\n" );
2476 else if( !strcmp( argv[ i ], "-trisoup" ) )
2479 Sys_Printf( "Converting brush faces to triangle soup\n" );
2482 else if( !strcmp( argv[ i ], "-debug" ) )
2485 Sys_Printf( "Lightmap debugging enabled\n" );
2488 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2490 debugSurfaces = qtrue;
2491 Sys_Printf( "Lightmap surface debugging enabled\n" );
2494 else if( !strcmp( argv[ i ], "-debugunused" ) )
2496 debugUnused = qtrue;
2497 Sys_Printf( "Unused luxel debugging enabled\n" );
2500 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2503 Sys_Printf( "Lightmap axis debugging enabled\n" );
2506 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2508 debugCluster = qtrue;
2509 Sys_Printf( "Luxel cluster debugging enabled\n" );
2512 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2514 debugOrigin = qtrue;
2515 Sys_Printf( "Luxel origin debugging enabled\n" );
2518 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2521 debugDeluxemap = qtrue;
2522 Sys_Printf( "Deluxemap debugging enabled\n" );
2525 else if( !strcmp( argv[ i ], "-export" ) )
2527 exportLightmaps = qtrue;
2528 Sys_Printf( "Exporting lightmaps\n" );
2531 else if( !strcmp(argv[ i ], "-notrace" ))
2534 Sys_Printf( "Shadow occlusion disabled\n" );
2536 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2538 patchShadows = qtrue;
2539 Sys_Printf( "Patch shadow casting enabled\n" );
2541 else if( !strcmp( argv[ i ], "-extra" ) )
2543 superSample = EXTRA_SCALE; /* ydnar */
2544 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2546 else if( !strcmp( argv[ i ], "-extrawide" ) )
2548 superSample = EXTRAWIDE_SCALE; /* ydnar */
2549 filter = qtrue; /* ydnar */
2550 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2552 else if( !strcmp( argv[ i ], "-samplesize" ) )
2554 sampleSize = atoi( argv[ i + 1 ] );
2555 if( sampleSize < 1 )
2558 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2560 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2562 minSampleSize = atoi( argv[ i + 1 ] );
2563 if( minSampleSize < 1 )
2566 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2568 else if( !strcmp( argv[ i ], "-samplescale" ) )
2570 sampleScale = atoi( argv[ i + 1 ] );
2572 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2574 else if( !strcmp( argv[ i ], "-novertex" ) )
2576 noVertexLighting = qtrue;
2577 Sys_Printf( "Disabling vertex lighting\n" );
2579 else if( !strcmp( argv[ i ], "-nogrid" ) )
2581 noGridLighting = qtrue;
2582 Sys_Printf( "Disabling grid lighting\n" );
2584 else if( !strcmp( argv[ i ], "-border" ) )
2586 lightmapBorder = qtrue;
2587 Sys_Printf( "Adding debug border to lightmaps\n" );
2589 else if( !strcmp( argv[ i ], "-nosurf" ) )
2592 Sys_Printf( "Not tracing against surfaces\n" );
2594 else if( !strcmp( argv[ i ], "-dump" ) )
2597 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2599 else if( !strcmp( argv[ i ], "-lomem" ) )
2602 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2604 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2606 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2608 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2610 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2612 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2615 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2618 Sys_Printf( "Disabling lightstyles\n" );
2620 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2623 Sys_Printf( "Enabling lightstyles\n" );
2625 else if( !strcmp( argv[ i ], "-keeplights" ))
2628 Sys_Printf( "Leaving light entities on map after compile\n" );
2630 else if( !strcmp( argv[ i ], "-cpma" ) )
2633 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2635 else if( !strcmp( argv[ i ], "-floodlight" ) )
2637 floodlighty = qtrue;
2638 Sys_Printf( "FloodLighting enabled\n" );
2640 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2642 debugnormals = qtrue;
2643 Sys_Printf( "DebugNormals enabled\n" );
2645 else if( !strcmp( argv[ i ], "-lowquality" ) )
2647 floodlight_lowquality = qtrue;
2648 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2651 /* r7: dirtmapping */
2652 else if( !strcmp( argv[ i ], "-dirty" ) )
2655 Sys_Printf( "Dirtmapping enabled\n" );
2657 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2660 Sys_Printf( "Dirtmap debugging enabled\n" );
2662 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2664 dirtMode = atoi( argv[ i + 1 ] );
2665 if( dirtMode != 0 && dirtMode != 1 )
2668 Sys_Printf( "Enabling randomized dirtmapping\n" );
2670 Sys_Printf( "Enabling ordered dir mapping\n" );
2673 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2675 dirtDepth = atof( argv[ i + 1 ] );
2676 if( dirtDepth <= 0.0f )
2678 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2681 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2683 dirtScale = atof( argv[ i + 1 ] );
2684 if( dirtScale <= 0.0f )
2686 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2689 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2691 dirtGain = atof( argv[ i + 1 ] );
2692 if( dirtGain <= 0.0f )
2694 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2697 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2699 lightmapTriangleCheck = qtrue;
2701 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2703 lightmapExtraVisClusterNudge = qtrue;
2705 /* unhandled args */
2708 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2713 /* fix up lightmap search power */
2714 if(lightmapMergeSize)
2716 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2717 if(lightmapSearchBlockSize < 1)
2718 lightmapSearchBlockSize = 1;
2720 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2723 /* clean up map name */
2724 strcpy( source, ExpandArg( argv[ i ] ) );
2725 StripExtension( source );
2726 DefaultExtension( source, ".bsp" );
2727 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2728 StripExtension( mapSource );
2729 DefaultExtension( mapSource, ".map" );
2731 /* ydnar: set default sample size */
2732 SetDefaultSampleSize( sampleSize );
2734 /* ydnar: handle shaders */
2735 BeginMapShaderFile( source );
2739 Sys_Printf( "Loading %s\n", source );
2741 /* ydnar: load surface file */
2742 LoadSurfaceExtraFile( source );
2745 LoadBSPFile( source );
2747 /* parse bsp entities */
2750 /* inject command line parameters */
2751 InjectCommandLine(argv, 0, argc - 1);
2754 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2755 if( value[ 0 ] != '1' )
2756 LoadMapFile( mapSource, qtrue );
2758 /* set the entity/model origins and init yDrawVerts */
2761 /* ydnar: set up optimization */
2765 SetupSurfaceLightmaps();
2767 /* initialize the surface facet tracing */
2770 /* light the world */
2773 /* ydnar: store off lightmaps */
2774 StoreSurfaceLightmaps();
2776 /* write out the bsp */
2778 Sys_Printf( "Writing %s\n", source );
2779 WriteBSPFile( source );
2781 /* ydnar: export lightmaps */
2782 if( exportLightmaps && !externalLightmaps )
2785 /* return to sender */