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 ){
48 float photons, d, angle, elevation, da, de;
59 if ( sun->numSamples < 1 ) {
64 photons = sun->photons / sun->numSamples;
66 /* create the right number of suns */
67 for ( i = 0; i < sun->numSamples; i++ )
69 /* calculate sun direction */
71 VectorCopy( sun->direction, direction );
76 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
77 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
78 sun->direction[ 2 ] = sin( elevation );
80 xz_dist = sqrt( x*x + z*z )
81 latitude = atan2( xz_dist, y ) * RADIANS
82 longitude = atan2( x, z ) * RADIANS
85 d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
86 angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
87 elevation = atan2( sun->direction[ 2 ], d );
89 /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
92 da = ( Random() * 2.0f - 1.0f ) * sun->deviance;
93 de = ( Random() * 2.0f - 1.0f ) * sun->deviance;
95 while ( ( da * da + de * de ) > ( sun->deviance * sun->deviance ) );
100 //% Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
102 /* create new vector */
103 direction[ 0 ] = cos( angle ) * cos( elevation );
104 direction[ 1 ] = sin( angle ) * cos( elevation );
105 direction[ 2 ] = sin( elevation );
110 light = safe_malloc( sizeof( *light ) );
111 memset( light, 0, sizeof( *light ) );
112 light->next = lights;
115 /* initialize the light */
116 light->flags = LIGHT_SUN_DEFAULT;
117 light->type = EMIT_SUN;
119 light->falloffTolerance = falloffTolerance;
120 light->filterRadius = sun->filterRadius / sun->numSamples;
121 light->style = noStyles ? LS_NORMAL : sun->style;
123 /* set the light's position out to infinity */
124 VectorMA( vec3_origin, ( MAX_WORLD_COORD * 8.0f ), direction, light->origin ); /* MAX_WORLD_COORD * 2.0f */
126 /* set the facing to be the inverse of the sun direction */
127 VectorScale( direction, -1.0, light->normal );
128 light->dist = DotProduct( light->origin, light->normal );
130 /* set color and photons */
131 VectorCopy( sun->color, light->color );
132 light->photons = photons * skyScale;
136 if ( sun->next != NULL ) {
137 CreateSunLight( sun->next );
144 CreateSkyLights() - ydnar
145 simulates sky light with multiple suns
148 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius, int style ){
150 int angleSteps, elevationSteps;
151 float angle, elevation;
152 float angleStep, elevationStep;
157 if ( value <= 0.0f || iterations < 2 ) {
161 /* basic sun setup */
162 VectorCopy( color, sun.color );
164 sun.filterRadius = filterRadius;
166 sun.style = noStyles ? LS_NORMAL : style;
170 elevationSteps = iterations - 1;
171 angleSteps = elevationSteps * 4;
173 elevationStep = DEG2RAD( 90.0f / iterations ); /* skip elevation 0 */
174 angleStep = DEG2RAD( 360.0f / angleSteps );
176 /* calc individual sun brightness */
177 numSuns = angleSteps * elevationSteps + 1;
178 sun.photons = value / numSuns;
180 /* iterate elevation */
181 elevation = elevationStep * 0.5f;
183 for ( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
186 for ( j = 0; j < angleSteps; j++ )
189 sun.direction[ 0 ] = cos( angle ) * cos( elevation );
190 sun.direction[ 1 ] = sin( angle ) * cos( elevation );
191 sun.direction[ 2 ] = sin( elevation );
192 CreateSunLight( &sun );
199 elevation += elevationStep;
200 angle += angleStep / elevationSteps;
203 /* create vertical sun */
204 VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
205 CreateSunLight( &sun );
215 creates lights from light entities
218 void CreateEntityLights( void ){
220 light_t *light, *light2;
226 float intensity, scale, deviance, filterRadius;
227 int spawnflags, flags, numSamples;
231 /* go throught entity list and find lights */
232 for ( i = 0; i < numEntities; i++ )
236 name = ValueForKey( e, "classname" );
238 /* ydnar: check for lightJunior */
239 if ( Q_strncasecmp( name, "lightJunior", 11 ) == 0 ) {
242 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 ) {
257 light = safe_malloc( sizeof( *light ) );
258 memset( light, 0, sizeof( *light ) );
259 light->next = lights;
262 /* handle spawnflags */
263 spawnflags = IntForKey( e, "spawnflags" );
265 /* ydnar: quake 3+ light behavior */
266 if ( wolfLight == qfalse ) {
267 /* set default flags */
268 flags = LIGHT_Q3A_DEFAULT;
270 /* linear attenuation? */
271 if ( spawnflags & 1 ) {
272 flags |= LIGHT_ATTEN_LINEAR;
273 flags &= ~LIGHT_ATTEN_ANGLE;
276 /* no angle attenuate? */
277 if ( spawnflags & 2 ) {
278 flags &= ~LIGHT_ATTEN_ANGLE;
282 /* ydnar: wolf light behavior */
285 /* set default flags */
286 flags = LIGHT_WOLF_DEFAULT;
288 /* inverse distance squared attenuation? */
289 if ( spawnflags & 1 ) {
290 flags &= ~LIGHT_ATTEN_LINEAR;
291 flags |= LIGHT_ATTEN_ANGLE;
294 /* angle attenuate? */
295 if ( spawnflags & 2 ) {
296 flags |= LIGHT_ATTEN_ANGLE;
300 /* other flags (borrowed from wolf) */
302 /* wolf dark light? */
303 if ( ( spawnflags & 4 ) || ( spawnflags & 8 ) ) {
308 if ( spawnflags & 16 ) {
309 flags &= ~LIGHT_GRID;
315 flags &= ~LIGHT_SURFACES;
318 /* vortex: unnormalized? */
319 if ( spawnflags & 32 ) {
320 flags |= LIGHT_UNNORMALIZED;
323 /* vortex: distance atten? */
324 if ( spawnflags & 64 ) {
325 flags |= LIGHT_ATTEN_DISTANCE;
328 /* store the flags */
329 light->flags = flags;
331 /* ydnar: set fade key (from wolf) */
333 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
334 light->fade = FloatForKey( e, "fade" );
335 if ( light->fade == 0.0f ) {
340 /* ydnar: set angle scaling (from vlight) */
341 light->angleScale = FloatForKey( e, "_anglescale" );
342 if ( light->angleScale != 0.0f ) {
343 light->flags |= LIGHT_ATTEN_ANGLE;
347 GetVectorForKey( e, "origin", light->origin );
348 light->style = IntForKey( e, "_style" );
349 if ( light->style == LS_NORMAL ) {
350 light->style = IntForKey( e, "style" );
352 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
353 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
356 if ( light->style != LS_NORMAL ) {
357 Sys_FPrintf( SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
360 /* set light intensity */
361 intensity = FloatForKey( e, "_light" );
362 if ( intensity == 0.0f ) {
363 intensity = FloatForKey( e, "light" );
365 if ( intensity == 0.0f ) {
369 /* ydnar: set light scale (sof2) */
370 scale = FloatForKey( e, "scale" );
371 if ( scale == 0.0f ) {
376 /* ydnar: get deviance and samples */
377 deviance = FloatForKey( e, "_deviance" );
378 if ( deviance == 0.0f ) {
379 deviance = FloatForKey( e, "_deviation" );
381 if ( deviance == 0.0f ) {
382 deviance = FloatForKey( e, "_jitter" );
384 numSamples = IntForKey( e, "_samples" );
385 if ( deviance < 0.0f || numSamples < 1 ) {
389 intensity /= numSamples;
391 /* ydnar: get filter radius */
392 filterRadius = FloatForKey( e, "_filterradius" );
393 if ( filterRadius == 0.0f ) {
394 filterRadius = FloatForKey( e, "_filteradius" );
396 if ( filterRadius == 0.0f ) {
397 filterRadius = FloatForKey( e, "_filter" );
399 if ( filterRadius < 0.0f ) {
402 light->filterRadius = filterRadius;
404 /* set light color */
405 _color = ValueForKey( e, "_color" );
406 if ( _color && _color[ 0 ] ) {
407 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
409 light->color[0] = Image_LinearFloatFromsRGBFloat( light->color[0] );
410 light->color[1] = Image_LinearFloatFromsRGBFloat( light->color[1] );
411 light->color[2] = Image_LinearFloatFromsRGBFloat( light->color[2] );
413 if ( !( light->flags & LIGHT_UNNORMALIZED ) ) {
414 ColorNormalize( light->color, light->color );
418 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
421 light->extraDist = FloatForKey( e, "_extradist" );
422 if ( light->extraDist == 0.0f ) {
423 light->extraDist = extraDist;
426 light->photons = intensity;
428 light->type = EMIT_POINT;
430 /* set falloff threshold */
431 light->falloffTolerance = falloffTolerance / numSamples;
433 /* lights with a target will be spotlights */
434 target = ValueForKey( e, "target" );
443 e2 = FindTargetEntity( target );
445 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
446 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
447 light->photons *= pointScale;
451 /* not a point light */
455 /* make a spotlight */
456 GetVectorForKey( e2, "origin", dest );
457 VectorSubtract( dest, light->origin, light->normal );
458 dist = VectorNormalize( light->normal, light->normal );
459 radius = FloatForKey( e, "radius" );
466 light->radiusByDist = ( radius + 16 ) / dist;
467 light->type = EMIT_SPOT;
469 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
470 light->flags &= ~LIGHT_ATTEN_LINEAR;
471 light->flags |= LIGHT_ATTEN_ANGLE;
474 /* ydnar: is this a sun? */
475 _sun = ValueForKey( e, "_sun" );
476 if ( _sun[ 0 ] == '1' ) {
477 /* not a spot light */
480 /* unlink this light */
481 lights = light->next;
484 VectorScale( light->normal, -1.0f, sun.direction );
485 VectorCopy( light->color, sun.color );
486 sun.photons = intensity;
487 sun.deviance = deviance / 180.0f * Q_PI;
488 sun.numSamples = numSamples;
489 sun.style = noStyles ? LS_NORMAL : light->style;
492 /* make a sun light */
493 CreateSunLight( &sun );
495 /* free original light */
499 /* skip the rest of this love story */
504 light->photons *= spotScale;
509 light->photons *= pointScale;
512 /* jitter the light */
513 for ( j = 1; j < numSamples; j++ )
516 light2 = safe_malloc( sizeof( *light ) );
517 memcpy( light2, light, sizeof( *light ) );
518 light2->next = lights;
522 if ( light->type == EMIT_SPOT ) {
530 light2->origin[ 0 ] = light->origin[ 0 ] + ( Random() * 2.0f - 1.0f ) * deviance;
531 light2->origin[ 1 ] = light->origin[ 1 ] + ( Random() * 2.0f - 1.0f ) * deviance;
532 light2->origin[ 2 ] = light->origin[ 2 ] + ( Random() * 2.0f - 1.0f ) * deviance;
540 CreateSurfaceLights() - ydnar
541 this hijacks the radiosity code to generate surface lights for first pass
544 #define APPROX_BOUNCE 1.0f
546 void CreateSurfaceLights( void ){
548 bspDrawSurface_t *ds;
558 /* get sun shader supressor */
559 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
561 /* walk the list of surfaces */
562 for ( i = 0; i < numBSPDrawSurfaces; i++ )
564 /* get surface and other bits */
565 ds = &bspDrawSurfaces[ i ];
566 info = &surfaceInfos[ i ];
570 if ( si->sun != NULL && nss[ 0 ] != '1' ) {
571 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
572 CreateSunLight( si->sun );
573 si->sun = NULL; /* FIXME: leak! */
577 if ( si->skyLightValue > 0.0f ) {
578 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
579 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
580 si->skyLightValue = 0.0f; /* FIXME: hack! */
583 /* try to early out */
584 if ( si->value <= 0 ) {
588 /* autosprite shaders become point lights */
589 if ( si->autosprite ) {
590 /* create an average xyz */
591 VectorAdd( info->mins, info->maxs, origin );
592 VectorScale( origin, 0.5f, origin );
595 light = safe_malloc( sizeof( *light ) );
596 memset( light, 0, sizeof( *light ) );
597 light->next = lights;
601 light->flags = LIGHT_Q3A_DEFAULT;
602 light->type = EMIT_POINT;
603 light->photons = si->value * pointScale;
606 VectorCopy( origin, light->origin );
607 VectorCopy( si->color, light->color );
608 light->falloffTolerance = falloffTolerance;
609 light->style = si->lightStyle;
611 /* add to point light count and continue */
616 /* get subdivision amount */
617 if ( si->lightSubdivide > 0 ) {
618 subdivide = si->lightSubdivide;
621 subdivide = defaultLightSubdivide;
625 switch ( ds->surfaceType )
628 case MST_TRIANGLE_SOUP:
629 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
633 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
646 find the offset values for inline models
649 void SetEntityOrigins( void ){
656 bspDrawSurface_t *ds;
659 /* ydnar: copy drawverts into private storage for nefarious purposes */
660 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
661 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
663 /* set the entity origins */
664 for ( i = 0; i < numEntities; i++ )
666 /* get entity and model */
668 key = ValueForKey( e, "model" );
669 if ( key[ 0 ] != '*' ) {
672 modelnum = atoi( key + 1 );
673 dm = &bspModels[ modelnum ];
675 /* get entity origin */
676 key = ValueForKey( e, "origin" );
677 if ( key[ 0 ] == '\0' ) {
680 GetVectorForKey( e, "origin", origin );
682 /* set origin for all surfaces for this model */
683 for ( j = 0; j < dm->numBSPSurfaces; j++ )
686 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
689 for ( k = 0; k < ds->numVerts; k++ )
691 f = ds->firstVert + k;
692 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
701 PointToPolygonFormFactor()
702 calculates the area over a point/normal hemisphere a winding covers
703 ydnar: fixme: there has to be a faster way to calculate this
704 without the expensive per-vert sqrts and transcendental functions
705 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
706 between this and the approximation
709 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
711 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ){
712 vec3_t triVector, triNormal;
714 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
716 float dot, angle, facing;
719 /* this is expensive */
720 for ( i = 0; i < w->numpoints; i++ )
722 VectorSubtract( w->p[ i ], point, dirs[ i ] );
723 VectorFastNormalize( dirs[ i ], dirs[ i ] );
726 /* duplicate first vertex to avoid mod operation */
727 VectorCopy( dirs[ 0 ], dirs[ i ] );
729 /* calculcate relative area */
731 for ( i = 0; i < w->numpoints; i++ )
735 dot = DotProduct( dirs[ i ], dirs[ j ] );
737 /* roundoff can cause slight creep, which gives an IND from acos */
741 else if ( dot < -1.0f ) {
748 CrossProduct( dirs[ i ], dirs[ j ], triVector );
749 if ( VectorFastNormalize( triVector, triNormal ) < 0.0001f ) {
753 facing = DotProduct( normal, triNormal );
754 total += facing * angle;
756 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
757 if ( total > 6.3f || total < -6.3f ) {
762 /* now in the range of 0 to 1 over the entire incoming hemisphere */
763 //% total /= (2.0f * 3.141592657f);
764 total *= ONE_OVER_2PI;
771 LightContributionTosample()
772 determines the amount of light reaching a sample (luxel or vertex) from a given light
775 int LightContributionToSample( trace_t *trace ){
780 float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
781 qboolean angledDeluxe = qtrue;
782 float colorBrightness;
783 qboolean doAddDeluxe = qtrue;
786 light = trace->light;
789 trace->forceSubsampling = 0.0f; /* to make sure */
790 VectorClear( trace->color );
791 VectorClear( trace->colorNoShadow );
792 VectorClear( trace->directionContribution );
794 colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f / 255.0f );
796 /* ydnar: early out */
797 if ( !( light->flags & LIGHT_SURFACES ) || light->envelope <= 0.0f ) {
801 /* do some culling checks */
802 if ( light->type != EMIT_SUN ) {
803 /* MrE: if the light is behind the surface */
804 if ( trace->twoSided == qfalse ) {
805 if ( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f ) {
810 /* ydnar: test pvs */
811 if ( !ClusterVisible( trace->cluster, light->cluster ) ) {
816 /* exact point to polygon form factor */
817 if ( light->type == EMIT_AREA ) {
822 /* project sample point into light plane */
823 d = DotProduct( trace->origin, light->normal ) - light->dist;
825 /* sample point behind plane? */
826 if ( !( light->flags & LIGHT_TWOSIDED ) && d < -1.0f ) {
830 /* sample plane coincident? */
831 if ( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f ) {
836 /* nudge the point so that it is clearly forward of the light */
837 /* so that surfaces meeting a light emitter don't get black edges */
838 if ( d > -8.0f && d < 8.0f ) {
839 VectorMA( trace->origin, ( 8.0f - d ), light->normal, pushedOrigin );
842 VectorCopy( trace->origin, pushedOrigin );
845 /* get direction and distance */
846 VectorCopy( light->origin, trace->end );
847 dist = SetupTrace( trace );
848 if ( dist >= light->envelope ) {
852 /* ptpff approximation */
854 /* angle attenuation */
855 angle = DotProduct( trace->normal, trace->direction );
857 /* twosided lighting */
858 if ( trace->twoSided && angle < 0 ) {
861 /* no deluxemap contribution from "other side" light */
862 doAddDeluxe = qfalse;
866 angle *= -DotProduct( light->normal, trace->direction );
867 if ( angle == 0.0f ) {
870 else if ( angle < 0.0f &&
871 ( trace->twoSided || ( light->flags & LIGHT_TWOSIDED ) ) ) {
874 /* no deluxemap contribution from "other side" light */
875 doAddDeluxe = qfalse;
878 /* clamp the distance to prevent super hot spots */
879 dist = sqrt( dist * dist + light->extraDist * light->extraDist );
880 if ( dist < 16.0f ) {
884 add = light->photons / ( dist * dist ) * angle;
887 if ( angledDeluxe ) {
888 addDeluxe = light->photons / ( dist * dist ) * angle;
891 addDeluxe = light->photons / ( dist * dist );
897 /* calculate the contribution */
898 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
899 if ( factor == 0.0f ) {
902 else if ( factor < 0.0f ) {
903 /* twosided lighting */
904 if ( trace->twoSided || ( light->flags & LIGHT_TWOSIDED ) ) {
907 /* push light origin to other side of the plane */
908 VectorMA( light->origin, -2.0f, light->normal, trace->end );
909 dist = SetupTrace( trace );
910 if ( dist >= light->envelope ) {
914 /* no deluxemap contribution from "other side" light */
915 doAddDeluxe = qfalse;
922 /* also don't deluxe if the direction is on the wrong side */
923 if ( DotProduct( trace->normal, trace->direction ) < 0 ) {
924 /* no deluxemap contribution from "other side" light */
925 doAddDeluxe = qfalse;
928 /* ydnar: moved to here */
929 add = factor * light->add;
937 /* point/spot lights */
938 else if ( light->type == EMIT_POINT || light->type == EMIT_SPOT ) {
939 /* get direction and distance */
940 VectorCopy( light->origin, trace->end );
941 dist = SetupTrace( trace );
942 if ( dist >= light->envelope ) {
946 /* clamp the distance to prevent super hot spots */
947 dist = sqrt( dist * dist + light->extraDist * light->extraDist );
948 if ( dist < 16.0f ) {
952 /* angle attenuation */
953 if ( light->flags & LIGHT_ATTEN_ANGLE ) {
954 /* standard Lambert attenuation */
955 float dot = DotProduct( trace->normal, trace->direction );
957 /* twosided lighting */
958 if ( trace->twoSided && dot < 0 ) {
961 /* no deluxemap contribution from "other side" light */
962 doAddDeluxe = qfalse;
965 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
966 if ( lightAngleHL ) {
967 if ( dot > 0.001f ) { // skip coplanar
971 dot = ( dot * 0.5f ) + 0.5f;
985 if ( light->angleScale != 0.0f ) {
986 angle /= light->angleScale;
987 if ( angle > 1.0f ) {
993 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
994 add = angle * light->photons * linearScale - ( dist * light->fade );
1000 if ( angledDeluxe ) {
1001 addDeluxe = angle * light->photons * linearScale - ( dist * light->fade );
1004 addDeluxe = light->photons * linearScale - ( dist * light->fade );
1007 if ( addDeluxe < 0.0f ) {
1014 add = ( light->photons / ( dist * dist ) ) * angle;
1020 if ( angledDeluxe ) {
1021 addDeluxe = ( light->photons / ( dist * dist ) ) * angle;
1024 addDeluxe = ( light->photons / ( dist * dist ) );
1028 if ( addDeluxe < 0.0f ) {
1033 /* handle spotlights */
1034 if ( light->type == EMIT_SPOT ) {
1035 float distByNormal, radiusAtDist, sampleRadius;
1036 vec3_t pointAtDist, distToSample;
1038 /* do cone calculation */
1039 distByNormal = -DotProduct( trace->displacement, light->normal );
1040 if ( distByNormal < 0.0f ) {
1043 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1044 radiusAtDist = light->radiusByDist * distByNormal;
1045 VectorSubtract( trace->origin, pointAtDist, distToSample );
1046 sampleRadius = VectorLength( distToSample );
1048 /* outside the cone */
1049 if ( sampleRadius >= radiusAtDist ) {
1054 if ( sampleRadius > ( radiusAtDist - 32.0f ) ) {
1055 add *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
1060 addDeluxe *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
1062 if ( addDeluxe < 0.0f ) {
1069 /* ydnar: sunlight */
1070 else if ( light->type == EMIT_SUN ) {
1071 /* get origin and direction */
1072 VectorAdd( trace->origin, light->origin, trace->end );
1073 dist = SetupTrace( trace );
1075 /* angle attenuation */
1076 if ( light->flags & LIGHT_ATTEN_ANGLE ) {
1077 /* standard Lambert attenuation */
1078 float dot = DotProduct( trace->normal, trace->direction );
1080 /* twosided lighting */
1081 if ( trace->twoSided && dot < 0 ) {
1084 /* no deluxemap contribution from "other side" light */
1085 doAddDeluxe = qfalse;
1088 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
1089 if ( lightAngleHL ) {
1090 if ( dot > 0.001f ) { // skip coplanar
1094 dot = ( dot * 0.5f ) + 0.5f;
1109 add = light->photons * angle;
1112 if ( angledDeluxe ) {
1113 addDeluxe = light->photons * angle;
1116 addDeluxe = light->photons;
1119 if ( addDeluxe < 0.0f ) {
1124 if ( add <= 0.0f ) {
1128 /* VorteX: set noShadow color */
1129 VectorScale( light->color, add, trace->colorNoShadow );
1131 addDeluxe *= colorBrightness;
1134 addDeluxe *= addDeluxeBounceScale;
1135 if ( addDeluxe < 0.00390625f ) {
1136 addDeluxe = 0.00390625f;
1140 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1143 trace->testAll = qtrue;
1144 VectorScale( light->color, add, trace->color );
1146 /* trace to point */
1147 if ( trace->testOcclusion && !trace->forceSunlight ) {
1150 trace->forceSubsampling *= add;
1151 if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) {
1152 VectorClear( trace->color );
1153 VectorClear( trace->directionContribution );
1159 /* return to sender */
1163 Error( "Light of undefined type!" );
1166 /* VorteX: set noShadow color */
1167 VectorScale( light->color, add, trace->colorNoShadow );
1169 /* ydnar: changed to a variable number */
1170 if ( add <= 0.0f || ( add <= light->falloffTolerance && ( light->flags & LIGHT_FAST_ACTUAL ) ) ) {
1174 addDeluxe *= colorBrightness;
1176 /* hack land: scale down the radiosity contribution to light directionality.
1177 Deluxemaps fusion many light directions into one. In a rtl process all lights
1178 would contribute individually to the bump map, so several light sources together
1179 would make it more directional (example: a yellow and red lights received from
1180 opposing sides would light one side in red and the other in blue, adding
1181 the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
1182 neutralize each other making it look like having no direction.
1183 Same thing happens with radiosity. In deluxemapping case the radiosity contribution
1184 is modifying the direction applied from directional lights, making it go closer and closer
1185 to the surface normal the bigger is the amount of radiosity received.
1186 So, for preserving the directional lights contributions, we scale down the radiosity
1187 contribution. It's a hack, but there's a reason behind it */
1189 addDeluxe *= addDeluxeBounceScale;
1190 /* better NOT increase it beyond the original value
1191 if( addDeluxe < 0.00390625f )
1192 addDeluxe = 0.00390625f;
1196 if ( doAddDeluxe ) {
1197 VectorScale( trace->direction, addDeluxe, trace->directionContribution );
1201 trace->testAll = qfalse;
1202 VectorScale( light->color, add, trace->color );
1206 trace->forceSubsampling *= add;
1207 if ( trace->passSolid || trace->opaque ) {
1208 VectorClear( trace->color );
1209 VectorClear( trace->directionContribution );
1214 /* return to sender */
1222 determines the amount of light reaching a sample (luxel or vertex)
1225 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] ){
1230 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1231 VectorClear( colors[ lightmapNum ] );
1233 /* ydnar: normalmap */
1235 colors[ 0 ][ 0 ] = ( trace->normal[ 0 ] + 1.0f ) * 127.5f;
1236 colors[ 0 ][ 1 ] = ( trace->normal[ 1 ] + 1.0f ) * 127.5f;
1237 colors[ 0 ][ 2 ] = ( trace->normal[ 2 ] + 1.0f ) * 127.5f;
1241 /* ydnar: don't bounce ambient all the time */
1243 VectorCopy( ambientColor, colors[ 0 ] );
1246 /* ydnar: trace to all the list of lights pre-stored in tw */
1247 for ( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1250 trace->light = trace->lights[ i ];
1253 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1255 if ( styles[ lightmapNum ] == trace->light->style ||
1256 styles[ lightmapNum ] == LS_NONE ) {
1261 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1262 if ( lightmapNum >= MAX_LIGHTMAPS ) {
1267 LightContributionToSample( trace );
1268 if ( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f ) {
1272 /* handle negative light */
1273 if ( trace->light->flags & LIGHT_NEGATIVE ) {
1274 VectorScale( trace->color, -1.0f, trace->color );
1278 styles[ lightmapNum ] = trace->light->style;
1281 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1285 colors[ 0 ][ 0 ] >= 255.0f &&
1286 colors[ 0 ][ 1 ] >= 255.0f &&
1287 colors[ 0 ][ 2 ] >= 255.0f ) {
1296 LightContributionToPoint()
1297 for a given light, how much light/color reaches a given point in space (with no facing)
1298 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1301 int LightContributionToPoint( trace_t *trace ){
1307 light = trace->light;
1310 VectorClear( trace->color );
1312 /* ydnar: early out */
1313 if ( !( light->flags & LIGHT_GRID ) || light->envelope <= 0.0f ) {
1317 /* is this a sun? */
1318 if ( light->type != EMIT_SUN ) {
1325 if ( !ClusterVisible( trace->cluster, light->cluster ) ) {
1330 /* ydnar: check origin against light's pvs envelope */
1331 if ( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1332 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1333 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] ) {
1338 /* set light origin */
1339 if ( light->type == EMIT_SUN ) {
1340 VectorAdd( trace->origin, light->origin, trace->end );
1343 VectorCopy( light->origin, trace->end );
1347 dist = SetupTrace( trace );
1350 if ( dist > light->envelope ) {
1351 gridEnvelopeCulled++;
1355 /* ptpff approximation */
1356 if ( light->type == EMIT_AREA && faster ) {
1357 /* clamp the distance to prevent super hot spots */
1358 dist = sqrt( dist * dist + light->extraDist * light->extraDist );
1359 if ( dist < 16.0f ) {
1364 add = light->photons / ( dist * dist );
1367 /* exact point to polygon form factor */
1368 else if ( light->type == EMIT_AREA ) {
1370 vec3_t pushedOrigin;
1373 /* see if the point is behind the light */
1374 d = DotProduct( trace->origin, light->normal ) - light->dist;
1375 if ( !( light->flags & LIGHT_TWOSIDED ) && d < -1.0f ) {
1379 /* nudge the point so that it is clearly forward of the light */
1380 /* so that surfaces meeting a light emiter don't get black edges */
1381 if ( d > -8.0f && d < 8.0f ) {
1382 VectorMA( trace->origin, ( 8.0f - d ), light->normal, pushedOrigin );
1385 VectorCopy( trace->origin, pushedOrigin );
1388 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1389 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1390 if ( factor == 0.0f ) {
1393 else if ( factor < 0.0f ) {
1394 if ( light->flags & LIGHT_TWOSIDED ) {
1402 /* ydnar: moved to here */
1403 add = factor * light->add;
1406 /* point/spot lights */
1407 else if ( light->type == EMIT_POINT || light->type == EMIT_SPOT ) {
1408 /* clamp the distance to prevent super hot spots */
1409 dist = sqrt( dist * dist + light->extraDist * light->extraDist );
1410 if ( dist < 16.0f ) {
1415 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
1416 add = light->photons * linearScale - ( dist * light->fade );
1422 add = light->photons / ( dist * dist );
1425 /* handle spotlights */
1426 if ( light->type == EMIT_SPOT ) {
1427 float distByNormal, radiusAtDist, sampleRadius;
1428 vec3_t pointAtDist, distToSample;
1431 /* do cone calculation */
1432 distByNormal = -DotProduct( trace->displacement, light->normal );
1433 if ( distByNormal < 0.0f ) {
1436 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1437 radiusAtDist = light->radiusByDist * distByNormal;
1438 VectorSubtract( trace->origin, pointAtDist, distToSample );
1439 sampleRadius = VectorLength( distToSample );
1441 /* outside the cone */
1442 if ( sampleRadius >= radiusAtDist ) {
1447 if ( sampleRadius > ( radiusAtDist - 32.0f ) ) {
1448 add *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
1453 /* ydnar: sunlight */
1454 else if ( light->type == EMIT_SUN ) {
1456 add = light->photons;
1457 if ( add <= 0.0f ) {
1462 trace->testAll = qtrue;
1463 VectorScale( light->color, add, trace->color );
1465 /* trace to point */
1466 if ( trace->testOcclusion && !trace->forceSunlight ) {
1469 if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) {
1470 VectorClear( trace->color );
1475 /* return to sender */
1479 /* unknown light type */
1484 /* ydnar: changed to a variable number */
1485 if ( add <= 0.0f || ( add <= light->falloffTolerance && ( light->flags & LIGHT_FAST_ACTUAL ) ) ) {
1490 trace->testAll = qfalse;
1491 VectorScale( light->color, add, trace->color );
1495 if ( trace->passSolid ) {
1496 VectorClear( trace->color );
1500 /* we have a valid sample */
1508 grid samples are for quickly determining the lighting
1509 of dynamically placed entities in the world
1512 #define MAX_CONTRIBUTIONS 32768
1523 void TraceGrid( int num ){
1524 int i, j, x, y, z, mod, numCon, numStyles;
1526 vec3_t baseOrigin, cheapColor, color, thisdir;
1528 bspGridPoint_t *bgp;
1529 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1532 /* get grid points */
1533 gp = &rawGridPoints[ num ];
1534 bgp = &bspGridPoints[ num ];
1536 /* get grid origin */
1538 z = mod / ( gridBounds[ 0 ] * gridBounds[ 1 ] );
1539 mod -= z * ( gridBounds[ 0 ] * gridBounds[ 1 ] );
1540 y = mod / gridBounds[ 0 ];
1541 mod -= y * gridBounds[ 0 ];
1544 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1545 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1546 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1548 /* set inhibit sphere */
1549 if ( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] ) {
1550 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1552 else if ( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] ) {
1553 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1556 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1559 /* find point cluster */
1560 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1561 if ( trace.cluster < 0 ) {
1562 /* try to nudge the origin around to find a valid point */
1563 VectorCopy( trace.origin, baseOrigin );
1564 for ( step = 0; ( step += 0.005 ) <= 1.0; )
1566 VectorCopy( baseOrigin, trace.origin );
1567 trace.origin[ 0 ] += step * ( Random() - 0.5 ) * gridSize[0];
1568 trace.origin[ 1 ] += step * ( Random() - 0.5 ) * gridSize[1];
1569 trace.origin[ 2 ] += step * ( Random() - 0.5 ) * gridSize[2];
1571 /* ydnar: changed to find cluster num */
1572 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1573 if ( trace.cluster >= 0 ) {
1578 /* can't find a valid point at all */
1585 trace.testOcclusion = !noTrace;
1586 trace.forceSunlight = qfalse;
1587 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1588 trace.numSurfaces = 0;
1589 trace.surfaces = NULL;
1590 trace.numLights = 0;
1591 trace.lights = NULL;
1595 VectorClear( cheapColor );
1597 /* trace to all the lights, find the major light direction, and divide the
1598 total light between that along the direction and the remaining in the ambient */
1599 for ( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1605 if ( !LightContributionToPoint( &trace ) ) {
1609 /* handle negative light */
1610 if ( trace.light->flags & LIGHT_NEGATIVE ) {
1611 VectorScale( trace.color, -1.0f, trace.color );
1614 /* add a contribution */
1615 VectorCopy( trace.color, contributions[ numCon ].color );
1616 VectorCopy( trace.direction, contributions[ numCon ].dir );
1617 VectorClear( contributions[ numCon ].ambient );
1618 contributions[ numCon ].style = trace.light->style;
1621 /* push average direction around */
1622 addSize = VectorLength( trace.color );
1623 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1625 /* stop after a while */
1626 if ( numCon >= ( MAX_CONTRIBUTIONS - 1 ) ) {
1630 /* ydnar: cheap mode */
1631 VectorAdd( cheapColor, trace.color, cheapColor );
1632 if ( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f ) {
1637 /////// Floodlighting for point //////////////////
1638 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1639 if ( floodlighty ) {
1642 vec3_t dir = { 0, 0, 1 };
1643 float ambientFrac = 0.25f;
1645 trace.testOcclusion = qtrue;
1646 trace.forceSunlight = qfalse;
1647 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1648 trace.testAll = qtrue;
1650 for ( k = 0; k < 2; k++ )
1652 if ( k == 0 ) { // upper hemisphere
1653 trace.normal[0] = 0;
1654 trace.normal[1] = 0;
1655 trace.normal[2] = 1;
1657 else //lower hemisphere
1659 trace.normal[0] = 0;
1660 trace.normal[1] = 0;
1661 trace.normal[2] = -1;
1664 f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
1666 /* add a fraction as pure ambient, half as top-down direction */
1667 contributions[ numCon ].color[0] = floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1668 contributions[ numCon ].color[1] = floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1669 contributions[ numCon ].color[2] = floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
1671 contributions[ numCon ].ambient[0] = floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
1672 contributions[ numCon ].ambient[1] = floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
1673 contributions[ numCon ].ambient[2] = floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
1675 contributions[ numCon ].dir[0] = dir[0];
1676 contributions[ numCon ].dir[1] = dir[1];
1677 contributions[ numCon ].dir[2] = dir[2];
1679 contributions[ numCon ].style = 0;
1681 /* push average direction around */
1682 addSize = VectorLength( contributions[ numCon ].color );
1683 VectorMA( gp->dir, addSize, dir, gp->dir );
1688 /////////////////////
1690 /* normalize to get primary light direction */
1691 VectorNormalize( gp->dir, thisdir );
1693 /* now that we have identified the primary light direction,
1694 go back and separate all the light into directed and ambient */
1697 for ( i = 0; i < numCon; i++ )
1699 /* get relative directed strength */
1700 d = DotProduct( contributions[ i ].dir, thisdir );
1701 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1702 d = gridAmbientDirectionality + d * ( gridDirectionality - gridAmbientDirectionality );
1707 /* find appropriate style */
1708 for ( j = 0; j < numStyles; j++ )
1710 if ( gp->styles[ j ] == contributions[ i ].style ) {
1715 /* style not found? */
1716 if ( j >= numStyles ) {
1717 /* add a new style */
1718 if ( numStyles < MAX_LIGHTMAPS ) {
1719 gp->styles[ numStyles ] = contributions[ i ].style;
1720 bgp->styles[ numStyles ] = contributions[ i ].style;
1722 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1731 /* add the directed color */
1732 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1734 /* ambient light will be at 1/4 the value of directed light */
1735 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1736 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1738 /* (Hobbes: always setting it to .25 is hardly any better) */
1739 d = 0.25f * ( 1.0f - d );
1740 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1742 VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
1746 * the total light average = ambient value + 0.25 * sum of all directional values
1747 * we can also get the total light average as 0.25 * the sum of all contributions
1749 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1752 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1754 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1759 /* store off sample */
1760 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
1763 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1765 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1769 /* set minimum light and copy off to bytes */
1770 VectorCopy( gp->ambient[ i ], color );
1771 for ( j = 0; j < 3; j++ )
1772 if ( color[ j ] < minGridLight[ j ] ) {
1773 color[ j ] = minGridLight[ j ];
1776 /* vortex: apply gridscale and gridambientscale here */
1777 ColorToBytes( color, bgp->ambient[ i ], gridScale * gridAmbientScale );
1778 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1783 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1784 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1786 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1787 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1790 /* store direction */
1791 NormalToLatLong( thisdir, bgp->latLong );
1798 calculates the size of the lightgrid and allocates memory
1801 void SetupGrid( void ){
1803 vec3_t maxs, oldGridSize;
1808 /* don't do this if not grid lighting */
1809 if ( noGridLighting ) {
1813 /* ydnar: set grid size */
1814 value = ValueForKey( &entities[ 0 ], "gridsize" );
1815 if ( value[ 0 ] != '\0' ) {
1816 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1820 VectorCopy( gridSize, oldGridSize );
1821 for ( i = 0; i < 3; i++ )
1822 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1824 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1825 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1827 while ( numRawGridPoints > MAX_MAP_LIGHTGRID )
1829 /* get world bounds */
1830 for ( i = 0; i < 3; i++ )
1832 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1833 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1834 gridBounds[ i ] = ( maxs[ i ] - gridMins[ i ] ) / gridSize[ i ] + 1;
1838 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1840 /* increase grid size a bit */
1841 if ( numRawGridPoints > MAX_MAP_LIGHTGRID ) {
1842 gridSize[ j++ % 3 ] += 16.0f;
1847 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1850 if ( !VectorCompare( gridSize, oldGridSize ) ) {
1851 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1852 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1853 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1856 /* 2nd variable. fixme: is this silly? */
1857 numBSPGridPoints = numRawGridPoints;
1859 /* allocate lightgrid */
1860 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1861 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1863 if ( bspGridPoints != NULL ) {
1864 free( bspGridPoints );
1866 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1867 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1869 /* clear lightgrid */
1870 for ( i = 0; i < numRawGridPoints; i++ )
1872 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1873 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1874 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1875 for ( j = 1; j < MAX_LIGHTMAPS; j++ )
1877 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1878 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1883 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1890 does what it says...
1893 void LightWorld( qboolean fastAllocate ){
1897 qboolean minVertex, minGrid;
1901 /* ydnar: smooth normals */
1903 Sys_Printf( "--- SmoothNormals ---\n" );
1907 /* determine the number of grid points */
1908 Sys_Printf( "--- SetupGrid ---\n" );
1911 /* find the optional minimum lighting values */
1912 GetVectorForKey( &entities[ 0 ], "_color", color );
1914 color[0] = Image_LinearFloatFromsRGBFloat( color[0] );
1915 color[1] = Image_LinearFloatFromsRGBFloat( color[1] );
1916 color[2] = Image_LinearFloatFromsRGBFloat( color[2] );
1918 if ( VectorLength( color ) == 0.0f ) {
1919 VectorSet( color, 1.0, 1.0, 1.0 );
1923 f = FloatForKey( &entities[ 0 ], "_ambient" );
1925 f = FloatForKey( &entities[ 0 ], "ambient" );
1927 VectorScale( color, f, ambientColor );
1929 /* minvertexlight */
1931 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1932 if ( value[ 0 ] != '\0' ) {
1935 VectorScale( color, f, minVertexLight );
1940 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1941 if ( value[ 0 ] != '\0' ) {
1944 VectorScale( color, f, minGridLight );
1948 value = ValueForKey( &entities[ 0 ], "_minlight" );
1949 if ( value[ 0 ] != '\0' ) {
1951 VectorScale( color, f, minLight );
1952 if ( minVertex == qfalse ) {
1953 VectorScale( color, f, minVertexLight );
1955 if ( minGrid == qfalse ) {
1956 VectorScale( color, f, minGridLight );
1960 /* create world lights */
1961 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1962 CreateEntityLights();
1963 CreateSurfaceLights();
1964 Sys_Printf( "%9d point lights\n", numPointLights );
1965 Sys_Printf( "%9d spotlights\n", numSpotLights );
1966 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1967 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1969 /* calculate lightgrid */
1970 if ( !noGridLighting ) {
1971 /* ydnar: set up light envelopes */
1972 SetupEnvelopes( qtrue, fastgrid );
1974 Sys_Printf( "--- TraceGrid ---\n" );
1976 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1978 Sys_Printf( "%d x %d x %d = %d grid\n",
1979 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1981 /* ydnar: emit statistics on light culling */
1982 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1983 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1986 /* slight optimization to remove a sqrt */
1987 subdivideThreshold *= subdivideThreshold;
1989 /* map the world luxels */
1990 Sys_Printf( "--- MapRawLightmap ---\n" );
1991 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1992 Sys_Printf( "%9d luxels\n", numLuxels );
1993 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1994 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1998 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1999 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
2002 /* floodlight pass */
2003 FloodlightRawLightmaps();
2005 /* ydnar: set up light envelopes */
2006 SetupEnvelopes( qfalse, fast );
2008 /* light up my world */
2009 lightsPlaneCulled = 0;
2010 lightsEnvelopeCulled = 0;
2011 lightsBoundsCulled = 0;
2012 lightsClusterCulled = 0;
2014 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2015 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2016 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2018 StitchSurfaceLightmaps();
2020 Sys_Printf( "--- IlluminateVertexes ---\n" );
2021 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2022 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2024 /* ydnar: emit statistics on light culling */
2025 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2026 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2027 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2028 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2033 while ( bounce > 0 )
2035 /* store off the bsp between bounces */
2036 StoreSurfaceLightmaps( fastAllocate );
2038 Sys_Printf( "Writing %s\n", source );
2039 WriteBSPFile( source );
2042 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
2046 VectorClear( ambientColor );
2047 floodlighty = qfalse;
2049 /* generate diffuse lights */
2051 RadCreateDiffuseLights();
2053 /* setup light envelopes */
2054 SetupEnvelopes( qfalse, fastbounce );
2055 if ( numLights == 0 ) {
2056 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
2060 /* add to lightgrid */
2062 gridEnvelopeCulled = 0;
2063 gridBoundsCulled = 0;
2065 Sys_Printf( "--- BounceGrid ---\n" );
2067 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
2069 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
2070 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
2073 /* light up my world */
2074 lightsPlaneCulled = 0;
2075 lightsEnvelopeCulled = 0;
2076 lightsBoundsCulled = 0;
2077 lightsClusterCulled = 0;
2079 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
2080 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
2081 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
2082 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2084 StitchSurfaceLightmaps();
2086 Sys_Printf( "--- IlluminateVertexes ---\n" );
2087 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
2088 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
2090 /* ydnar: emit statistics on light culling */
2091 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
2092 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
2093 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
2094 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
2106 main routine for light processing
2109 int LightMain( int argc, char **argv ){
2112 char mapSource[ 1024 ];
2114 int lightmapMergeSize = 0;
2115 qboolean lightSamplesInsist = qfalse;
2116 qboolean fastAllocate = qtrue;
2120 Sys_Printf( "--- Light ---\n" );
2121 Sys_Printf( "--- ProcessGameSpecific ---\n" );
2123 /* set standard game flags */
2124 wolfLight = game->wolfLight;
2125 if ( wolfLight == qtrue ) {
2126 Sys_Printf( " lightning model: wolf\n" );
2129 Sys_Printf( " lightning model: quake3\n" );
2132 lmCustomSize = game->lightmapSize;
2133 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
2135 lightmapGamma = game->lightmapGamma;
2136 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
2138 lightmapsRGB = game->lightmapsRGB;
2139 if ( lightmapsRGB ) {
2140 Sys_Printf( " lightmap colorspace: sRGB\n" );
2143 Sys_Printf( " lightmap colorspace: linear\n" );
2146 texturesRGB = game->texturesRGB;
2147 if ( texturesRGB ) {
2148 Sys_Printf( " texture colorspace: sRGB\n" );
2151 Sys_Printf( " texture colorspace: linear\n" );
2154 colorsRGB = game->colorsRGB;
2156 Sys_Printf( " _color colorspace: sRGB\n" );
2159 Sys_Printf( " _color colorspace: linear\n" );
2162 lightmapCompensate = game->lightmapCompensate;
2163 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
2165 lightmapExposure = game->lightmapExposure;
2166 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
2168 gridScale = game->gridScale;
2169 Sys_Printf( " lightgrid scale: %f\n", gridScale );
2171 gridAmbientScale = game->gridAmbientScale;
2172 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
2174 lightAngleHL = game->lightAngleHL;
2175 if ( lightAngleHL ) {
2176 Sys_Printf( " half lambert light angle attenuation enabled \n" );
2179 noStyles = game->noStyles;
2180 if ( noStyles == qtrue ) {
2181 Sys_Printf( " shader lightstyles hack: disabled\n" );
2184 Sys_Printf( " shader lightstyles hack: enabled\n" );
2187 patchShadows = game->patchShadows;
2188 if ( patchShadows == qtrue ) {
2189 Sys_Printf( " patch shadows: enabled\n" );
2192 Sys_Printf( " patch shadows: disabled\n" );
2195 deluxemap = game->deluxeMap;
2196 deluxemode = game->deluxeMode;
2197 if ( deluxemap == qtrue ) {
2199 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
2202 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
2206 Sys_Printf( " deluxemapping: disabled\n" );
2209 Sys_Printf( "--- ProcessCommandLine ---\n" );
2211 /* process commandline arguments */
2212 for ( i = 1; i < ( argc - 1 ); i++ )
2214 /* lightsource scaling */
2215 if ( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) ) {
2216 f = atof( argv[ i + 1 ] );
2219 Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2220 Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2224 else if ( !strcmp( argv[ i ], "-spherical" ) || !strcmp( argv[ i ], "-sphericalscale" ) ) {
2225 f = atof( argv[ i + 1 ] );
2227 Sys_Printf( "Spherical point (entity) light scaled by %f to %f\n", f, pointScale );
2231 else if ( !strcmp( argv[ i ], "-spot" ) || !strcmp( argv[ i ], "-spotscale" ) ) {
2232 f = atof( argv[ i + 1 ] );
2234 Sys_Printf( "Spot point (entity) light scaled by %f to %f\n", f, spotScale );
2238 else if ( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) ) {
2239 f = atof( argv[ i + 1 ] );
2241 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
2245 else if ( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) ) {
2246 f = atof( argv[ i + 1 ] );
2248 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
2252 else if ( !strcmp( argv[ i ], "-vertexscale" ) ) {
2253 f = atof( argv[ i + 1 ] );
2254 vertexglobalscale *= f;
2255 Sys_Printf( "Vertexlight scaled by %f to %f\n", f, vertexglobalscale );
2259 else if ( !strcmp( argv[ i ], "-backsplash" ) && i < ( argc - 3 ) ) {
2260 f = atof( argv[ i + 1 ] );
2261 g_backsplashFractionScale = f;
2262 Sys_Printf( "Area lights backsplash fraction scaled by %f\n", f, g_backsplashFractionScale );
2263 f = atof( argv[ i + 2 ] );
2264 if ( f >= -900.0f ){
2265 g_backsplashDistance = f;
2266 Sys_Printf( "Area lights backsplash distance set globally to %f\n", f, g_backsplashDistance );
2271 else if ( !strcmp( argv[ i ], "-nolm" ) ) {
2273 Sys_Printf( "No lightmaps yo\n" );
2276 else if ( !strcmp( argv[ i ], "-bouncecolorratio" ) ) {
2277 f = atof( argv[ i + 1 ] );
2278 bounceColorRatio *= f;
2279 if ( bounceColorRatio > 1 ) {
2280 bounceColorRatio = 1;
2282 if ( bounceColorRatio < 0 ) {
2283 bounceColorRatio = 0;
2285 Sys_Printf( "Bounce color ratio set to %f\n", bounceColorRatio );
2289 else if ( !strcmp( argv[ i ], "-bouncescale" ) ) {
2290 f = atof( argv[ i + 1 ] );
2292 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2296 else if ( !strcmp( argv[ i ], "-scale" ) ) {
2297 f = atof( argv[ i + 1 ] );
2303 Sys_Printf( "All light scaled by %f\n", f );
2307 else if ( !strcmp( argv[ i ], "-gridscale" ) ) {
2308 f = atof( argv[ i + 1 ] );
2309 Sys_Printf( "Grid lightning scaled by %f\n", f );
2314 else if ( !strcmp( argv[ i ], "-gridambientscale" ) ) {
2315 f = atof( argv[ i + 1 ] );
2316 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2317 gridAmbientScale *= f;
2321 else if ( !strcmp( argv[ i ], "-griddirectionality" ) ) {
2322 f = atof( argv[ i + 1 ] );
2326 if ( f < gridAmbientDirectionality ) {
2327 gridAmbientDirectionality = f;
2329 Sys_Printf( "Grid directionality is %f\n", f );
2330 gridDirectionality = f;
2334 else if ( !strcmp( argv[ i ], "-gridambientdirectionality" ) ) {
2335 f = atof( argv[ i + 1 ] );
2339 if ( f > gridDirectionality ) {
2340 gridDirectionality = f;
2342 Sys_Printf( "Grid ambient directionality is %f\n", f );
2343 gridAmbientDirectionality = f;
2347 else if ( !strcmp( argv[ i ], "-gamma" ) ) {
2348 f = atof( argv[ i + 1 ] );
2350 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2354 else if ( !strcmp( argv[ i ], "-sRGBlight" ) ) {
2355 lightmapsRGB = qtrue;
2356 Sys_Printf( "Lighting is in sRGB\n" );
2359 else if ( !strcmp( argv[ i ], "-nosRGBlight" ) ) {
2360 lightmapsRGB = qfalse;
2361 Sys_Printf( "Lighting is linear\n" );
2364 else if ( !strcmp( argv[ i ], "-sRGBtex" ) ) {
2365 texturesRGB = qtrue;
2366 Sys_Printf( "Textures are in sRGB\n" );
2369 else if ( !strcmp( argv[ i ], "-nosRGBtex" ) ) {
2370 texturesRGB = qfalse;
2371 Sys_Printf( "Textures are linear\n" );
2374 else if ( !strcmp( argv[ i ], "-sRGBcolor" ) ) {
2376 Sys_Printf( "Colors are in sRGB\n" );
2379 else if ( !strcmp( argv[ i ], "-nosRGBcolor" ) ) {
2381 Sys_Printf( "Colors are linear\n" );
2384 else if ( !strcmp( argv[ i ], "-sRGB" ) ) {
2385 lightmapsRGB = qtrue;
2386 Sys_Printf( "Lighting is in sRGB\n" );
2387 texturesRGB = qtrue;
2388 Sys_Printf( "Textures are in sRGB\n" );
2390 Sys_Printf( "Colors are in sRGB\n" );
2393 else if ( !strcmp( argv[ i ], "-nosRGB" ) ) {
2394 lightmapsRGB = qfalse;
2395 Sys_Printf( "Lighting is linear\n" );
2396 texturesRGB = qfalse;
2397 Sys_Printf( "Textures are linear\n" );
2399 Sys_Printf( "Colors are linear\n" );
2402 else if ( !strcmp( argv[ i ], "-exposure" ) ) {
2403 f = atof( argv[ i + 1 ] );
2404 lightmapExposure = f;
2405 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2409 else if ( !strcmp( argv[ i ], "-compensate" ) ) {
2410 f = atof( argv[ i + 1 ] );
2414 lightmapCompensate = f;
2415 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2419 /* Lighting brightness */
2420 else if( !strcmp( argv[ i ], "-brightness" ) ){
2421 f = atof( argv[ i + 1 ] );
2422 lightmapBrightness = f;
2423 Sys_Printf( "Lighting brightness set to %f\n", lightmapBrightness );
2427 /* Lighting contrast */
2428 else if( !strcmp( argv[ i ], "-contrast" ) ){
2429 f = atof( argv[ i + 1 ] );
2430 lightmapContrast = f;
2431 if( lightmapContrast > 255 ){
2432 lightmapContrast = 255;
2434 else if( lightmapContrast < -255 ){
2435 lightmapContrast = -255;
2437 Sys_Printf( "Lighting contrast set to %f\n", lightmapContrast );
2439 /* change to factor in range of 0 to 129.5 */
2440 lightmapContrast = ( 259 * ( lightmapContrast + 255 ) ) / ( 255 * ( 259 - lightmapContrast ) );
2443 /* ydnar switches */
2444 else if ( !strcmp( argv[ i ], "-bounce" ) ) {
2445 bounce = atoi( argv[ i + 1 ] );
2449 else if ( bounce > 0 ) {
2450 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2455 else if ( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) ) {
2456 superSample = atoi( argv[ i + 1 ] );
2457 if ( superSample < 1 ) {
2460 else if ( superSample > 1 ) {
2461 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", ( superSample * superSample ) );
2466 else if ( !strcmp( argv[ i ], "-randomsamples" ) ) {
2467 lightRandomSamples = qtrue;
2468 Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
2471 else if ( !strcmp( argv[ i ], "-samples" ) ) {
2472 if ( *argv[i + 1] == '+' ) {
2473 lightSamplesInsist = qtrue;
2476 lightSamplesInsist = qfalse;
2478 lightSamples = atoi( argv[ i + 1 ] );
2479 if ( lightSamples < 1 ) {
2482 else if ( lightSamples > 1 ) {
2483 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2488 else if ( !strcmp( argv[ i ], "-samplessearchboxsize" ) ) {
2489 lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
2490 if ( lightSamplesSearchBoxSize <= 0 ) {
2491 lightSamplesSearchBoxSize = 1;
2493 if ( lightSamplesSearchBoxSize > 4 ) {
2494 lightSamplesSearchBoxSize = 4; /* more makes no sense */
2496 else if ( lightSamplesSearchBoxSize != 1 ) {
2497 Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
2502 else if ( !strcmp( argv[ i ], "-filter" ) ) {
2504 Sys_Printf( "Lightmap filtering enabled\n" );
2507 else if ( !strcmp( argv[ i ], "-dark" ) ) {
2509 Sys_Printf( "Dark lightmap seams enabled\n" );
2512 else if ( !strcmp( argv[ i ], "-shadeangle" ) ) {
2513 shadeAngleDegrees = atof( argv[ i + 1 ] );
2514 if ( shadeAngleDegrees < 0.0f ) {
2515 shadeAngleDegrees = 0.0f;
2517 else if ( shadeAngleDegrees > 0.0f ) {
2519 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2524 else if ( !strcmp( argv[ i ], "-thresh" ) ) {
2525 subdivideThreshold = atof( argv[ i + 1 ] );
2526 if ( subdivideThreshold < 0 ) {
2527 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2530 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2535 else if ( !strcmp( argv[ i ], "-approx" ) ) {
2536 approximateTolerance = atoi( argv[ i + 1 ] );
2537 if ( approximateTolerance < 0 ) {
2538 approximateTolerance = 0;
2540 else if ( approximateTolerance > 0 ) {
2541 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2545 else if ( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) ) {
2547 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2549 else if ( !strcmp( argv[ i ], "-deluxemode" ) ) {
2550 deluxemode = atoi( argv[ i + 1 ] );
2551 if ( deluxemode == 0 || deluxemode > 1 || deluxemode < 0 ) {
2552 Sys_Printf( "Generating modelspace deluxemaps\n" );
2556 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2560 else if ( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) ) {
2562 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2564 else if ( !strcmp( argv[ i ], "-external" ) ) {
2565 externalLightmaps = qtrue;
2566 Sys_Printf( "Storing all lightmaps externally\n" );
2569 else if ( !strcmp( argv[ i ], "-lightmapsize" ) ) {
2570 lmCustomSize = atoi( argv[ i + 1 ] );
2572 /* must be a power of 2 and greater than 2 */
2573 if ( ( ( lmCustomSize - 1 ) & lmCustomSize ) || lmCustomSize < 2 ) {
2574 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2575 lmCustomSize = game->lightmapSize;
2578 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2580 /* enable external lightmaps */
2581 if ( lmCustomSize != game->lightmapSize ) {
2582 externalLightmaps = qtrue;
2583 Sys_Printf( "Storing all lightmaps externally\n" );
2587 else if ( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) ) {
2588 lmLimitSize = atoi( argv[ i + 1 ] );
2591 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2594 else if ( !strcmp( argv[ i ], "-lightmapdir" ) ) {
2595 lmCustomDir = argv[i + 1];
2597 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2598 externalLightmaps = qtrue;
2599 Sys_Printf( "Storing all lightmaps externally\n" );
2602 /* ydnar: add this to suppress warnings */
2603 else if ( !strcmp( argv[ i ], "-custinfoparms" ) ) {
2604 Sys_Printf( "Custom info parms enabled\n" );
2605 useCustomInfoParms = qtrue;
2608 else if ( !strcmp( argv[ i ], "-wolf" ) ) {
2609 /* -game should already be set */
2611 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2614 else if ( !strcmp( argv[ i ], "-q3" ) ) {
2615 /* -game should already be set */
2617 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2620 else if ( !strcmp( argv[ i ], "-extradist" ) ) {
2621 extraDist = atof( argv[ i + 1 ] );
2622 if ( extraDist < 0 ) {
2626 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2629 else if ( !strcmp( argv[ i ], "-sunonly" ) ) {
2631 Sys_Printf( "Only computing sunlight\n" );
2634 else if ( !strcmp( argv[ i ], "-bounceonly" ) ) {
2636 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2639 else if ( !strcmp( argv[ i ], "-nocollapse" ) ) {
2641 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2644 else if ( !strcmp( argv[ i ], "-nolightmapsearch" ) ) {
2645 lightmapSearchBlockSize = 1;
2646 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2649 else if ( !strcmp( argv[ i ], "-lightmapsearchpower" ) ) {
2650 lightmapMergeSize = ( game->lightmapSize << atoi( argv[i + 1] ) );
2652 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi( argv[i] ), lightmapMergeSize );
2655 else if ( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) ) {
2656 lightmapSearchBlockSize = atoi( argv[i + 1] );
2658 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2661 else if ( !strcmp( argv[ i ], "-shade" ) ) {
2663 Sys_Printf( "Phong shading enabled\n" );
2666 else if ( !strcmp( argv[ i ], "-bouncegrid" ) ) {
2669 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2673 else if ( !strcmp( argv[ i ], "-smooth" ) ) {
2674 lightSamples = EXTRA_SCALE;
2675 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2678 else if ( !strcmp( argv[ i ], "-nofastpoint" ) ) {
2680 Sys_Printf( "Automatic fast mode for point lights disabled\n" );
2683 else if ( !strcmp( argv[ i ], "-fast" ) ) {
2687 Sys_Printf( "Fast mode enabled for all area lights\n" );
2690 else if ( !strcmp( argv[ i ], "-faster" ) ) {
2695 Sys_Printf( "Faster mode enabled\n" );
2698 // else if ( !strcmp( argv[ i ], "-fastallocate" ) ) {
2699 // fastAllocate = qtrue;
2700 // Sys_Printf( "Fast allocation mode enabled\n" );
2702 else if ( !strcmp( argv[ i ], "-slowallocate" ) ) {
2703 fastAllocate = qfalse;
2704 Sys_Printf( "Slow allocation mode enabled\n" );
2707 else if ( !strcmp( argv[ i ], "-fastgrid" ) ) {
2709 Sys_Printf( "Fast grid lighting enabled\n" );
2712 else if ( !strcmp( argv[ i ], "-fastbounce" ) ) {
2714 Sys_Printf( "Fast bounce mode enabled\n" );
2717 else if ( !strcmp( argv[ i ], "-cheap" ) ) {
2720 Sys_Printf( "Cheap mode enabled\n" );
2723 else if ( !strcmp( argv[ i ], "-cheapgrid" ) ) {
2725 Sys_Printf( "Cheap grid mode enabled\n" );
2728 else if ( !strcmp( argv[ i ], "-normalmap" ) ) {
2730 Sys_Printf( "Storing normal map instead of lightmap\n" );
2733 else if ( !strcmp( argv[ i ], "-trisoup" ) ) {
2735 Sys_Printf( "Converting brush faces to triangle soup\n" );
2738 else if ( !strcmp( argv[ i ], "-debug" ) ) {
2740 Sys_Printf( "Lightmap debugging enabled\n" );
2743 else if ( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) ) {
2744 debugSurfaces = qtrue;
2745 Sys_Printf( "Lightmap surface debugging enabled\n" );
2748 else if ( !strcmp( argv[ i ], "-debugunused" ) ) {
2749 debugUnused = qtrue;
2750 Sys_Printf( "Unused luxel debugging enabled\n" );
2753 else if ( !strcmp( argv[ i ], "-debugaxis" ) ) {
2755 Sys_Printf( "Lightmap axis debugging enabled\n" );
2758 else if ( !strcmp( argv[ i ], "-debugcluster" ) ) {
2759 debugCluster = qtrue;
2760 Sys_Printf( "Luxel cluster debugging enabled\n" );
2763 else if ( !strcmp( argv[ i ], "-debugorigin" ) ) {
2764 debugOrigin = qtrue;
2765 Sys_Printf( "Luxel origin debugging enabled\n" );
2768 else if ( !strcmp( argv[ i ], "-debugdeluxe" ) ) {
2770 debugDeluxemap = qtrue;
2771 Sys_Printf( "Deluxemap debugging enabled\n" );
2774 else if ( !strcmp( argv[ i ], "-export" ) ) {
2775 exportLightmaps = qtrue;
2776 Sys_Printf( "Exporting lightmaps\n" );
2779 else if ( !strcmp( argv[ i ], "-notrace" ) ) {
2781 Sys_Printf( "Shadow occlusion disabled\n" );
2783 else if ( !strcmp( argv[ i ], "-patchshadows" ) ) {
2784 patchShadows = qtrue;
2785 Sys_Printf( "Patch shadow casting enabled\n" );
2787 else if ( !strcmp( argv[ i ], "-extra" ) ) {
2788 superSample = EXTRA_SCALE; /* ydnar */
2789 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2791 else if ( !strcmp( argv[ i ], "-extrawide" ) ) {
2792 superSample = EXTRAWIDE_SCALE; /* ydnar */
2793 filter = qtrue; /* ydnar */
2794 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n" );
2796 else if ( !strcmp( argv[ i ], "-samplesize" ) ) {
2797 sampleSize = atoi( argv[ i + 1 ] );
2798 if ( sampleSize < 1 ) {
2802 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2804 else if ( !strcmp( argv[ i ], "-minsamplesize" ) ) {
2805 minSampleSize = atoi( argv[ i + 1 ] );
2806 if ( minSampleSize < 1 ) {
2810 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2812 else if ( !strcmp( argv[ i ], "-samplescale" ) ) {
2813 sampleScale = atoi( argv[ i + 1 ] );
2815 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale );
2817 else if ( !strcmp( argv[ i ], "-debugsamplesize" ) ) {
2818 debugSampleSize = 1;
2819 Sys_Printf( "debugging Lightmaps SampleSize\n" );
2821 else if ( !strcmp( argv[ i ], "-novertex" ) ) {
2822 noVertexLighting = 1;
2823 if ( ( atof( argv[ i + 1 ] ) != 0 ) && ( atof( argv[ i + 1 ] )) < 1 ) {
2824 noVertexLighting = ( atof( argv[ i + 1 ] ) );
2826 Sys_Printf( "Setting vertex lighting globally to %f\n", noVertexLighting );
2829 Sys_Printf( "Disabling vertex lighting\n" );
2832 else if ( !strcmp( argv[ i ], "-nogrid" ) ) {
2833 noGridLighting = qtrue;
2834 Sys_Printf( "Disabling grid lighting\n" );
2836 else if ( !strcmp( argv[ i ], "-border" ) ) {
2837 lightmapBorder = qtrue;
2838 Sys_Printf( "Adding debug border to lightmaps\n" );
2840 else if ( !strcmp( argv[ i ], "-nosurf" ) ) {
2842 Sys_Printf( "Not tracing against surfaces\n" );
2844 else if ( !strcmp( argv[ i ], "-dump" ) ) {
2846 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2848 else if ( !strcmp( argv[ i ], "-lomem" ) ) {
2850 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2852 else if ( !strcmp( argv[ i ], "-lightanglehl" ) ) {
2853 if ( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL ) {
2854 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2855 if ( lightAngleHL ) {
2856 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2859 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2864 else if ( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) ) {
2866 Sys_Printf( "Disabling lightstyles\n" );
2868 else if ( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) ) {
2870 Sys_Printf( "Enabling lightstyles\n" );
2872 else if ( !strcmp( argv[ i ], "-cpma" ) ) {
2874 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2876 else if ( !strcmp( argv[ i ], "-floodlight" ) ) {
2877 floodlighty = qtrue;
2878 Sys_Printf( "FloodLighting enabled\n" );
2880 else if ( !strcmp( argv[ i ], "-debugnormals" ) ) {
2881 debugnormals = qtrue;
2882 Sys_Printf( "DebugNormals enabled\n" );
2884 else if ( !strcmp( argv[ i ], "-lowquality" ) ) {
2885 floodlight_lowquality = qtrue;
2886 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2889 /* r7: dirtmapping */
2890 else if ( !strcmp( argv[ i ], "-dirty" ) ) {
2892 Sys_Printf( "Dirtmapping enabled\n" );
2894 else if ( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) ) {
2896 Sys_Printf( "Dirtmap debugging enabled\n" );
2898 else if ( !strcmp( argv[ i ], "-dirtmode" ) ) {
2899 dirtMode = atoi( argv[ i + 1 ] );
2900 if ( dirtMode != 0 && dirtMode != 1 ) {
2903 if ( dirtMode == 1 ) {
2904 Sys_Printf( "Enabling randomized dirtmapping\n" );
2907 Sys_Printf( "Enabling ordered dirtmapping\n" );
2911 else if ( !strcmp( argv[ i ], "-dirtdepth" ) ) {
2912 dirtDepth = atof( argv[ i + 1 ] );
2913 if ( dirtDepth <= 0.0f ) {
2916 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2919 else if ( !strcmp( argv[ i ], "-dirtscale" ) ) {
2920 dirtScale = atof( argv[ i + 1 ] );
2921 if ( dirtScale <= 0.0f ) {
2924 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2927 else if ( !strcmp( argv[ i ], "-dirtgain" ) ) {
2928 dirtGain = atof( argv[ i + 1 ] );
2929 if ( dirtGain <= 0.0f ) {
2932 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2935 else if ( !strcmp( argv[ i ], "-trianglecheck" ) ) {
2936 lightmapTriangleCheck = qtrue;
2938 else if ( !strcmp( argv[ i ], "-extravisnudge" ) ) {
2939 lightmapExtraVisClusterNudge = qtrue;
2941 else if ( !strcmp( argv[ i ], "-fill" ) ) {
2942 lightmapFill = qtrue;
2943 Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
2945 /* unhandled args */
2948 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2953 /* fix up falloff tolerance for sRGB */
2954 if ( lightmapsRGB ) {
2955 falloffTolerance = Image_LinearFloatFromsRGBFloat( falloffTolerance * ( 1.0 / 255.0 ) ) * 255.0;
2958 /* fix up samples count */
2959 if ( lightRandomSamples ) {
2960 if ( !lightSamplesInsist ) {
2961 /* approximately match -samples in quality */
2962 switch ( lightSamples )
2968 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2974 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2980 Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
2988 /* fix up lightmap search power */
2989 if ( lightmapMergeSize ) {
2990 lightmapSearchBlockSize = ( lightmapMergeSize / lmCustomSize ) * ( lightmapMergeSize / lmCustomSize );
2991 if ( lightmapSearchBlockSize < 1 ) {
2992 lightmapSearchBlockSize = 1;
2995 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2998 /* clean up map name */
2999 strcpy( source, ExpandArg( argv[ i ] ) );
3000 StripExtension( source );
3001 DefaultExtension( source, ".bsp" );
3002 strcpy( mapSource, ExpandArg( argv[ i ] ) );
3003 StripExtension( mapSource );
3004 DefaultExtension( mapSource, ".map" );
3006 /* ydnar: set default sample size */
3007 SetDefaultSampleSize( sampleSize );
3009 /* ydnar: handle shaders */
3010 BeginMapShaderFile( source );
3014 Sys_Printf( "Loading %s\n", source );
3016 /* ydnar: load surface file */
3017 LoadSurfaceExtraFile( source );
3020 LoadBSPFile( source );
3022 /* parse bsp entities */
3025 /* inject command line parameters */
3026 InjectCommandLine( argv, 0, argc - 1 );
3029 value = ValueForKey( &entities[ 0 ], "_keepLights" );
3030 if ( value[ 0 ] != '1' ) {
3031 LoadMapFile( mapSource, qtrue, qfalse );
3034 /* set the entity/model origins and init yDrawVerts */
3037 /* ydnar: set up optimization */
3041 SetupSurfaceLightmaps();
3043 /* initialize the surface facet tracing */
3046 /* light the world */
3047 LightWorld( fastAllocate );
3049 /* ydnar: store off lightmaps */
3050 StoreSurfaceLightmaps( fastAllocate );
3052 /* write out the bsp */
3054 Sys_Printf( "Writing %s\n", source );
3055 WriteBSPFile( source );
3057 /* ydnar: export lightmaps */
3058 if ( exportLightmaps && !externalLightmaps ) {
3062 /* return to sender */