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;
158 if ( value <= 0.0f || iterations < 2 ) {
162 /* calculate some stuff */
163 step = 2.0f / ( iterations - 1 );
166 /* basic sun setup */
167 VectorCopy( color, sun.color );
169 sun.filterRadius = filterRadius;
171 sun.style = noStyles ? LS_NORMAL : style;
175 elevationSteps = iterations - 1;
176 angleSteps = elevationSteps * 4;
178 elevationStep = DEG2RAD( 90.0f / iterations ); /* skip elevation 0 */
179 angleStep = DEG2RAD( 360.0f / angleSteps );
181 /* calc individual sun brightness */
182 numSuns = angleSteps * elevationSteps + 1;
183 sun.photons = value / numSuns;
185 /* iterate elevation */
186 elevation = elevationStep * 0.5f;
188 for ( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
191 for ( j = 0; j < angleSteps; j++ )
194 sun.direction[ 0 ] = cos( angle ) * cos( elevation );
195 sun.direction[ 1 ] = sin( angle ) * cos( elevation );
196 sun.direction[ 2 ] = sin( elevation );
197 CreateSunLight( &sun );
204 elevation += elevationStep;
205 angle += angleStep / elevationSteps;
208 /* create vertical sun */
209 VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
210 CreateSunLight( &sun );
220 creates lights from light entities
223 void CreateEntityLights( void ){
225 light_t *light, *light2;
231 float intensity, scale, deviance, filterRadius;
232 int spawnflags, flags, numSamples;
236 /* go throught entity list and find lights */
237 for ( i = 0; i < numEntities; i++ )
241 name = ValueForKey( e, "classname" );
243 /* ydnar: check for lightJunior */
244 if ( Q_strncasecmp( name, "lightJunior", 11 ) == 0 ) {
247 else if ( Q_strncasecmp( name, "light", 5 ) == 0 ) {
254 /* lights with target names (and therefore styles) are only parsed from BSP */
255 target = ValueForKey( e, "targetname" );
256 if ( target[ 0 ] != '\0' && i >= numBSPEntities ) {
262 light = safe_malloc( sizeof( *light ) );
263 memset( light, 0, sizeof( *light ) );
264 light->next = lights;
267 /* handle spawnflags */
268 spawnflags = IntForKey( e, "spawnflags" );
270 /* ydnar: quake 3+ light behavior */
271 if ( wolfLight == qfalse ) {
272 /* set default flags */
273 flags = LIGHT_Q3A_DEFAULT;
275 /* linear attenuation? */
276 if ( spawnflags & 1 ) {
277 flags |= LIGHT_ATTEN_LINEAR;
278 flags &= ~LIGHT_ATTEN_ANGLE;
281 /* no angle attenuate? */
282 if ( spawnflags & 2 ) {
283 flags &= ~LIGHT_ATTEN_ANGLE;
287 /* ydnar: wolf light behavior */
290 /* set default flags */
291 flags = LIGHT_WOLF_DEFAULT;
293 /* inverse distance squared attenuation? */
294 if ( spawnflags & 1 ) {
295 flags &= ~LIGHT_ATTEN_LINEAR;
296 flags |= LIGHT_ATTEN_ANGLE;
299 /* angle attenuate? */
300 if ( spawnflags & 2 ) {
301 flags |= LIGHT_ATTEN_ANGLE;
305 /* other flags (borrowed from wolf) */
307 /* wolf dark light? */
308 if ( ( spawnflags & 4 ) || ( spawnflags & 8 ) ) {
313 if ( spawnflags & 16 ) {
314 flags &= ~LIGHT_GRID;
320 flags &= ~LIGHT_SURFACES;
323 /* store the flags */
324 light->flags = flags;
326 /* ydnar: set fade key (from wolf) */
328 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
329 light->fade = FloatForKey( e, "fade" );
330 if ( light->fade == 0.0f ) {
335 /* ydnar: set angle scaling (from vlight) */
336 light->angleScale = FloatForKey( e, "_anglescale" );
337 if ( light->angleScale != 0.0f ) {
338 light->flags |= LIGHT_ATTEN_ANGLE;
342 GetVectorForKey( e, "origin", light->origin );
343 light->style = IntForKey( e, "_style" );
344 if ( light->style == LS_NORMAL ) {
345 light->style = IntForKey( e, "style" );
347 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
348 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
351 if ( light->style != LS_NORMAL ) {
352 Sys_FPrintf( SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
355 /* set light intensity */
356 intensity = FloatForKey( e, "_light" );
357 if ( intensity == 0.0f ) {
358 intensity = FloatForKey( e, "light" );
360 if ( intensity == 0.0f ) {
364 /* ydnar: set light scale (sof2) */
365 scale = FloatForKey( e, "scale" );
366 if ( scale == 0.0f ) {
371 /* ydnar: get deviance and samples */
372 deviance = FloatForKey( e, "_deviance" );
373 if ( deviance == 0.0f ) {
374 deviance = FloatForKey( e, "_deviation" );
376 if ( deviance == 0.0f ) {
377 deviance = FloatForKey( e, "_jitter" );
379 numSamples = IntForKey( e, "_samples" );
380 if ( deviance < 0.0f || numSamples < 1 ) {
384 intensity /= numSamples;
386 /* ydnar: get filter radius */
387 filterRadius = FloatForKey( e, "_filterradius" );
388 if ( filterRadius == 0.0f ) {
389 filterRadius = FloatForKey( e, "_filteradius" );
391 if ( filterRadius == 0.0f ) {
392 filterRadius = FloatForKey( e, "_filter" );
394 if ( filterRadius < 0.0f ) {
397 light->filterRadius = filterRadius;
399 /* set light color */
400 _color = ValueForKey( e, "_color" );
401 if ( _color && _color[ 0 ] ) {
402 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
403 ColorNormalize( light->color, light->color );
406 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
409 intensity = intensity * pointScale;
410 light->photons = intensity;
412 light->type = EMIT_POINT;
414 /* set falloff threshold */
415 light->falloffTolerance = falloffTolerance / numSamples;
417 /* lights with a target will be spotlights */
418 target = ValueForKey( e, "target" );
427 e2 = FindTargetEntity( target );
429 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
430 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
434 /* not a point light */
438 /* make a spotlight */
439 GetVectorForKey( e2, "origin", dest );
440 VectorSubtract( dest, light->origin, light->normal );
441 dist = VectorNormalize( light->normal, light->normal );
442 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' ) {
460 /* not a spot light */
463 /* unlink this light */
464 lights = light->next;
467 VectorScale( light->normal, -1.0f, sun.direction );
468 VectorCopy( light->color, sun.color );
469 sun.photons = ( intensity / pointScale );
470 sun.deviance = deviance / 180.0f * Q_PI;
471 sun.numSamples = numSamples;
472 sun.style = noStyles ? LS_NORMAL : light->style;
475 /* make a sun light */
476 CreateSunLight( &sun );
478 /* free original light */
482 /* skip the rest of this love story */
488 /* jitter the light */
489 for ( j = 1; j < numSamples; j++ )
492 light2 = safe_malloc( sizeof( *light ) );
493 memcpy( light2, light, sizeof( *light ) );
494 light2->next = lights;
498 if ( light->type == EMIT_SPOT ) {
506 light2->origin[ 0 ] = light->origin[ 0 ] + ( Random() * 2.0f - 1.0f ) * deviance;
507 light2->origin[ 1 ] = light->origin[ 1 ] + ( Random() * 2.0f - 1.0f ) * deviance;
508 light2->origin[ 2 ] = light->origin[ 2 ] + ( Random() * 2.0f - 1.0f ) * deviance;
516 CreateSurfaceLights() - ydnar
517 this hijacks the radiosity code to generate surface lights for first pass
520 #define APPROX_BOUNCE 1.0f
522 void CreateSurfaceLights( void ){
524 bspDrawSurface_t *ds;
534 /* get sun shader supressor */
535 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
537 /* walk the list of surfaces */
538 for ( i = 0; i < numBSPDrawSurfaces; i++ )
540 /* get surface and other bits */
541 ds = &bspDrawSurfaces[ i ];
542 info = &surfaceInfos[ i ];
546 if ( si->sun != NULL && nss[ 0 ] != '1' ) {
547 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
548 CreateSunLight( si->sun );
549 si->sun = NULL; /* FIXME: leak! */
553 if ( si->skyLightValue > 0.0f ) {
554 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
555 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
556 si->skyLightValue = 0.0f; /* FIXME: hack! */
559 /* try to early out */
560 if ( si->value <= 0 ) {
564 /* autosprite shaders become point lights */
565 if ( si->autosprite ) {
566 /* create an average xyz */
567 VectorAdd( info->mins, info->maxs, origin );
568 VectorScale( origin, 0.5f, origin );
571 light = safe_malloc( sizeof( *light ) );
572 memset( light, 0, sizeof( *light ) );
573 light->next = lights;
577 light->flags = LIGHT_Q3A_DEFAULT;
578 light->type = EMIT_POINT;
579 light->photons = si->value * pointScale;
582 VectorCopy( origin, light->origin );
583 VectorCopy( si->color, light->color );
584 light->falloffTolerance = falloffTolerance;
585 light->style = si->lightStyle;
587 /* add to point light count and continue */
592 /* get subdivision amount */
593 if ( si->lightSubdivide > 0 ) {
594 subdivide = si->lightSubdivide;
597 subdivide = defaultLightSubdivide;
601 switch ( ds->surfaceType )
604 case MST_TRIANGLE_SOUP:
605 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
609 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
622 find the offset values for inline models
625 void SetEntityOrigins( void ){
632 bspDrawSurface_t *ds;
635 /* ydnar: copy drawverts into private storage for nefarious purposes */
636 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
637 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
639 /* set the entity origins */
640 for ( i = 0; i < numEntities; i++ )
642 /* get entity and model */
644 key = ValueForKey( e, "model" );
645 if ( key[ 0 ] != '*' ) {
648 modelnum = atoi( key + 1 );
649 dm = &bspModels[ modelnum ];
651 /* get entity origin */
652 key = ValueForKey( e, "origin" );
653 if ( key[ 0 ] == '\0' ) {
656 GetVectorForKey( e, "origin", origin );
658 /* set origin for all surfaces for this model */
659 for ( j = 0; j < dm->numBSPSurfaces; j++ )
662 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
665 for ( k = 0; k < ds->numVerts; k++ )
667 f = ds->firstVert + k;
668 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
677 PointToPolygonFormFactor()
678 calculates the area over a point/normal hemisphere a winding covers
679 ydnar: fixme: there has to be a faster way to calculate this
680 without the expensive per-vert sqrts and transcendental functions
681 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
682 between this and the approximation
685 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
687 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ){
688 vec3_t triVector, triNormal;
690 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
692 float dot, angle, facing;
695 /* this is expensive */
696 for ( i = 0; i < w->numpoints; i++ )
698 VectorSubtract( w->p[ i ], point, dirs[ i ] );
699 VectorNormalize( dirs[ i ], dirs[ i ] );
702 /* duplicate first vertex to avoid mod operation */
703 VectorCopy( dirs[ 0 ], dirs[ i ] );
705 /* calculcate relative area */
707 for ( i = 0; i < w->numpoints; i++ )
711 dot = DotProduct( dirs[ i ], dirs[ j ] );
713 /* roundoff can cause slight creep, which gives an IND from acos */
717 else if ( dot < -1.0f ) {
724 CrossProduct( dirs[ i ], dirs[ j ], triVector );
725 if ( VectorNormalize( triVector, triNormal ) < 0.0001f ) {
729 facing = DotProduct( normal, triNormal );
730 total += facing * angle;
732 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
733 if ( total > 6.3f || total < -6.3f ) {
738 /* now in the range of 0 to 1 over the entire incoming hemisphere */
739 //% total /= (2.0f * 3.141592657f);
740 total *= ONE_OVER_2PI;
747 LightContributionTosample()
748 determines the amount of light reaching a sample (luxel or vertex) from a given light
751 int LightContributionToSample( trace_t *trace ){
759 light = trace->light;
762 VectorClear( trace->color );
764 /* ydnar: early out */
765 if ( !( light->flags & LIGHT_SURFACES ) || light->envelope <= 0.0f ) {
769 /* do some culling checks */
770 if ( light->type != EMIT_SUN ) {
771 /* MrE: if the light is behind the surface */
772 if ( trace->twoSided == qfalse ) {
773 if ( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f ) {
778 /* ydnar: test pvs */
779 if ( !ClusterVisible( trace->cluster, light->cluster ) ) {
784 /* exact point to polygon form factor */
785 if ( light->type == EMIT_AREA ) {
791 /* project sample point into light plane */
792 d = DotProduct( trace->origin, light->normal ) - light->dist;
794 /* sample point behind plane? */
795 if ( !( light->flags & LIGHT_TWOSIDED ) && d < -1.0f ) {
799 /* sample plane coincident? */
800 if ( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f ) {
805 /* nudge the point so that it is clearly forward of the light */
806 /* so that surfaces meeting a light emiter don't get black edges */
807 if ( d > -8.0f && d < 8.0f ) {
808 VectorMA( trace->origin, ( 8.0f - d ), light->normal, pushedOrigin );
811 VectorCopy( trace->origin, pushedOrigin );
814 /* get direction and distance */
815 VectorCopy( light->origin, trace->end );
816 dist = SetupTrace( trace );
817 if ( dist >= light->envelope ) {
821 /* ptpff approximation */
823 /* angle attenuation */
824 angle = DotProduct( trace->normal, trace->direction );
826 /* twosided lighting */
827 if ( trace->twoSided ) {
828 angle = fabs( angle );
832 angle *= -DotProduct( light->normal, trace->direction );
833 if ( angle == 0.0f ) {
836 else if ( angle < 0.0f &&
837 ( trace->twoSided || ( light->flags & LIGHT_TWOSIDED ) ) ) {
840 add = light->photons / ( dist * dist ) * angle;
844 /* calculate the contribution */
845 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
846 if ( factor == 0.0f ) {
849 else if ( factor < 0.0f ) {
850 /* twosided lighting */
851 if ( trace->twoSided || ( light->flags & LIGHT_TWOSIDED ) ) {
854 /* push light origin to other side of the plane */
855 VectorMA( light->origin, -2.0f, light->normal, trace->end );
856 dist = SetupTrace( trace );
857 if ( dist >= light->envelope ) {
866 /* ydnar: moved to here */
867 add = factor * light->add;
871 /* point/spot lights */
872 else if ( light->type == EMIT_POINT || light->type == EMIT_SPOT ) {
873 /* get direction and distance */
874 VectorCopy( light->origin, trace->end );
875 dist = SetupTrace( trace );
876 if ( dist >= light->envelope ) {
880 /* clamp the distance to prevent super hot spots */
881 if ( dist < 16.0f ) {
885 /* angle attenuation */
886 angle = ( light->flags & LIGHT_ATTEN_ANGLE ) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
887 if ( light->angleScale != 0.0f ) {
888 angle /= light->angleScale;
889 if ( angle > 1.0f ) {
894 /* twosided lighting */
895 if ( trace->twoSided ) {
896 angle = fabs( angle );
900 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
901 add = angle * light->photons * linearScale - ( dist * light->fade );
907 add = light->photons / ( dist * dist ) * angle;
910 /* handle spotlights */
911 if ( light->type == EMIT_SPOT ) {
912 float distByNormal, radiusAtDist, sampleRadius;
913 vec3_t pointAtDist, distToSample;
916 /* do cone calculation */
917 distByNormal = -DotProduct( trace->displacement, light->normal );
918 if ( distByNormal < 0.0f ) {
921 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
922 radiusAtDist = light->radiusByDist * distByNormal;
923 VectorSubtract( trace->origin, pointAtDist, distToSample );
924 sampleRadius = VectorLength( distToSample );
926 /* outside the cone */
927 if ( sampleRadius >= radiusAtDist ) {
932 if ( sampleRadius > ( radiusAtDist - 32.0f ) ) {
933 add *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
938 /* ydnar: sunlight */
939 else if ( light->type == EMIT_SUN ) {
940 /* get origin and direction */
941 VectorAdd( trace->origin, light->origin, trace->end );
942 dist = SetupTrace( trace );
944 /* angle attenuation */
945 angle = ( light->flags & LIGHT_ATTEN_ANGLE )
946 ? DotProduct( trace->normal, trace->direction )
949 /* twosided lighting */
950 if ( trace->twoSided ) {
951 angle = fabs( angle );
955 add = light->photons * angle;
961 trace->testAll = qtrue;
962 VectorScale( light->color, add, trace->color );
965 if ( trace->testOcclusion && !trace->forceSunlight ) {
968 if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) {
969 VectorClear( trace->color );
974 /* return to sender */
978 /* ydnar: changed to a variable number */
979 if ( add <= 0.0f || ( add <= light->falloffTolerance && ( light->flags & LIGHT_FAST_ACTUAL ) ) ) {
984 trace->testAll = qfalse;
985 VectorScale( light->color, add, trace->color );
989 if ( trace->passSolid || trace->opaque ) {
990 VectorClear( trace->color );
994 /* return to sender */
1002 determines the amount of light reaching a sample (luxel or vertex)
1005 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] ){
1010 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1011 VectorClear( colors[ lightmapNum ] );
1013 /* ydnar: normalmap */
1015 colors[ 0 ][ 0 ] = ( trace->normal[ 0 ] + 1.0f ) * 127.5f;
1016 colors[ 0 ][ 1 ] = ( trace->normal[ 1 ] + 1.0f ) * 127.5f;
1017 colors[ 0 ][ 2 ] = ( trace->normal[ 2 ] + 1.0f ) * 127.5f;
1021 /* ydnar: don't bounce ambient all the time */
1023 VectorCopy( ambientColor, colors[ 0 ] );
1026 /* ydnar: trace to all the list of lights pre-stored in tw */
1027 for ( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1030 trace->light = trace->lights[ i ];
1033 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1035 if ( styles[ lightmapNum ] == trace->light->style ||
1036 styles[ lightmapNum ] == LS_NONE ) {
1041 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1042 if ( lightmapNum >= MAX_LIGHTMAPS ) {
1047 LightContributionToSample( trace );
1048 if ( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f ) {
1052 /* handle negative light */
1053 if ( trace->light->flags & LIGHT_NEGATIVE ) {
1054 VectorScale( trace->color, -1.0f, trace->color );
1058 styles[ lightmapNum ] = trace->light->style;
1061 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1065 colors[ 0 ][ 0 ] >= 255.0f &&
1066 colors[ 0 ][ 1 ] >= 255.0f &&
1067 colors[ 0 ][ 2 ] >= 255.0f ) {
1076 LightContributionToPoint()
1077 for a given light, how much light/color reaches a given point in space (with no facing)
1078 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1081 int LightContributionToPoint( trace_t *trace ){
1087 light = trace->light;
1090 VectorClear( trace->color );
1092 /* ydnar: early out */
1093 if ( !( light->flags & LIGHT_GRID ) || light->envelope <= 0.0f ) {
1097 /* is this a sun? */
1098 if ( light->type != EMIT_SUN ) {
1105 if ( !ClusterVisible( trace->cluster, light->cluster ) ) {
1110 /* ydnar: check origin against light's pvs envelope */
1111 if ( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1112 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1113 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] ) {
1118 /* set light origin */
1119 if ( light->type == EMIT_SUN ) {
1120 VectorAdd( trace->origin, light->origin, trace->end );
1123 VectorCopy( light->origin, trace->end );
1127 dist = SetupTrace( trace );
1130 if ( dist > light->envelope ) {
1131 gridEnvelopeCulled++;
1135 /* ptpff approximation */
1136 if ( light->type == EMIT_AREA && faster ) {
1137 /* clamp the distance to prevent super hot spots */
1138 if ( dist < 16.0f ) {
1143 add = light->photons / ( dist * dist );
1146 /* exact point to polygon form factor */
1147 else if ( light->type == EMIT_AREA ) {
1149 vec3_t pushedOrigin;
1152 /* see if the point is behind the light */
1153 d = DotProduct( trace->origin, light->normal ) - light->dist;
1154 if ( !( light->flags & LIGHT_TWOSIDED ) && d < -1.0f ) {
1158 /* nudge the point so that it is clearly forward of the light */
1159 /* so that surfaces meeting a light emiter don't get black edges */
1160 if ( d > -8.0f && d < 8.0f ) {
1161 VectorMA( trace->origin, ( 8.0f - d ), light->normal, pushedOrigin );
1164 VectorCopy( trace->origin, pushedOrigin );
1167 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1168 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1169 if ( factor == 0.0f ) {
1172 else if ( factor < 0.0f ) {
1173 if ( light->flags & LIGHT_TWOSIDED ) {
1181 /* ydnar: moved to here */
1182 add = factor * light->add;
1185 /* point/spot lights */
1186 else if ( light->type == EMIT_POINT || light->type == EMIT_SPOT ) {
1187 /* clamp the distance to prevent super hot spots */
1188 if ( dist < 16.0f ) {
1193 if ( light->flags & LIGHT_ATTEN_LINEAR ) {
1194 add = light->photons * linearScale - ( dist * light->fade );
1200 add = light->photons / ( dist * dist );
1203 /* handle spotlights */
1204 if ( light->type == EMIT_SPOT ) {
1205 float distByNormal, radiusAtDist, sampleRadius;
1206 vec3_t pointAtDist, distToSample;
1209 /* do cone calculation */
1210 distByNormal = -DotProduct( trace->displacement, light->normal );
1211 if ( distByNormal < 0.0f ) {
1214 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1215 radiusAtDist = light->radiusByDist * distByNormal;
1216 VectorSubtract( trace->origin, pointAtDist, distToSample );
1217 sampleRadius = VectorLength( distToSample );
1219 /* outside the cone */
1220 if ( sampleRadius >= radiusAtDist ) {
1225 if ( sampleRadius > ( radiusAtDist - 32.0f ) ) {
1226 add *= ( ( radiusAtDist - sampleRadius ) / 32.0f );
1231 /* ydnar: sunlight */
1232 else if ( light->type == EMIT_SUN ) {
1234 add = light->photons;
1235 if ( add <= 0.0f ) {
1240 trace->testAll = qtrue;
1241 VectorScale( light->color, add, trace->color );
1243 /* trace to point */
1244 if ( trace->testOcclusion && !trace->forceSunlight ) {
1247 if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) {
1248 VectorClear( trace->color );
1253 /* return to sender */
1257 /* unknown light type */
1262 /* ydnar: changed to a variable number */
1263 if ( add <= 0.0f || ( add <= light->falloffTolerance && ( light->flags & LIGHT_FAST_ACTUAL ) ) ) {
1268 trace->testAll = qfalse;
1269 VectorScale( light->color, add, trace->color );
1273 if ( trace->passSolid ) {
1274 VectorClear( trace->color );
1278 /* we have a valid sample */
1286 grid samples are for quickly determining the lighting
1287 of dynamically placed entities in the world
1290 #define MAX_CONTRIBUTIONS 1024
1300 void TraceGrid( int num ){
1301 int i, j, x, y, z, mod, step, numCon, numStyles;
1303 vec3_t baseOrigin, cheapColor, color;
1305 bspGridPoint_t *bgp;
1306 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1310 /* get grid points */
1311 gp = &rawGridPoints[ num ];
1312 bgp = &bspGridPoints[ num ];
1314 /* get grid origin */
1316 z = mod / ( gridBounds[ 0 ] * gridBounds[ 1 ] );
1317 mod -= z * ( gridBounds[ 0 ] * gridBounds[ 1 ] );
1318 y = mod / gridBounds[ 0 ];
1319 mod -= y * gridBounds[ 0 ];
1322 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1323 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1324 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1326 /* set inhibit sphere */
1327 if ( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] ) {
1328 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1330 else if ( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] ) {
1331 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1334 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1337 /* find point cluster */
1338 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1339 if ( trace.cluster < 0 ) {
1340 /* try to nudge the origin around to find a valid point */
1341 VectorCopy( trace.origin, baseOrigin );
1342 for ( step = 9; step <= 18; step += 9 )
1344 for ( i = 0; i < 8; i++ )
1346 VectorCopy( baseOrigin, trace.origin );
1348 trace.origin[ 0 ] += step;
1351 trace.origin[ 0 ] -= step;
1355 trace.origin[ 1 ] += step;
1358 trace.origin[ 1 ] -= step;
1362 trace.origin[ 2 ] += step;
1365 trace.origin[ 2 ] -= step;
1368 /* ydnar: changed to find cluster num */
1369 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1370 if ( trace.cluster >= 0 ) {
1380 /* can't find a valid point at all */
1387 trace.testOcclusion = !noTrace;
1388 trace.forceSunlight = qfalse;
1389 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1390 trace.numSurfaces = 0;
1391 trace.surfaces = NULL;
1392 trace.numLights = 0;
1393 trace.lights = NULL;
1397 VectorClear( cheapColor );
1399 /* trace to all the lights, find the major light direction, and divide the
1400 total light between that along the direction and the remaining in the ambient */
1401 for ( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1407 if ( !LightContributionToPoint( &trace ) ) {
1411 /* handle negative light */
1412 if ( trace.light->flags & LIGHT_NEGATIVE ) {
1413 VectorScale( trace.color, -1.0f, trace.color );
1416 /* add a contribution */
1417 VectorCopy( trace.color, contributions[ numCon ].color );
1418 VectorCopy( trace.direction, contributions[ numCon ].dir );
1419 contributions[ numCon ].style = trace.light->style;
1422 /* push average direction around */
1423 addSize = VectorLength( trace.color );
1424 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1426 /* stop after a while */
1427 if ( numCon >= ( MAX_CONTRIBUTIONS - 1 ) ) {
1431 /* ydnar: cheap mode */
1432 VectorAdd( cheapColor, trace.color, cheapColor );
1433 if ( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f ) {
1438 /* normalize to get primary light direction */
1439 VectorNormalize( gp->dir, gp->dir );
1441 /* now that we have identified the primary light direction,
1442 go back and separate all the light into directed and ambient */
1444 for ( i = 0; i < numCon; i++ )
1446 /* get relative directed strength */
1447 d = DotProduct( contributions[ i ].dir, gp->dir );
1452 /* find appropriate style */
1453 for ( j = 0; j < numStyles; j++ )
1455 if ( gp->styles[ j ] == contributions[ i ].style ) {
1460 /* style not found? */
1461 if ( j >= numStyles ) {
1462 /* add a new style */
1463 if ( numStyles < MAX_LIGHTMAPS ) {
1464 gp->styles[ numStyles ] = contributions[ i ].style;
1465 bgp->styles[ numStyles ] = contributions[ i ].style;
1467 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1476 /* add the directed color */
1477 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1479 /* ambient light will be at 1/4 the value of directed light */
1480 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1481 d = 0.25f * ( 1.0f - d );
1482 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1486 /* store off sample */
1487 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
1489 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1491 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1494 /* set minimum light and copy off to bytes */
1495 VectorCopy( gp->ambient[ i ], color );
1496 for ( j = 0; j < 3; j++ )
1497 if ( color[ j ] < minGridLight[ j ] ) {
1498 color[ j ] = minGridLight[ j ];
1500 ColorToBytes( color, bgp->ambient[ i ], 1.0f );
1501 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );
1506 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1507 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1509 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1510 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1513 /* store direction */
1515 NormalToLatLong( gp->dir, bgp->latLong );
1523 calculates the size of the lightgrid and allocates memory
1526 void SetupGrid( void ){
1528 vec3_t maxs, oldGridSize;
1533 /* don't do this if not grid lighting */
1534 if ( noGridLighting ) {
1538 /* ydnar: set grid size */
1539 value = ValueForKey( &entities[ 0 ], "gridsize" );
1540 if ( value[ 0 ] != '\0' ) {
1541 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1545 VectorCopy( gridSize, oldGridSize );
1546 for ( i = 0; i < 3; i++ )
1547 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1549 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1550 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1552 while ( numRawGridPoints > MAX_MAP_LIGHTGRID )
1554 /* get world bounds */
1555 for ( i = 0; i < 3; i++ )
1557 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1558 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1559 gridBounds[ i ] = ( maxs[ i ] - gridMins[ i ] ) / gridSize[ i ] + 1;
1563 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1565 /* increase grid size a bit */
1566 if ( numRawGridPoints > MAX_MAP_LIGHTGRID ) {
1567 gridSize[ j++ % 3 ] += 16.0f;
1572 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1575 if ( !VectorCompare( gridSize, oldGridSize ) ) {
1576 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1577 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1578 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1581 /* 2nd variable. fixme: is this silly? */
1582 numBSPGridPoints = numRawGridPoints;
1584 /* allocate lightgrid */
1585 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1586 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1588 if ( bspGridPoints != NULL ) {
1589 free( bspGridPoints );
1591 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1592 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1594 /* clear lightgrid */
1595 for ( i = 0; i < numRawGridPoints; i++ )
1597 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1598 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1599 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1600 for ( j = 1; j < MAX_LIGHTMAPS; j++ )
1602 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1603 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1608 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1615 does what it says...
1618 void LightWorld( void ){
1622 qboolean minVertex, minGrid;
1626 /* ydnar: smooth normals */
1628 Sys_Printf( "--- SmoothNormals ---\n" );
1632 /* determine the number of grid points */
1633 Sys_Printf( "--- SetupGrid ---\n" );
1636 /* find the optional minimum lighting values */
1637 GetVectorForKey( &entities[ 0 ], "_color", color );
1638 if ( VectorLength( color ) == 0.0f ) {
1639 VectorSet( color, 1.0, 1.0, 1.0 );
1643 f = FloatForKey( &entities[ 0 ], "_ambient" );
1645 f = FloatForKey( &entities[ 0 ], "ambient" );
1647 VectorScale( color, f, ambientColor );
1649 /* minvertexlight */
1651 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1652 if ( value[ 0 ] != '\0' ) {
1655 VectorScale( color, f, minVertexLight );
1660 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1661 if ( value[ 0 ] != '\0' ) {
1664 VectorScale( color, f, minGridLight );
1668 value = ValueForKey( &entities[ 0 ], "_minlight" );
1669 if ( value[ 0 ] != '\0' ) {
1671 VectorScale( color, f, minLight );
1672 if ( minVertex == qfalse ) {
1673 VectorScale( color, f, minVertexLight );
1675 if ( minGrid == qfalse ) {
1676 VectorScale( color, f, minGridLight );
1680 /* create world lights */
1681 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1682 CreateEntityLights();
1683 CreateSurfaceLights();
1684 Sys_Printf( "%9d point lights\n", numPointLights );
1685 Sys_Printf( "%9d spotlights\n", numSpotLights );
1686 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1687 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1689 /* calculate lightgrid */
1690 if ( !noGridLighting ) {
1691 /* ydnar: set up light envelopes */
1692 SetupEnvelopes( qtrue, fastgrid );
1694 Sys_Printf( "--- TraceGrid ---\n" );
1695 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1696 Sys_Printf( "%d x %d x %d = %d grid\n",
1697 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1699 /* ydnar: emit statistics on light culling */
1700 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1701 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1704 /* slight optimization to remove a sqrt */
1705 subdivideThreshold *= subdivideThreshold;
1707 /* map the world luxels */
1708 Sys_Printf( "--- MapRawLightmap ---\n" );
1709 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1710 Sys_Printf( "%9d luxels\n", numLuxels );
1711 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1712 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1716 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1721 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1725 /* ydnar: set up light envelopes */
1726 SetupEnvelopes( qfalse, fast );
1728 /* light up my world */
1729 lightsPlaneCulled = 0;
1730 lightsEnvelopeCulled = 0;
1731 lightsBoundsCulled = 0;
1732 lightsClusterCulled = 0;
1734 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1735 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1736 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1738 StitchSurfaceLightmaps();
1740 Sys_Printf( "--- IlluminateVertexes ---\n" );
1741 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1742 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1744 /* ydnar: emit statistics on light culling */
1745 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1746 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1747 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1748 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1753 while ( bounce > 0 )
1755 /* store off the bsp between bounces */
1756 StoreSurfaceLightmaps();
1757 Sys_Printf( "Writing %s\n", source );
1758 WriteBSPFile( source );
1761 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1765 VectorClear( ambientColor );
1767 /* generate diffuse lights */
1769 RadCreateDiffuseLights();
1771 /* setup light envelopes */
1772 SetupEnvelopes( qfalse, fastbounce );
1773 if ( numLights == 0 ) {
1774 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1778 /* add to lightgrid */
1780 gridEnvelopeCulled = 0;
1781 gridBoundsCulled = 0;
1783 Sys_Printf( "--- BounceGrid ---\n" );
1784 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1785 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1786 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1789 /* light up my world */
1790 lightsPlaneCulled = 0;
1791 lightsEnvelopeCulled = 0;
1792 lightsBoundsCulled = 0;
1793 lightsClusterCulled = 0;
1795 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1796 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1797 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1798 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1800 StitchSurfaceLightmaps();
1802 Sys_Printf( "--- IlluminateVertexes ---\n" );
1803 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1804 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1806 /* ydnar: emit statistics on light culling */
1807 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1808 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1809 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1810 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1822 main routine for light processing
1825 int LightMain( int argc, char **argv ){
1828 char mapSource[ 1024 ];
1833 Sys_Printf( "--- Light ---\n" );
1835 /* set standard game flags */
1836 wolfLight = game->wolfLight;
1837 lmCustomSize = game->lightmapSize;
1838 lightmapGamma = game->lightmapGamma;
1839 lightmapCompensate = game->lightmapCompensate;
1841 /* process commandline arguments */
1842 for ( i = 1; i < ( argc - 1 ); i++ )
1844 /* lightsource scaling */
1845 if ( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) ) {
1846 f = atof( argv[ i + 1 ] );
1848 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1852 else if ( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) ) {
1853 f = atof( argv[ i + 1 ] );
1855 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1859 else if ( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) ) {
1860 f = atof( argv[ i + 1 ] );
1862 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1866 else if ( !strcmp( argv[ i ], "-bouncescale" ) ) {
1867 f = atof( argv[ i + 1 ] );
1869 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
1873 else if ( !strcmp( argv[ i ], "-scale" ) ) {
1874 f = atof( argv[ i + 1 ] );
1879 Sys_Printf( "All light scaled by %f\n", f );
1883 else if ( !strcmp( argv[ i ], "-gamma" ) ) {
1884 f = atof( argv[ i + 1 ] );
1886 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
1890 else if ( !strcmp( argv[ i ], "-compensate" ) ) {
1891 f = atof( argv[ i + 1 ] );
1895 lightmapCompensate = f;
1896 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
1900 /* ydnar switches */
1901 else if ( !strcmp( argv[ i ], "-bounce" ) ) {
1902 bounce = atoi( argv[ i + 1 ] );
1906 else if ( bounce > 0 ) {
1907 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
1912 else if ( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) ) {
1913 superSample = atoi( argv[ i + 1 ] );
1914 if ( superSample < 1 ) {
1917 else if ( superSample > 1 ) {
1918 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", ( superSample * superSample ) );
1923 else if ( !strcmp( argv[ i ], "-samples" ) ) {
1924 lightSamples = atoi( argv[ i + 1 ] );
1925 if ( lightSamples < 1 ) {
1928 else if ( lightSamples > 1 ) {
1929 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
1934 else if ( !strcmp( argv[ i ], "-filter" ) ) {
1936 Sys_Printf( "Lightmap filtering enabled\n" );
1939 else if ( !strcmp( argv[ i ], "-dark" ) ) {
1941 Sys_Printf( "Dark lightmap seams enabled\n" );
1950 else if ( !strcmp( argv[ i ], "-shadeangle" ) ) {
1951 shadeAngleDegrees = atof( argv[ i + 1 ] );
1952 if ( shadeAngleDegrees < 0.0f ) {
1953 shadeAngleDegrees = 0.0f;
1955 else if ( shadeAngleDegrees > 0.0f ) {
1957 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
1962 else if ( !strcmp( argv[ i ], "-thresh" ) ) {
1963 subdivideThreshold = atof( argv[ i + 1 ] );
1964 if ( subdivideThreshold < 0 ) {
1965 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
1968 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
1973 else if ( !strcmp( argv[ i ], "-approx" ) ) {
1974 approximateTolerance = atoi( argv[ i + 1 ] );
1975 if ( approximateTolerance < 0 ) {
1976 approximateTolerance = 0;
1978 else if ( approximateTolerance > 0 ) {
1979 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
1984 else if ( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) ) {
1986 Sys_Printf( "Generating deluxemaps for average light direction\n" );
1989 else if ( !strcmp( argv[ i ], "-external" ) ) {
1990 externalLightmaps = qtrue;
1991 Sys_Printf( "Storing all lightmaps externally\n" );
1994 else if ( !strcmp( argv[ i ], "-lightmapsize" ) ) {
1995 lmCustomSize = atoi( argv[ i + 1 ] );
1997 /* must be a power of 2 and greater than 2 */
1998 if ( ( ( lmCustomSize - 1 ) & lmCustomSize ) || lmCustomSize < 2 ) {
1999 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2000 lmCustomSize = game->lightmapSize;
2003 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2005 /* enable external lightmaps */
2006 if ( lmCustomSize != game->lightmapSize ) {
2007 externalLightmaps = qtrue;
2008 Sys_Printf( "Storing all lightmaps externally\n" );
2012 /* ydnar: add this to suppress warnings */
2013 else if ( !strcmp( argv[ i ], "-custinfoparms" ) ) {
2014 Sys_Printf( "Custom info parms enabled\n" );
2015 useCustomInfoParms = qtrue;
2018 else if ( !strcmp( argv[ i ], "-wolf" ) ) {
2019 /* -game should already be set */
2021 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2024 else if ( !strcmp( argv[ i ], "-q3" ) ) {
2025 /* -game should already be set */
2027 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2030 else if ( !strcmp( argv[ i ], "-sunonly" ) ) {
2032 Sys_Printf( "Only computing sunlight\n" );
2035 else if ( !strcmp( argv[ i ], "-bounceonly" ) ) {
2037 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2040 else if ( !strcmp( argv[ i ], "-nocollapse" ) ) {
2042 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2045 else if ( !strcmp( argv[ i ], "-shade" ) ) {
2047 Sys_Printf( "Phong shading enabled\n" );
2050 else if ( !strcmp( argv[ i ], "-bouncegrid" ) ) {
2053 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2057 else if ( !strcmp( argv[ i ], "-smooth" ) ) {
2058 lightSamples = EXTRA_SCALE;
2059 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2062 else if ( !strcmp( argv[ i ], "-fast" ) ) {
2066 Sys_Printf( "Fast mode enabled\n" );
2069 else if ( !strcmp( argv[ i ], "-faster" ) ) {
2074 Sys_Printf( "Faster mode enabled\n" );
2077 else if ( !strcmp( argv[ i ], "-fastgrid" ) ) {
2079 Sys_Printf( "Fast grid lighting enabled\n" );
2082 else if ( !strcmp( argv[ i ], "-fastbounce" ) ) {
2084 Sys_Printf( "Fast bounce mode enabled\n" );
2087 else if ( !strcmp( argv[ i ], "-cheap" ) ) {
2090 Sys_Printf( "Cheap mode enabled\n" );
2093 else if ( !strcmp( argv[ i ], "-cheapgrid" ) ) {
2095 Sys_Printf( "Cheap grid mode enabled\n" );
2098 else if ( !strcmp( argv[ i ], "-normalmap" ) ) {
2100 Sys_Printf( "Storing normal map instead of lightmap\n" );
2103 else if ( !strcmp( argv[ i ], "-trisoup" ) ) {
2105 Sys_Printf( "Converting brush faces to triangle soup\n" );
2108 else if ( !strcmp( argv[ i ], "-debug" ) ) {
2110 Sys_Printf( "Lightmap debugging enabled\n" );
2113 else if ( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) ) {
2114 debugSurfaces = qtrue;
2115 Sys_Printf( "Lightmap surface debugging enabled\n" );
2118 else if ( !strcmp( argv[ i ], "-debugunused" ) ) {
2119 debugUnused = qtrue;
2120 Sys_Printf( "Unused luxel debugging enabled\n" );
2123 else if ( !strcmp( argv[ i ], "-debugaxis" ) ) {
2125 Sys_Printf( "Lightmap axis debugging enabled\n" );
2128 else if ( !strcmp( argv[ i ], "-debugcluster" ) ) {
2129 debugCluster = qtrue;
2130 Sys_Printf( "Luxel cluster debugging enabled\n" );
2133 else if ( !strcmp( argv[ i ], "-debugorigin" ) ) {
2134 debugOrigin = qtrue;
2135 Sys_Printf( "Luxel origin debugging enabled\n" );
2138 else if ( !strcmp( argv[ i ], "-debugdeluxe" ) ) {
2140 debugDeluxemap = qtrue;
2141 Sys_Printf( "Deluxemap debugging enabled\n" );
2144 else if ( !strcmp( argv[ i ], "-export" ) ) {
2145 exportLightmaps = qtrue;
2146 Sys_Printf( "Exporting lightmaps\n" );
2149 else if ( !strcmp( argv[ i ], "-notrace" ) ) {
2151 Sys_Printf( "Shadow occlusion disabled\n" );
2153 else if ( !strcmp( argv[ i ], "-patchshadows" ) ) {
2154 patchShadows = qtrue;
2155 Sys_Printf( "Patch shadow casting enabled\n" );
2157 else if ( !strcmp( argv[ i ], "-extra" ) ) {
2158 superSample = EXTRA_SCALE; /* ydnar */
2159 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2161 else if ( !strcmp( argv[ i ], "-extrawide" ) ) {
2162 superSample = EXTRAWIDE_SCALE; /* ydnar */
2163 filter = qtrue; /* ydnar */
2164 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n" );
2166 else if ( !strcmp( argv[ i ], "-samplesize" ) ) {
2167 sampleSize = atoi( argv[ i + 1 ] );
2168 if ( sampleSize < 1 ) {
2172 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2174 else if ( !strcmp( argv[ i ], "-novertex" ) ) {
2175 noVertexLighting = qtrue;
2176 Sys_Printf( "Disabling vertex lighting\n" );
2178 else if ( !strcmp( argv[ i ], "-nogrid" ) ) {
2179 noGridLighting = qtrue;
2180 Sys_Printf( "Disabling grid lighting\n" );
2182 else if ( !strcmp( argv[ i ], "-border" ) ) {
2183 lightmapBorder = qtrue;
2184 Sys_Printf( "Adding debug border to lightmaps\n" );
2186 else if ( !strcmp( argv[ i ], "-nosurf" ) ) {
2188 Sys_Printf( "Not tracing against surfaces\n" );
2190 else if ( !strcmp( argv[ i ], "-dump" ) ) {
2192 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2194 else if ( !strcmp( argv[ i ], "-lomem" ) ) {
2196 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2198 else if ( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) ) {
2200 Sys_Printf( "Disabling lightstyles\n" );
2202 else if ( !strcmp( argv[ i ], "-cpma" ) ) {
2204 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2207 /* r7: dirtmapping */
2208 else if ( !strcmp( argv[ i ], "-dirty" ) ) {
2210 Sys_Printf( "Dirtmapping enabled\n" );
2212 else if ( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) ) {
2214 Sys_Printf( "Dirtmap debugging enabled\n" );
2216 else if ( !strcmp( argv[ i ], "-dirtmode" ) ) {
2217 dirtMode = atoi( argv[ i + 1 ] );
2218 if ( dirtMode != 0 && dirtMode != 1 ) {
2221 if ( dirtMode == 1 ) {
2222 Sys_Printf( "Enabling randomized dirtmapping\n" );
2225 Sys_Printf( "Enabling ordered dir mapping\n" );
2228 else if ( !strcmp( argv[ i ], "-dirtdepth" ) ) {
2229 dirtDepth = atof( argv[ i + 1 ] );
2230 if ( dirtDepth <= 0.0f ) {
2233 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2235 else if ( !strcmp( argv[ i ], "-dirtscale" ) ) {
2236 dirtScale = atof( argv[ i + 1 ] );
2237 if ( dirtScale <= 0.0f ) {
2240 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2242 else if ( !strcmp( argv[ i ], "-dirtgain" ) ) {
2243 dirtGain = atof( argv[ i + 1 ] );
2244 if ( dirtGain <= 0.0f ) {
2247 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2250 /* unhandled args */
2252 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2257 /* clean up map name */
2258 strcpy( source, ExpandArg( argv[ i ] ) );
2259 StripExtension( source );
2260 DefaultExtension( source, ".bsp" );
2261 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2262 StripExtension( mapSource );
2263 DefaultExtension( mapSource, ".map" );
2265 /* ydnar: set default sample size */
2266 SetDefaultSampleSize( sampleSize );
2268 /* ydnar: handle shaders */
2269 BeginMapShaderFile( source );
2273 Sys_Printf( "Loading %s\n", source );
2275 /* ydnar: load surface file */
2276 LoadSurfaceExtraFile( source );
2279 LoadBSPFile( source );
2281 /* parse bsp entities */
2285 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2286 if ( value[ 0 ] != '1' ) {
2287 LoadMapFile( mapSource, qtrue );
2290 /* set the entity/model origins and init yDrawVerts */
2293 /* ydnar: set up optimization */
2296 SetupSurfaceLightmaps();
2298 /* initialize the surface facet tracing */
2301 /* light the world */
2304 /* ydnar: store off lightmaps */
2305 StoreSurfaceLightmaps();
2307 /* write out the bsp */
2309 Sys_Printf( "Writing %s\n", source );
2310 WriteBSPFile( source );
2312 /* ydnar: export lightmaps */
2313 if ( exportLightmaps && !externalLightmaps ) {
2317 /* return to sender */