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;
155 if( value <= 0.0f || iterations < 2 )
158 /* basic sun setup */
159 VectorCopy( color, sun.color );
161 sun.filterRadius = filterRadius;
163 sun.style = noStyles ? LS_NORMAL : style;
167 elevationSteps = iterations - 1;
168 angleSteps = elevationSteps * 4;
170 elevationStep = DEG2RAD( 90.0f / iterations ); /* skip elevation 0 */
171 angleStep = DEG2RAD( 360.0f / angleSteps );
173 /* calc individual sun brightness */
174 numSuns = angleSteps * elevationSteps + 1;
175 sun.photons = value / numSuns;
177 /* iterate elevation */
178 elevation = elevationStep * 0.5f;
180 for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
183 for( j = 0; j < angleSteps; j++ )
186 sun.direction[ 0 ] = cos( angle ) * cos( elevation );
187 sun.direction[ 1 ] = sin( angle ) * cos( elevation );
188 sun.direction[ 2 ] = sin( elevation );
189 CreateSunLight( &sun );
196 elevation += elevationStep;
197 angle += angleStep / elevationSteps;
200 /* create vertical sun */
201 VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
202 CreateSunLight( &sun );
212 creates lights from light entities
215 void CreateEntityLights( void )
218 light_t *light, *light2;
224 float intensity, scale, deviance, filterRadius;
225 int spawnflags, flags, numSamples;
229 /* go throught entity list and find lights */
230 for( i = 0; i < numEntities; i++ )
234 name = ValueForKey( e, "classname" );
236 /* ydnar: check for lightJunior */
237 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
239 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
244 /* lights with target names (and therefore styles) are only parsed from BSP */
245 target = ValueForKey( e, "targetname" );
246 if( target[ 0 ] != '\0' && i >= numBSPEntities )
251 light = safe_malloc( sizeof( *light ) );
252 memset( light, 0, sizeof( *light ) );
253 light->next = lights;
256 /* handle spawnflags */
257 spawnflags = IntForKey( e, "spawnflags" );
259 /* ydnar: quake 3+ light behavior */
260 if( wolfLight == qfalse )
262 /* set default flags */
263 flags = LIGHT_Q3A_DEFAULT;
265 /* linear attenuation? */
268 flags |= LIGHT_ATTEN_LINEAR;
269 flags &= ~LIGHT_ATTEN_ANGLE;
272 /* no angle attenuate? */
274 flags &= ~LIGHT_ATTEN_ANGLE;
277 /* ydnar: wolf light behavior */
280 /* set default flags */
281 flags = LIGHT_WOLF_DEFAULT;
283 /* inverse distance squared attenuation? */
286 flags &= ~LIGHT_ATTEN_LINEAR;
287 flags |= LIGHT_ATTEN_ANGLE;
290 /* angle attenuate? */
292 flags |= LIGHT_ATTEN_ANGLE;
295 /* other flags (borrowed from wolf) */
297 /* wolf dark light? */
298 if( (spawnflags & 4) || (spawnflags & 8) )
302 if( spawnflags & 16 )
303 flags &= ~LIGHT_GRID;
309 flags &= ~LIGHT_SURFACES;
312 /* vortex: unnormalized? */
314 flags |= LIGHT_UNNORMALIZED;
316 /* vortex: distance atten? */
318 flags |= LIGHT_ATTEN_DISTANCE;
320 /* store the flags */
321 light->flags = flags;
323 /* ydnar: set fade key (from wolf) */
325 if( light->flags & LIGHT_ATTEN_LINEAR )
327 light->fade = FloatForKey( e, "fade" );
328 if( light->fade == 0.0f )
332 /* ydnar: set angle scaling (from vlight) */
333 light->angleScale = FloatForKey( e, "_anglescale" );
334 if( light->angleScale != 0.0f )
335 light->flags |= LIGHT_ATTEN_ANGLE;
338 GetVectorForKey( e, "origin", light->origin);
339 light->style = IntForKey( e, "_style" );
340 if( light->style == LS_NORMAL )
341 light->style = IntForKey( e, "style" );
342 if( light->style < LS_NORMAL || light->style >= LS_NONE )
343 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
345 if( light->style != LS_NORMAL ) {
346 Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
349 /* set light intensity */
350 intensity = FloatForKey( e, "_light" );
351 if( intensity == 0.0f )
352 intensity = FloatForKey( e, "light" );
353 if( intensity == 0.0f)
356 /* ydnar: set light scale (sof2) */
357 scale = FloatForKey( e, "scale" );
362 /* ydnar: get deviance and samples */
363 deviance = FloatForKey( e, "_deviance" );
364 if( deviance == 0.0f )
365 deviance = FloatForKey( e, "_deviation" );
366 if( deviance == 0.0f )
367 deviance = FloatForKey( e, "_jitter" );
368 numSamples = IntForKey( e, "_samples" );
369 if( deviance < 0.0f || numSamples < 1 )
374 intensity /= numSamples;
376 /* ydnar: get filter radius */
377 filterRadius = FloatForKey( e, "_filterradius" );
378 if( filterRadius == 0.0f )
379 filterRadius = FloatForKey( e, "_filteradius" );
380 if( filterRadius == 0.0f )
381 filterRadius = FloatForKey( e, "_filter" );
382 if( filterRadius < 0.0f )
384 light->filterRadius = filterRadius;
386 /* set light color */
387 _color = ValueForKey( e, "_color" );
388 if( _color && _color[ 0 ] )
390 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
393 light->color[0] = Image_LinearFloatFromsRGBFloat(light->color[0]);
394 light->color[1] = Image_LinearFloatFromsRGBFloat(light->color[1]);
395 light->color[2] = Image_LinearFloatFromsRGBFloat(light->color[2]);
397 if (!(light->flags & LIGHT_UNNORMALIZED))
399 ColorNormalize( light->color, light->color );
403 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
405 light->extraDist = FloatForKey( e, "_extradist" );
406 if(light->extraDist == 0.0f)
407 light->extraDist = extraDist;
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 ] );
432 light->photons *= pointScale;
436 /* not a point light */
440 /* make a spotlight */
441 GetVectorForKey( e2, "origin", dest );
442 VectorSubtract( dest, light->origin, light->normal );
443 dist = VectorNormalize( light->normal, light->normal );
444 radius = FloatForKey( e, "radius" );
449 light->radiusByDist = (radius + 16) / dist;
450 light->type = EMIT_SPOT;
452 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
453 light->flags &= ~LIGHT_ATTEN_LINEAR;
454 light->flags |= LIGHT_ATTEN_ANGLE;
457 /* ydnar: is this a sun? */
458 _sun = ValueForKey( e, "_sun" );
459 if( _sun[ 0 ] == '1' )
461 /* not a spot light */
464 /* unlink this light */
465 lights = light->next;
468 VectorScale( light->normal, -1.0f, sun.direction );
469 VectorCopy( light->color, sun.color );
470 sun.photons = intensity;
471 sun.deviance = deviance / 180.0f * Q_PI;
472 sun.numSamples = numSamples;
473 sun.style = noStyles ? LS_NORMAL : light->style;
476 /* make a sun light */
477 CreateSunLight( &sun );
479 /* free original light */
483 /* skip the rest of this love story */
488 light->photons *= spotScale;
493 light->photons *= pointScale;
495 /* jitter the light */
496 for( j = 1; j < numSamples; j++ )
499 light2 = safe_malloc( sizeof( *light ) );
500 memcpy( light2, light, sizeof( *light ) );
501 light2->next = lights;
505 if( light->type == EMIT_SPOT )
511 light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
512 light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
513 light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
521 CreateSurfaceLights() - ydnar
522 this hijacks the radiosity code to generate surface lights for first pass
525 #define APPROX_BOUNCE 1.0f
527 void CreateSurfaceLights( void )
530 bspDrawSurface_t *ds;
540 /* get sun shader supressor */
541 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
543 /* walk the list of surfaces */
544 for( i = 0; i < numBSPDrawSurfaces; i++ )
546 /* get surface and other bits */
547 ds = &bspDrawSurfaces[ i ];
548 info = &surfaceInfos[ i ];
552 if( si->sun != NULL && nss[ 0 ] != '1' )
554 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
555 CreateSunLight( si->sun );
556 si->sun = NULL; /* FIXME: leak! */
560 if( si->skyLightValue > 0.0f )
562 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
563 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
564 si->skyLightValue = 0.0f; /* FIXME: hack! */
567 /* try to early out */
571 /* autosprite shaders become point lights */
574 /* create an average xyz */
575 VectorAdd( info->mins, info->maxs, origin );
576 VectorScale( origin, 0.5f, origin );
579 light = safe_malloc( sizeof( *light ) );
580 memset( light, 0, sizeof( *light ) );
581 light->next = lights;
585 light->flags = LIGHT_Q3A_DEFAULT;
586 light->type = EMIT_POINT;
587 light->photons = si->value * pointScale;
590 VectorCopy( origin, light->origin );
591 VectorCopy( si->color, light->color );
592 light->falloffTolerance = falloffTolerance;
593 light->style = si->lightStyle;
595 /* add to point light count and continue */
600 /* get subdivision amount */
601 if( si->lightSubdivide > 0 )
602 subdivide = si->lightSubdivide;
604 subdivide = defaultLightSubdivide;
607 switch( ds->surfaceType )
610 case MST_TRIANGLE_SOUP:
611 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
615 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
628 find the offset values for inline models
631 void SetEntityOrigins( void )
639 bspDrawSurface_t *ds;
642 /* ydnar: copy drawverts into private storage for nefarious purposes */
643 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
644 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
646 /* set the entity origins */
647 for( i = 0; i < numEntities; i++ )
649 /* get entity and model */
651 key = ValueForKey( e, "model" );
652 if( key[ 0 ] != '*' )
654 modelnum = atoi( key + 1 );
655 dm = &bspModels[ modelnum ];
657 /* get entity origin */
658 key = ValueForKey( e, "origin" );
659 if( key[ 0 ] == '\0' )
661 GetVectorForKey( e, "origin", origin );
663 /* set origin for all surfaces for this model */
664 for( j = 0; j < dm->numBSPSurfaces; j++ )
667 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
670 for( k = 0; k < ds->numVerts; k++ )
672 f = ds->firstVert + k;
673 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
682 PointToPolygonFormFactor()
683 calculates the area over a point/normal hemisphere a winding covers
684 ydnar: fixme: there has to be a faster way to calculate this
685 without the expensive per-vert sqrts and transcendental functions
686 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
687 between this and the approximation
690 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
692 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
694 vec3_t triVector, triNormal;
696 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
698 float dot, angle, facing;
701 /* this is expensive */
702 for( i = 0; i < w->numpoints; i++ )
704 VectorSubtract( w->p[ i ], point, dirs[ i ] );
705 VectorNormalize( dirs[ i ], dirs[ i ] );
708 /* duplicate first vertex to avoid mod operation */
709 VectorCopy( dirs[ 0 ], dirs[ i ] );
711 /* calculcate relative area */
713 for( i = 0; i < w->numpoints; i++ )
717 dot = DotProduct( dirs[ i ], dirs[ j ] );
719 /* roundoff can cause slight creep, which gives an IND from acos */
722 else if( dot < -1.0f )
728 CrossProduct( dirs[ i ], dirs[ j ], triVector );
729 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
732 facing = DotProduct( normal, triNormal );
733 total += facing * angle;
735 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
736 if( total > 6.3f || total < -6.3f )
740 /* now in the range of 0 to 1 over the entire incoming hemisphere */
741 //% total /= (2.0f * 3.141592657f);
742 total *= ONE_OVER_2PI;
749 LightContributionTosample()
750 determines the amount of light reaching a sample (luxel or vertex) from a given light
753 int LightContributionToSample( trace_t *trace )
759 float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
760 qboolean angledDeluxe = qtrue;
761 float colorBrightness;
762 qboolean doAddDeluxe = qtrue;
765 light = trace->light;
768 trace->forceSubsampling = 0.0f; /* to make sure */
769 VectorClear( trace->color );
770 VectorClear( trace->colorNoShadow );
771 VectorClear( trace->directionContribution );
773 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
775 /* ydnar: early out */
776 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
779 /* do some culling checks */
780 if( light->type != EMIT_SUN )
782 /* MrE: if the light is behind the surface */
783 if( trace->twoSided == qfalse )
784 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
787 /* ydnar: test pvs */
788 if( !ClusterVisible( trace->cluster, light->cluster ) )
792 /* exact point to polygon form factor */
793 if( light->type == EMIT_AREA )
799 /* project sample point into light plane */
800 d = DotProduct( trace->origin, light->normal ) - light->dist;
803 /* sample point behind plane? */
804 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
807 /* sample plane coincident? */
808 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
812 /* nudge the point so that it is clearly forward of the light */
813 /* so that surfaces meeting a light emitter don't get black edges */
814 if( d > -8.0f && d < 8.0f )
815 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
817 VectorCopy( trace->origin, pushedOrigin );
819 /* get direction and distance */
820 VectorCopy( light->origin, trace->end );
821 dist = SetupTrace( trace );
822 if( dist >= light->envelope )
825 /* ptpff approximation */
828 /* angle attenuation */
829 angle = DotProduct( trace->normal, trace->direction );
831 /* twosided lighting */
832 if( trace->twoSided && angle < 0 )
836 /* no deluxemap contribution from "other side" light */
837 doAddDeluxe = qfalse;
841 angle *= -DotProduct( light->normal, trace->direction );
844 else if( angle < 0.0f &&
845 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
849 /* no deluxemap contribution from "other side" light */
850 doAddDeluxe = qfalse;
853 /* clamp the distance to prevent super hot spots */
854 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
858 add = light->photons / (dist * dist) * angle;
863 addDeluxe = light->photons / (dist * dist) * angle;
865 addDeluxe = light->photons / (dist * dist);
870 /* calculate the contribution */
871 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
874 else if( factor < 0.0f )
876 /* twosided lighting */
877 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
881 /* push light origin to other side of the plane */
882 VectorMA( light->origin, -2.0f, light->normal, trace->end );
883 dist = SetupTrace( trace );
884 if( dist >= light->envelope )
887 /* no deluxemap contribution from "other side" light */
888 doAddDeluxe = qfalse;
894 /* also don't deluxe if the direction is on the wrong side */
895 if(DotProduct(trace->normal, trace->direction) < 0)
897 /* no deluxemap contribution from "other side" light */
898 doAddDeluxe = qfalse;
901 /* ydnar: moved to here */
902 add = factor * light->add;
909 /* point/spot lights */
910 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
912 /* get direction and distance */
913 VectorCopy( light->origin, trace->end );
914 dist = SetupTrace( trace );
915 if( dist >= light->envelope )
918 /* clamp the distance to prevent super hot spots */
919 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
923 /* angle attenuation */
924 if( light->flags & LIGHT_ATTEN_ANGLE )
926 /* standard Lambert attenuation */
927 float dot = DotProduct( trace->normal, trace->direction );
929 /* twosided lighting */
930 if( trace->twoSided && dot < 0 )
934 /* no deluxemap contribution from "other side" light */
935 doAddDeluxe = qfalse;
938 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
941 if( dot > 0.001f ) // skip coplanar
943 if( dot > 1.0f ) dot = 1.0f;
944 dot = ( dot * 0.5f ) + 0.5f;
956 if( light->angleScale != 0.0f )
958 angle /= light->angleScale;
964 if( light->flags & LIGHT_ATTEN_LINEAR )
966 add = angle * light->photons * linearScale - (dist * light->fade);
973 addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
975 addDeluxe = light->photons * linearScale - (dist * light->fade);
977 if( addDeluxe < 0.0f )
983 add = (light->photons / (dist * dist)) * angle;
990 addDeluxe = (light->photons / (dist * dist)) * angle;
992 addDeluxe = (light->photons / (dist * dist));
995 if( addDeluxe < 0.0f )
999 /* handle spotlights */
1000 if( light->type == EMIT_SPOT )
1002 float distByNormal, radiusAtDist, sampleRadius;
1003 vec3_t pointAtDist, distToSample;
1005 /* do cone calculation */
1006 distByNormal = -DotProduct( trace->displacement, light->normal );
1007 if( distByNormal < 0.0f )
1009 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1010 radiusAtDist = light->radiusByDist * distByNormal;
1011 VectorSubtract( trace->origin, pointAtDist, distToSample );
1012 sampleRadius = VectorLength( distToSample );
1014 /* outside the cone */
1015 if( sampleRadius >= radiusAtDist )
1019 if( sampleRadius > (radiusAtDist - 32.0f) )
1021 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1025 addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
1027 if( addDeluxe < 0.0f )
1033 /* ydnar: sunlight */
1034 else if( light->type == EMIT_SUN )
1036 /* get origin and direction */
1037 VectorAdd( trace->origin, light->origin, trace->end );
1038 dist = SetupTrace( trace );
1040 /* angle attenuation */
1041 if( light->flags & LIGHT_ATTEN_ANGLE )
1043 /* standard Lambert attenuation */
1044 float dot = DotProduct( trace->normal, trace->direction );
1046 /* twosided lighting */
1047 if( trace->twoSided && dot < 0 )
1051 /* no deluxemap contribution from "other side" light */
1052 doAddDeluxe = qfalse;
1055 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1058 if( dot > 0.001f ) // skip coplanar
1060 if( dot > 1.0f ) dot = 1.0f;
1061 dot = ( dot * 0.5f ) + 0.5f;
1074 add = light->photons * angle;
1079 addDeluxe = light->photons * angle;
1081 addDeluxe = light->photons;
1083 if( addDeluxe < 0.0f )
1090 /* VorteX: set noShadow color */
1091 VectorScale(light->color, add, trace->colorNoShadow);
1093 addDeluxe *= colorBrightness;
1097 addDeluxe *= addDeluxeBounceScale;
1098 if( addDeluxe < 0.00390625f )
1099 addDeluxe = 0.00390625f;
1102 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1105 trace->testAll = qtrue;
1106 VectorScale( light->color, add, trace->color );
1108 /* trace to point */
1109 if( trace->testOcclusion && !trace->forceSunlight )
1113 trace->forceSubsampling *= add;
1114 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1116 VectorClear( trace->color );
1117 VectorClear( trace->directionContribution );
1123 /* return to sender */
1127 Error("Light of undefined type!");
1129 /* VorteX: set noShadow color */
1130 VectorScale(light->color, add, trace->colorNoShadow);
1132 /* ydnar: changed to a variable number */
1133 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1136 addDeluxe *= colorBrightness;
1138 /* hack land: scale down the radiosity contribution to light directionality.
1139 Deluxemaps fusion many light directions into one. In a rtl process all lights
1140 would contribute individually to the bump map, so several light sources together
1141 would make it more directional (example: a yellow and red lights received from
1142 opposing sides would light one side in red and the other in blue, adding
1143 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1144 neutralize each other making it look like having no direction.
1145 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1146 is modifying the direction applied from directional lights, making it go closer and closer
1147 to the surface normal the bigger is the amount of radiosity received.
1148 So, for preserving the directional lights contributions, we scale down the radiosity
1149 contribution. It's a hack, but there's a reason behind it */
1152 addDeluxe *= addDeluxeBounceScale;
1153 /* better NOT increase it beyond the original value
1154 if( addDeluxe < 0.00390625f )
1155 addDeluxe = 0.00390625f;
1161 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1165 trace->testAll = qfalse;
1166 VectorScale( light->color, add, trace->color );
1170 trace->forceSubsampling *= add;
1171 if( trace->passSolid || trace->opaque )
1173 VectorClear( trace->color );
1174 VectorClear( trace->directionContribution );
1179 /* return to sender */
1187 determines the amount of light reaching a sample (luxel or vertex)
1190 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1196 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1197 VectorClear( colors[ lightmapNum ] );
1199 /* ydnar: normalmap */
1202 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1203 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1204 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1208 /* ydnar: don't bounce ambient all the time */
1210 VectorCopy( ambientColor, colors[ 0 ] );
1212 /* ydnar: trace to all the list of lights pre-stored in tw */
1213 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1216 trace->light = trace->lights[ i ];
1219 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1221 if( styles[ lightmapNum ] == trace->light->style ||
1222 styles[ lightmapNum ] == LS_NONE )
1226 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1227 if( lightmapNum >= MAX_LIGHTMAPS )
1231 LightContributionToSample( trace );
1232 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1235 /* handle negative light */
1236 if( trace->light->flags & LIGHT_NEGATIVE )
1237 VectorScale( trace->color, -1.0f, trace->color );
1240 styles[ lightmapNum ] = trace->light->style;
1243 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1247 colors[ 0 ][ 0 ] >= 255.0f &&
1248 colors[ 0 ][ 1 ] >= 255.0f &&
1249 colors[ 0 ][ 2 ] >= 255.0f )
1257 LightContributionToPoint()
1258 for a given light, how much light/color reaches a given point in space (with no facing)
1259 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1262 int LightContributionToPoint( trace_t *trace )
1269 light = trace->light;
1272 VectorClear( trace->color );
1274 /* ydnar: early out */
1275 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1278 /* is this a sun? */
1279 if( light->type != EMIT_SUN )
1286 if( !ClusterVisible( trace->cluster, light->cluster ) )
1290 /* ydnar: check origin against light's pvs envelope */
1291 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1292 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1293 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1299 /* set light origin */
1300 if( light->type == EMIT_SUN )
1301 VectorAdd( trace->origin, light->origin, trace->end );
1303 VectorCopy( light->origin, trace->end );
1306 dist = SetupTrace( trace );
1309 if( dist > light->envelope )
1311 gridEnvelopeCulled++;
1315 /* ptpff approximation */
1316 if( light->type == EMIT_AREA && faster )
1318 /* clamp the distance to prevent super hot spots */
1319 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1324 add = light->photons / (dist * dist);
1327 /* exact point to polygon form factor */
1328 else if( light->type == EMIT_AREA )
1331 vec3_t pushedOrigin;
1334 /* see if the point is behind the light */
1335 d = DotProduct( trace->origin, light->normal ) - light->dist;
1336 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1339 /* nudge the point so that it is clearly forward of the light */
1340 /* so that surfaces meeting a light emiter don't get black edges */
1341 if( d > -8.0f && d < 8.0f )
1342 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1344 VectorCopy( trace->origin, pushedOrigin );
1346 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1347 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1348 if( factor == 0.0f )
1350 else if( factor < 0.0f )
1352 if( light->flags & LIGHT_TWOSIDED )
1358 /* ydnar: moved to here */
1359 add = factor * light->add;
1362 /* point/spot lights */
1363 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1365 /* clamp the distance to prevent super hot spots */
1366 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1371 if( light->flags & LIGHT_ATTEN_LINEAR )
1373 add = light->photons * linearScale - (dist * light->fade);
1378 add = light->photons / (dist * dist);
1380 /* handle spotlights */
1381 if( light->type == EMIT_SPOT )
1383 float distByNormal, radiusAtDist, sampleRadius;
1384 vec3_t pointAtDist, distToSample;
1387 /* do cone calculation */
1388 distByNormal = -DotProduct( trace->displacement, light->normal );
1389 if( distByNormal < 0.0f )
1391 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1392 radiusAtDist = light->radiusByDist * distByNormal;
1393 VectorSubtract( trace->origin, pointAtDist, distToSample );
1394 sampleRadius = VectorLength( distToSample );
1396 /* outside the cone */
1397 if( sampleRadius >= radiusAtDist )
1401 if( sampleRadius > (radiusAtDist - 32.0f) )
1402 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1406 /* ydnar: sunlight */
1407 else if( light->type == EMIT_SUN )
1410 add = light->photons;
1415 trace->testAll = qtrue;
1416 VectorScale( light->color, add, trace->color );
1418 /* trace to point */
1419 if( trace->testOcclusion && !trace->forceSunlight )
1423 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1425 VectorClear( trace->color );
1430 /* return to sender */
1434 /* unknown light type */
1438 /* ydnar: changed to a variable number */
1439 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1443 trace->testAll = qfalse;
1444 VectorScale( light->color, add, trace->color );
1448 if( trace->passSolid )
1450 VectorClear( trace->color );
1454 /* we have a valid sample */
1462 grid samples are for quickly determining the lighting
1463 of dynamically placed entities in the world
1466 #define MAX_CONTRIBUTIONS 32768
1477 void TraceGrid( int num )
1479 int i, j, x, y, z, mod, numCon, numStyles;
1481 vec3_t baseOrigin, cheapColor, color, thisdir;
1483 bspGridPoint_t *bgp;
1484 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1487 /* get grid points */
1488 gp = &rawGridPoints[ num ];
1489 bgp = &bspGridPoints[ num ];
1491 /* get grid origin */
1493 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1494 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1495 y = mod / gridBounds[ 0 ];
1496 mod -= y * gridBounds[ 0 ];
1499 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1500 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1501 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1503 /* set inhibit sphere */
1504 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1505 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1506 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1507 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1509 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1511 /* find point cluster */
1512 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1513 if( trace.cluster < 0 )
1515 /* try to nudge the origin around to find a valid point */
1516 VectorCopy( trace.origin, baseOrigin );
1517 for( step = 0; (step += 0.005) <= 1.0; )
1519 VectorCopy( baseOrigin, trace.origin );
1520 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1521 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1522 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1524 /* ydnar: changed to find cluster num */
1525 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1526 if( trace.cluster >= 0 )
1530 /* can't find a valid point at all */
1536 trace.testOcclusion = !noTrace;
1537 trace.forceSunlight = qfalse;
1538 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1539 trace.numSurfaces = 0;
1540 trace.surfaces = NULL;
1541 trace.numLights = 0;
1542 trace.lights = NULL;
1546 VectorClear( cheapColor );
1548 /* trace to all the lights, find the major light direction, and divide the
1549 total light between that along the direction and the remaining in the ambient */
1550 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1556 if( !LightContributionToPoint( &trace ) )
1559 /* handle negative light */
1560 if( trace.light->flags & LIGHT_NEGATIVE )
1561 VectorScale( trace.color, -1.0f, trace.color );
1563 /* add a contribution */
1564 VectorCopy( trace.color, contributions[ numCon ].color );
1565 VectorCopy( trace.direction, contributions[ numCon ].dir );
1566 VectorClear( contributions[ numCon ].ambient );
1567 contributions[ numCon ].style = trace.light->style;
1570 /* push average direction around */
1571 addSize = VectorLength( trace.color );
1572 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1574 /* stop after a while */
1575 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1578 /* ydnar: cheap mode */
1579 VectorAdd( cheapColor, trace.color, cheapColor );
1580 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1584 /////// Floodlighting for point //////////////////
1585 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1590 vec3_t dir = { 0, 0, 1 };
1591 float ambientFrac = 0.25f;
1593 trace.testOcclusion = qtrue;
1594 trace.forceSunlight = qfalse;
1595 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1596 trace.testAll = qtrue;
1598 for( k = 0; k < 2; k++ )
1600 if( k == 0 ) // upper hemisphere
1602 trace.normal[0] = 0;
1603 trace.normal[1] = 0;
1604 trace.normal[2] = 1;
1606 else //lower hemisphere
1608 trace.normal[0] = 0;
1609 trace.normal[1] = 0;
1610 trace.normal[2] = -1;
1613 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1615 /* add a fraction as pure ambient, half as top-down direction */
1616 contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1617 contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1618 contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1620 contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1621 contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1622 contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1624 contributions[ numCon ].dir[0] = dir[0];
1625 contributions[ numCon ].dir[1] = dir[1];
1626 contributions[ numCon ].dir[2] = dir[2];
1628 contributions[ numCon ].style = 0;
1630 /* push average direction around */
1631 addSize = VectorLength( contributions[ numCon ].color );
1632 VectorMA( gp->dir, addSize, dir, gp->dir );
1637 /////////////////////
1639 /* normalize to get primary light direction */
1640 VectorNormalize( gp->dir, thisdir );
1642 /* now that we have identified the primary light direction,
1643 go back and separate all the light into directed and ambient */
1646 for( i = 0; i < numCon; i++ )
1648 /* get relative directed strength */
1649 d = DotProduct( contributions[ i ].dir, thisdir );
1650 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1651 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1655 /* find appropriate style */
1656 for( j = 0; j < numStyles; j++ )
1658 if( gp->styles[ j ] == contributions[ i ].style )
1662 /* style not found? */
1663 if( j >= numStyles )
1665 /* add a new style */
1666 if( numStyles < MAX_LIGHTMAPS )
1668 gp->styles[ numStyles ] = contributions[ i ].style;
1669 bgp->styles[ numStyles ] = contributions[ i ].style;
1671 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1679 /* add the directed color */
1680 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1682 /* ambient light will be at 1/4 the value of directed light */
1683 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1684 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1686 /* (Hobbes: always setting it to .25 is hardly any better) */
1687 d = 0.25f * (1.0f - d);
1688 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1690 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1694 * the total light average = ambient value + 0.25 * sum of all directional values
1695 * we can also get the total light average as 0.25 * the sum of all contributions
1697 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1700 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1702 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1707 /* store off sample */
1708 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1711 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1713 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1716 /* set minimum light and copy off to bytes */
1717 VectorCopy( gp->ambient[ i ], color );
1718 for( j = 0; j < 3; j++ )
1719 if( color[ j ] < minGridLight[ j ] )
1720 color[ j ] = minGridLight[ j ];
1722 /* vortex: apply gridscale and gridambientscale here */
1723 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1724 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1729 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1730 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1732 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1733 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1736 /* store direction */
1737 NormalToLatLong( thisdir, bgp->latLong );
1744 calculates the size of the lightgrid and allocates memory
1747 void SetupGrid( void )
1750 vec3_t maxs, oldGridSize;
1755 /* don't do this if not grid lighting */
1756 if( noGridLighting )
1759 /* ydnar: set grid size */
1760 value = ValueForKey( &entities[ 0 ], "gridsize" );
1761 if( value[ 0 ] != '\0' )
1762 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1765 VectorCopy( gridSize, oldGridSize );
1766 for( i = 0; i < 3; i++ )
1767 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1769 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1770 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1772 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1774 /* get world bounds */
1775 for( i = 0; i < 3; i++ )
1777 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1778 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1779 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1783 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1785 /* increase grid size a bit */
1786 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1787 gridSize[ j++ % 3 ] += 16.0f;
1791 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1794 if( !VectorCompare( gridSize, oldGridSize ) )
1796 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1797 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1798 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1801 /* 2nd variable. fixme: is this silly? */
1802 numBSPGridPoints = numRawGridPoints;
1804 /* allocate lightgrid */
1805 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1806 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1808 if( bspGridPoints != NULL )
1809 free( bspGridPoints );
1810 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1811 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1813 /* clear lightgrid */
1814 for( i = 0; i < numRawGridPoints; i++ )
1816 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1817 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1818 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1819 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1821 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1822 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1827 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1834 does what it says...
1837 void LightWorld( void )
1842 qboolean minVertex, minGrid;
1846 /* ydnar: smooth normals */
1849 Sys_Printf( "--- SmoothNormals ---\n" );
1853 /* determine the number of grid points */
1854 Sys_Printf( "--- SetupGrid ---\n" );
1857 /* find the optional minimum lighting values */
1858 GetVectorForKey( &entities[ 0 ], "_color", color );
1861 color[0] = Image_LinearFloatFromsRGBFloat(color[0]);
1862 color[1] = Image_LinearFloatFromsRGBFloat(color[1]);
1863 color[2] = Image_LinearFloatFromsRGBFloat(color[2]);
1865 if( VectorLength( color ) == 0.0f )
1866 VectorSet( color, 1.0, 1.0, 1.0 );
1869 f = FloatForKey( &entities[ 0 ], "_ambient" );
1871 f = FloatForKey( &entities[ 0 ], "ambient" );
1872 VectorScale( color, f, ambientColor );
1874 /* minvertexlight */
1876 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1877 if( value[ 0 ] != '\0' )
1881 VectorScale( color, f, minVertexLight );
1886 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1887 if( value[ 0 ] != '\0' )
1891 VectorScale( color, f, minGridLight );
1895 value = ValueForKey( &entities[ 0 ], "_minlight" );
1896 if( value[ 0 ] != '\0' )
1899 VectorScale( color, f, minLight );
1900 if( minVertex == qfalse )
1901 VectorScale( color, f, minVertexLight );
1902 if( minGrid == qfalse )
1903 VectorScale( color, f, minGridLight );
1906 /* create world lights */
1907 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1908 CreateEntityLights();
1909 CreateSurfaceLights();
1910 Sys_Printf( "%9d point lights\n", numPointLights );
1911 Sys_Printf( "%9d spotlights\n", numSpotLights );
1912 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1913 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1915 /* calculate lightgrid */
1916 if( !noGridLighting )
1918 /* ydnar: set up light envelopes */
1919 SetupEnvelopes( qtrue, fastgrid );
1921 Sys_Printf( "--- TraceGrid ---\n" );
1923 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1925 Sys_Printf( "%d x %d x %d = %d grid\n",
1926 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1928 /* ydnar: emit statistics on light culling */
1929 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1930 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1933 /* slight optimization to remove a sqrt */
1934 subdivideThreshold *= subdivideThreshold;
1936 /* map the world luxels */
1937 Sys_Printf( "--- MapRawLightmap ---\n" );
1938 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1939 Sys_Printf( "%9d luxels\n", numLuxels );
1940 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1941 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1946 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1947 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1950 /* floodlight pass */
1951 FloodlightRawLightmaps();
1953 /* ydnar: set up light envelopes */
1954 SetupEnvelopes( qfalse, fast );
1956 /* light up my world */
1957 lightsPlaneCulled = 0;
1958 lightsEnvelopeCulled = 0;
1959 lightsBoundsCulled = 0;
1960 lightsClusterCulled = 0;
1962 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1963 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1964 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1966 StitchSurfaceLightmaps();
1968 Sys_Printf( "--- IlluminateVertexes ---\n" );
1969 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1970 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1972 /* ydnar: emit statistics on light culling */
1973 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1974 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1975 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1976 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1983 /* store off the bsp between bounces */
1984 StoreSurfaceLightmaps();
1986 Sys_Printf( "Writing %s\n", source );
1987 WriteBSPFile( source );
1990 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1994 VectorClear( ambientColor );
1995 floodlighty = qfalse;
1997 /* generate diffuse lights */
1999 RadCreateDiffuseLights();
2001 /* setup light envelopes */
2002 SetupEnvelopes( qfalse, fastbounce );
2003 if( numLights == 0 )
2005 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
2009 /* add to lightgrid */
2012 gridEnvelopeCulled = 0;
2013 gridBoundsCulled = 0;
2015 Sys_Printf( "--- BounceGrid ---\n" );
2017 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2019 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2020 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2023 /* light up my world */
2024 lightsPlaneCulled = 0;
2025 lightsEnvelopeCulled = 0;
2026 lightsBoundsCulled = 0;
2027 lightsClusterCulled = 0;
2029 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2030 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2031 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2032 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2034 StitchSurfaceLightmaps();
2036 Sys_Printf( "--- IlluminateVertexes ---\n" );
2037 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2038 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2040 /* ydnar: emit statistics on light culling */
2041 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2042 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2043 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2044 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2056 main routine for light processing
2059 int LightMain( int argc, char **argv )
2063 char mapSource[ 1024 ];
2065 int lightmapMergeSize = 0;
2066 qboolean lightSamplesInsist = qfalse;
2070 Sys_Printf( "--- Light ---\n" );
2071 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2073 /* set standard game flags */
2074 wolfLight = game->wolfLight;
2075 if (wolfLight == qtrue)
2076 Sys_Printf( " lightning model: wolf\n" );
2078 Sys_Printf( " lightning model: quake3\n" );
2080 lmCustomSize = game->lightmapSize;
2081 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2083 lightmapGamma = game->lightmapGamma;
2084 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2086 lightmapsRGB = game->lightmapsRGB;
2088 Sys_Printf( " lightmap colorspace: sRGB\n" );
2090 Sys_Printf( " lightmap colorspace: linear\n" );
2092 texturesRGB = game->texturesRGB;
2094 Sys_Printf( " texture colorspace: sRGB\n" );
2096 Sys_Printf( " texture colorspace: linear\n" );
2098 colorsRGB = game->colorsRGB;
2100 Sys_Printf( " _color colorspace: sRGB\n" );
2102 Sys_Printf( " _color colorspace: linear\n" );
2104 lightmapCompensate = game->lightmapCompensate;
2105 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2107 lightmapExposure = game->lightmapExposure;
2108 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2110 gridScale = game->gridScale;
2111 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2113 gridAmbientScale = game->gridAmbientScale;
2114 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2116 lightAngleHL = game->lightAngleHL;
2118 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2120 noStyles = game->noStyles;
2121 if (noStyles == qtrue)
2122 Sys_Printf( " shader lightstyles hack: disabled\n" );
2124 Sys_Printf( " shader lightstyles hack: enabled\n" );
2126 patchShadows = game->patchShadows;
2127 if (patchShadows == qtrue)
2128 Sys_Printf( " patch shadows: enabled\n" );
2130 Sys_Printf( " patch shadows: disabled\n" );
2132 deluxemap = game->deluxeMap;
2133 deluxemode = game->deluxeMode;
2134 if (deluxemap == qtrue)
2137 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2139 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2142 Sys_Printf( " deluxemapping: disabled\n" );
2144 Sys_Printf( "--- ProcessCommandLine ---\n" );
2146 /* process commandline arguments */
2147 for( i = 1; i < (argc - 1); i++ )
2149 /* lightsource scaling */
2150 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
2152 f = atof( argv[ i + 1 ] );
2155 Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2156 Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2160 else if( !strcmp( argv[ i ], "-spherical" ) || !strcmp( argv[ i ], "-sphericalscale" ) )
2162 f = atof( argv[ i + 1 ] );
2164 Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2168 else if( !strcmp( argv[ i ], "-spot" ) || !strcmp( argv[ i ], "-spotscale" ) )
2170 f = atof( argv[ i + 1 ] );
2172 Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2176 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
2178 f = atof( argv[ i + 1 ] );
2180 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2184 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
2186 f = atof( argv[ i + 1 ] );
2188 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2192 else if( !strcmp( argv[ i ], "-bouncescale" ) )
2194 f = atof( argv[ i + 1 ] );
2196 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2200 else if( !strcmp( argv[ i ], "-scale" ) )
2202 f = atof( argv[ i + 1 ] );
2208 Sys_Printf( "All light scaled by %f\n", f );
2212 else if( !strcmp( argv[ i ], "-gridscale" ) )
2214 f = atof( argv[ i + 1 ] );
2215 Sys_Printf( "Grid lightning scaled by %f\n", f );
2220 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2222 f = atof( argv[ i + 1 ] );
2223 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2224 gridAmbientScale *= f;
2228 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2230 f = atof( argv[ i + 1 ] );
2232 if(f < gridAmbientDirectionality) gridAmbientDirectionality = f;
2233 Sys_Printf( "Grid directionality is %f\n", f );
2234 gridDirectionality = f;
2238 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2240 f = atof( argv[ i + 1 ] );
2242 if(f > gridDirectionality) gridDirectionality = f;
2243 Sys_Printf( "Grid ambient directionality is %f\n", f );
2244 gridAmbientDirectionality = f;
2248 else if( !strcmp( argv[ i ], "-gamma" ) )
2250 f = atof( argv[ i + 1 ] );
2252 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2256 else if( !strcmp( argv[ i ], "-sRGBlight" ) )
2258 lightmapsRGB = qtrue;
2259 Sys_Printf( "Lighting is in sRGB\n" );
2262 else if( !strcmp( argv[ i ], "-nosRGBlight" ) )
2264 lightmapsRGB = qfalse;
2265 Sys_Printf( "Lighting is linear\n" );
2268 else if( !strcmp( argv[ i ], "-sRGBtex" ) )
2270 texturesRGB = qtrue;
2271 Sys_Printf( "Textures are in sRGB\n" );
2274 else if( !strcmp( argv[ i ], "-nosRGBtex" ) )
2276 texturesRGB = qfalse;
2277 Sys_Printf( "Textures are linear\n" );
2280 else if( !strcmp( argv[ i ], "-sRGBcolor" ) )
2283 Sys_Printf( "Colors are in sRGB\n" );
2286 else if( !strcmp( argv[ i ], "-nosRGBcolor" ) )
2289 Sys_Printf( "Colors are linear\n" );
2292 else if( !strcmp( argv[ i ], "-nosRGB" ) )
2294 lightmapsRGB = qtrue;
2295 Sys_Printf( "Lighting is linear\n" );
2296 texturesRGB = qtrue;
2297 Sys_Printf( "Textures are linear\n" );
2299 Sys_Printf( "Colors are linear\n" );
2302 else if( !strcmp( argv[ i ], "-exposure" ) )
2304 f = atof( argv[ i + 1 ] );
2305 lightmapExposure = f;
2306 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2310 else if( !strcmp( argv[ i ], "-compensate" ) )
2312 f = atof( argv[ i + 1 ] );
2315 lightmapCompensate = f;
2316 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2320 /* ydnar switches */
2321 else if( !strcmp( argv[ i ], "-bounce" ) )
2323 bounce = atoi( argv[ i + 1 ] );
2326 else if( bounce > 0 )
2327 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2331 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2333 superSample = atoi( argv[ i + 1 ] );
2334 if( superSample < 1 )
2336 else if( superSample > 1 )
2337 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2341 else if( !strcmp( argv[ i ], "-randomsamples" ) )
2343 lightRandomSamples = qtrue;
2344 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2347 else if( !strcmp( argv[ i ], "-samples" ) )
2349 if(*argv[i+1] == '+')
2350 lightSamplesInsist = qtrue;
2352 lightSamplesInsist = qfalse;
2353 lightSamples = atoi( argv[ i + 1 ] );
2354 if( lightSamples < 1 )
2356 else if( lightSamples > 1 )
2357 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2361 else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
2363 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2364 if( lightSamplesSearchBoxSize <= 0 )
2365 lightSamplesSearchBoxSize = 1;
2366 if( lightSamplesSearchBoxSize > 4 )
2367 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2368 else if( lightSamplesSearchBoxSize != 1 )
2369 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2373 else if( !strcmp( argv[ i ], "-filter" ) )
2376 Sys_Printf( "Lightmap filtering enabled\n" );
2379 else if( !strcmp( argv[ i ], "-dark" ) )
2382 Sys_Printf( "Dark lightmap seams enabled\n" );
2385 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2387 shadeAngleDegrees = atof( argv[ i + 1 ] );
2388 if( shadeAngleDegrees < 0.0f )
2389 shadeAngleDegrees = 0.0f;
2390 else if( shadeAngleDegrees > 0.0f )
2393 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2398 else if( !strcmp( argv[ i ], "-thresh" ) )
2400 subdivideThreshold = atof( argv[ i + 1 ] );
2401 if( subdivideThreshold < 0 )
2402 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2404 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2408 else if( !strcmp( argv[ i ], "-approx" ) )
2410 approximateTolerance = atoi( argv[ i + 1 ] );
2411 if( approximateTolerance < 0 )
2412 approximateTolerance = 0;
2413 else if( approximateTolerance > 0 )
2414 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2417 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2420 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2422 else if( !strcmp( argv[ i ], "-deluxemode" ))
2424 deluxemode = atoi( argv[ i + 1 ] );
2425 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2427 Sys_Printf( "Generating modelspace deluxemaps\n" );
2431 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2434 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2437 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2439 else if( !strcmp( argv[ i ], "-external" ) )
2441 externalLightmaps = qtrue;
2442 Sys_Printf( "Storing all lightmaps externally\n" );
2445 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2447 lmCustomSize = atoi( argv[ i + 1 ] );
2449 /* must be a power of 2 and greater than 2 */
2450 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2452 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2453 lmCustomSize = game->lightmapSize;
2456 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2458 /* enable external lightmaps */
2459 if( lmCustomSize != game->lightmapSize )
2461 externalLightmaps = qtrue;
2462 Sys_Printf( "Storing all lightmaps externally\n" );
2466 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2468 lmLimitSize = atoi( argv[ i + 1 ] );
2471 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2474 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2476 lmCustomDir = argv[i + 1];
2478 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2479 externalLightmaps = qtrue;
2480 Sys_Printf( "Storing all lightmaps externally\n" );
2483 /* ydnar: add this to suppress warnings */
2484 else if( !strcmp( argv[ i ], "-custinfoparms") )
2486 Sys_Printf( "Custom info parms enabled\n" );
2487 useCustomInfoParms = qtrue;
2490 else if( !strcmp( argv[ i ], "-wolf" ) )
2492 /* -game should already be set */
2494 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2497 else if( !strcmp( argv[ i ], "-q3" ) )
2499 /* -game should already be set */
2501 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2504 else if( !strcmp( argv[ i ], "-extradist" ) )
2506 extraDist = atof( argv[ i + 1 ] );
2510 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2513 else if( !strcmp( argv[ i ], "-sunonly" ) )
2516 Sys_Printf( "Only computing sunlight\n" );
2519 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2522 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2525 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2528 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2531 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2533 lightmapSearchBlockSize = 1;
2534 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2537 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2539 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2541 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2544 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2546 lightmapSearchBlockSize = atoi(argv[i+1]);
2548 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2551 else if( !strcmp( argv[ i ], "-shade" ) )
2554 Sys_Printf( "Phong shading enabled\n" );
2557 else if( !strcmp( argv[ i ], "-bouncegrid") )
2561 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2564 else if( !strcmp( argv[ i ], "-smooth" ) )
2566 lightSamples = EXTRA_SCALE;
2567 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2570 else if( !strcmp( argv[ i ], "-fast" ) )
2575 Sys_Printf( "Fast mode enabled\n" );
2578 else if( !strcmp( argv[ i ], "-faster" ) )
2584 Sys_Printf( "Faster mode enabled\n" );
2587 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2590 Sys_Printf( "Fast grid lighting enabled\n" );
2593 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2596 Sys_Printf( "Fast bounce mode enabled\n" );
2599 else if( !strcmp( argv[ i ], "-cheap" ) )
2603 Sys_Printf( "Cheap mode enabled\n" );
2606 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2609 Sys_Printf( "Cheap grid mode enabled\n" );
2612 else if( !strcmp( argv[ i ], "-normalmap" ) )
2615 Sys_Printf( "Storing normal map instead of lightmap\n" );
2618 else if( !strcmp( argv[ i ], "-trisoup" ) )
2621 Sys_Printf( "Converting brush faces to triangle soup\n" );
2624 else if( !strcmp( argv[ i ], "-debug" ) )
2627 Sys_Printf( "Lightmap debugging enabled\n" );
2630 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2632 debugSurfaces = qtrue;
2633 Sys_Printf( "Lightmap surface debugging enabled\n" );
2636 else if( !strcmp( argv[ i ], "-debugunused" ) )
2638 debugUnused = qtrue;
2639 Sys_Printf( "Unused luxel debugging enabled\n" );
2642 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2645 Sys_Printf( "Lightmap axis debugging enabled\n" );
2648 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2650 debugCluster = qtrue;
2651 Sys_Printf( "Luxel cluster debugging enabled\n" );
2654 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2656 debugOrigin = qtrue;
2657 Sys_Printf( "Luxel origin debugging enabled\n" );
2660 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2663 debugDeluxemap = qtrue;
2664 Sys_Printf( "Deluxemap debugging enabled\n" );
2667 else if( !strcmp( argv[ i ], "-export" ) )
2669 exportLightmaps = qtrue;
2670 Sys_Printf( "Exporting lightmaps\n" );
2673 else if( !strcmp(argv[ i ], "-notrace" ))
2676 Sys_Printf( "Shadow occlusion disabled\n" );
2678 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2680 patchShadows = qtrue;
2681 Sys_Printf( "Patch shadow casting enabled\n" );
2683 else if( !strcmp( argv[ i ], "-extra" ) )
2685 superSample = EXTRA_SCALE; /* ydnar */
2686 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2688 else if( !strcmp( argv[ i ], "-extrawide" ) )
2690 superSample = EXTRAWIDE_SCALE; /* ydnar */
2691 filter = qtrue; /* ydnar */
2692 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2694 else if( !strcmp( argv[ i ], "-samplesize" ) )
2696 sampleSize = atoi( argv[ i + 1 ] );
2697 if( sampleSize < 1 )
2700 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2702 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2704 minSampleSize = atoi( argv[ i + 1 ] );
2705 if( minSampleSize < 1 )
2708 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2710 else if( !strcmp( argv[ i ], "-samplescale" ) )
2712 sampleScale = atoi( argv[ i + 1 ] );
2714 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2716 else if( !strcmp( argv[ i ], "-novertex" ) )
2718 noVertexLighting = qtrue;
2719 Sys_Printf( "Disabling vertex lighting\n" );
2721 else if( !strcmp( argv[ i ], "-nogrid" ) )
2723 noGridLighting = qtrue;
2724 Sys_Printf( "Disabling grid lighting\n" );
2726 else if( !strcmp( argv[ i ], "-border" ) )
2728 lightmapBorder = qtrue;
2729 Sys_Printf( "Adding debug border to lightmaps\n" );
2731 else if( !strcmp( argv[ i ], "-nosurf" ) )
2734 Sys_Printf( "Not tracing against surfaces\n" );
2736 else if( !strcmp( argv[ i ], "-dump" ) )
2739 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2741 else if( !strcmp( argv[ i ], "-lomem" ) )
2744 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2746 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2748 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2750 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2752 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2754 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2757 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2760 Sys_Printf( "Disabling lightstyles\n" );
2762 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2765 Sys_Printf( "Enabling lightstyles\n" );
2767 else if( !strcmp( argv[ i ], "-cpma" ) )
2770 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2772 else if( !strcmp( argv[ i ], "-floodlight" ) )
2774 floodlighty = qtrue;
2775 Sys_Printf( "FloodLighting enabled\n" );
2777 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2779 debugnormals = qtrue;
2780 Sys_Printf( "DebugNormals enabled\n" );
2782 else if( !strcmp( argv[ i ], "-lowquality" ) )
2784 floodlight_lowquality = qtrue;
2785 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2788 /* r7: dirtmapping */
2789 else if( !strcmp( argv[ i ], "-dirty" ) )
2792 Sys_Printf( "Dirtmapping enabled\n" );
2794 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2797 Sys_Printf( "Dirtmap debugging enabled\n" );
2799 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2801 dirtMode = atoi( argv[ i + 1 ] );
2802 if( dirtMode != 0 && dirtMode != 1 )
2805 Sys_Printf( "Enabling randomized dirtmapping\n" );
2807 Sys_Printf( "Enabling ordered dir mapping\n" );
2810 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2812 dirtDepth = atof( argv[ i + 1 ] );
2813 if( dirtDepth <= 0.0f )
2815 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2818 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2820 dirtScale = atof( argv[ i + 1 ] );
2821 if( dirtScale <= 0.0f )
2823 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2826 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2828 dirtGain = atof( argv[ i + 1 ] );
2829 if( dirtGain <= 0.0f )
2831 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2834 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2836 lightmapTriangleCheck = qtrue;
2838 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2840 lightmapExtraVisClusterNudge = qtrue;
2842 else if( !strcmp( argv[ i ], "-fill" ) )
2844 lightmapFill = qtrue;
2845 Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2847 /* unhandled args */
2850 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2855 /* fix up falloff tolerance for sRGB */
2857 falloffTolerance = Image_LinearFloatFromsRGBFloat(falloffTolerance * (1.0 / 255.0)) * 255.0;
2859 /* fix up samples count */
2860 if(lightRandomSamples)
2862 if(!lightSamplesInsist)
2864 /* approximately match -samples in quality */
2865 switch(lightSamples)
2871 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2877 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2883 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2891 /* fix up lightmap search power */
2892 if(lightmapMergeSize)
2894 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2895 if(lightmapSearchBlockSize < 1)
2896 lightmapSearchBlockSize = 1;
2898 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2901 /* clean up map name */
2902 strcpy( source, ExpandArg( argv[ i ] ) );
2903 StripExtension( source );
2904 DefaultExtension( source, ".bsp" );
2905 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2906 StripExtension( mapSource );
2907 DefaultExtension( mapSource, ".map" );
2909 /* ydnar: set default sample size */
2910 SetDefaultSampleSize( sampleSize );
2912 /* ydnar: handle shaders */
2913 BeginMapShaderFile( source );
2917 Sys_Printf( "Loading %s\n", source );
2919 /* ydnar: load surface file */
2920 LoadSurfaceExtraFile( source );
2923 LoadBSPFile( source );
2925 /* parse bsp entities */
2928 /* inject command line parameters */
2929 InjectCommandLine(argv, 0, argc - 1);
2932 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2933 if( value[ 0 ] != '1' )
2934 LoadMapFile( mapSource, qtrue, qfalse );
2936 /* set the entity/model origins and init yDrawVerts */
2939 /* ydnar: set up optimization */
2943 SetupSurfaceLightmaps();
2945 /* initialize the surface facet tracing */
2948 /* light the world */
2951 /* ydnar: store off lightmaps */
2952 StoreSurfaceLightmaps();
2954 /* write out the bsp */
2956 Sys_Printf( "Writing %s\n", source );
2957 WriteBSPFile( source );
2959 /* ydnar: export lightmaps */
2960 if( exportLightmaps && !externalLightmaps )
2963 /* return to sender */