1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
42 CreateSunLight() - ydnar
43 this creates a sun light
46 static void CreateSunLight( sun_t *sun )
49 float photons, d, angle, elevation, da, de;
59 if( sun->numSamples < 1 )
63 photons = sun->photons / sun->numSamples;
65 /* create the right number of suns */
66 for( i = 0; i < sun->numSamples; i++ )
68 /* calculate sun direction */
70 VectorCopy( sun->direction, direction );
74 sun->direction[ 0 ] = cos( angle ) * cos( elevation );
75 sun->direction[ 1 ] = sin( angle ) * cos( elevation );
76 sun->direction[ 2 ] = sin( elevation );
78 xz_dist = sqrt( x*x + z*z )
79 latitude = atan2( xz_dist, y ) * RADIANS
80 longitude = atan2( x, z ) * RADIANS
83 d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
84 angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
85 elevation = atan2( sun->direction[ 2 ], d );
87 /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
90 da = (Random() * 2.0f - 1.0f) * sun->deviance;
91 de = (Random() * 2.0f - 1.0f) * sun->deviance;
93 while( (da * da + de * de) > (sun->deviance * sun->deviance) );
98 //% Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
100 /* create new vector */
101 direction[ 0 ] = cos( angle ) * cos( elevation );
102 direction[ 1 ] = sin( angle ) * cos( elevation );
103 direction[ 2 ] = sin( elevation );
108 light = safe_malloc( sizeof( *light ) );
109 memset( light, 0, sizeof( *light ) );
110 light->next = lights;
113 /* initialize the light */
114 light->flags = LIGHT_SUN_DEFAULT;
115 light->type = EMIT_SUN;
117 light->falloffTolerance = falloffTolerance;
118 light->filterRadius = sun->filterRadius / sun->numSamples;
119 light->style = noStyles ? LS_NORMAL : sun->style;
121 /* set the light's position out to infinity */
122 VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin ); /* MAX_WORLD_COORD * 2.0f */
124 /* set the facing to be the inverse of the sun direction */
125 VectorScale( direction, -1.0, light->normal );
126 light->dist = DotProduct( light->origin, light->normal );
128 /* set color and photons */
129 VectorCopy( sun->color, light->color );
130 light->photons = photons * skyScale;
134 if( sun->next != NULL )
135 CreateSunLight( sun->next );
141 CreateSkyLights() - ydnar
142 simulates sky light with multiple suns
145 static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius, int style )
148 int angleSteps, elevationSteps;
149 float angle, elevation;
150 float angleStep, elevationStep;
156 if( value <= 0.0f || iterations < 2 )
159 /* calculate some stuff */
160 step = 2.0f / (iterations - 1);
163 /* basic sun setup */
164 VectorCopy( color, sun.color );
166 sun.filterRadius = filterRadius;
168 sun.style = noStyles ? LS_NORMAL : style;
172 elevationSteps = iterations - 1;
173 angleSteps = elevationSteps * 4;
175 elevationStep = DEG2RAD( 90.0f / iterations ); /* skip elevation 0 */
176 angleStep = DEG2RAD( 360.0f / angleSteps );
178 /* calc individual sun brightness */
179 numSuns = angleSteps * elevationSteps + 1;
180 sun.photons = value / numSuns;
182 /* iterate elevation */
183 elevation = elevationStep * 0.5f;
185 for( i = 0, elevation = elevationStep * 0.5f; i < elevationSteps; i++ )
188 for( j = 0; j < angleSteps; j++ )
191 sun.direction[ 0 ] = cos( angle ) * cos( elevation );
192 sun.direction[ 1 ] = sin( angle ) * cos( elevation );
193 sun.direction[ 2 ] = sin( elevation );
194 CreateSunLight( &sun );
201 elevation += elevationStep;
202 angle += angleStep / elevationSteps;
205 /* create vertical sun */
206 VectorSet( sun.direction, 0.0f, 0.0f, 1.0f );
207 CreateSunLight( &sun );
217 creates lights from light entities
220 void CreateEntityLights( void )
223 light_t *light, *light2;
229 float intensity, scale, deviance, filterRadius;
230 int spawnflags, flags, numSamples;
234 /* go throught entity list and find lights */
235 for( i = 0; i < numEntities; i++ )
239 name = ValueForKey( e, "classname" );
241 /* ydnar: check for lightJunior */
242 if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
244 else if( Q_strncasecmp( name, "light", 5 ) == 0 )
249 /* lights with target names (and therefore styles) are only parsed from BSP */
250 target = ValueForKey( e, "targetname" );
251 if( target[ 0 ] != '\0' && i >= numBSPEntities )
256 light = safe_malloc( sizeof( *light ) );
257 memset( light, 0, sizeof( *light ) );
258 light->next = lights;
261 /* handle spawnflags */
262 spawnflags = IntForKey( e, "spawnflags" );
264 /* ydnar: quake 3+ light behavior */
265 if( wolfLight == qfalse )
267 /* set default flags */
268 flags = LIGHT_Q3A_DEFAULT;
270 /* linear attenuation? */
273 flags |= LIGHT_ATTEN_LINEAR;
274 flags &= ~LIGHT_ATTEN_ANGLE;
277 /* no angle attenuate? */
279 flags &= ~LIGHT_ATTEN_ANGLE;
282 /* ydnar: wolf light behavior */
285 /* set default flags */
286 flags = LIGHT_WOLF_DEFAULT;
288 /* inverse distance squared attenuation? */
291 flags &= ~LIGHT_ATTEN_LINEAR;
292 flags |= LIGHT_ATTEN_ANGLE;
295 /* angle attenuate? */
297 flags |= LIGHT_ATTEN_ANGLE;
300 /* other flags (borrowed from wolf) */
302 /* wolf dark light? */
303 if( (spawnflags & 4) || (spawnflags & 8) )
307 if( spawnflags & 16 )
308 flags &= ~LIGHT_GRID;
314 flags &= ~LIGHT_SURFACES;
317 /* vortex: unnormalized? */
319 flags |= LIGHT_UNNORMALIZED;
321 /* vortex: distance atten? */
323 flags |= LIGHT_ATTEN_DISTANCE;
325 /* store the flags */
326 light->flags = flags;
328 /* ydnar: set fade key (from wolf) */
330 if( light->flags & LIGHT_ATTEN_LINEAR )
332 light->fade = FloatForKey( e, "fade" );
333 if( light->fade == 0.0f )
337 /* ydnar: set angle scaling (from vlight) */
338 light->angleScale = FloatForKey( e, "_anglescale" );
339 if( light->angleScale != 0.0f )
340 light->flags |= LIGHT_ATTEN_ANGLE;
343 GetVectorForKey( e, "origin", light->origin);
344 light->style = IntForKey( e, "_style" );
345 if( light->style == LS_NORMAL )
346 light->style = IntForKey( e, "style" );
347 if( light->style < LS_NORMAL || light->style >= LS_NONE )
348 Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
350 if( light->style != LS_NORMAL ) {
351 Sys_FPrintf (SYS_WRN, "WARNING: Styled light found targeting %s\n **", target );
354 /* set light intensity */
355 intensity = FloatForKey( e, "_light" );
356 if( intensity == 0.0f )
357 intensity = FloatForKey( e, "light" );
358 if( intensity == 0.0f)
361 /* ydnar: set light scale (sof2) */
362 scale = FloatForKey( e, "scale" );
367 /* ydnar: get deviance and samples */
368 deviance = FloatForKey( e, "_deviance" );
369 if( deviance == 0.0f )
370 deviance = FloatForKey( e, "_deviation" );
371 if( deviance == 0.0f )
372 deviance = FloatForKey( e, "_jitter" );
373 numSamples = IntForKey( e, "_samples" );
374 if( deviance < 0.0f || numSamples < 1 )
379 intensity /= numSamples;
381 /* ydnar: get filter radius */
382 filterRadius = FloatForKey( e, "_filterradius" );
383 if( filterRadius == 0.0f )
384 filterRadius = FloatForKey( e, "_filteradius" );
385 if( filterRadius == 0.0f )
386 filterRadius = FloatForKey( e, "_filter" );
387 if( filterRadius < 0.0f )
389 light->filterRadius = filterRadius;
391 /* set light color */
392 _color = ValueForKey( e, "_color" );
393 if( _color && _color[ 0 ] )
395 sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
396 if (!(light->flags & LIGHT_UNNORMALIZED))
398 ColorNormalize( light->color, light->color );
402 light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
404 light->extraDist = FloatForKey( e, "_extradist" );
405 if(light->extraDist == 0.0f)
406 light->extraDist = extraDist;
408 intensity = intensity * pointScale;
409 light->photons = intensity;
411 light->type = EMIT_POINT;
413 /* set falloff threshold */
414 light->falloffTolerance = falloffTolerance / numSamples;
416 /* lights with a target will be spotlights */
417 target = ValueForKey( e, "target" );
427 e2 = FindTargetEntity( target );
430 Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
431 (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
435 /* not a point light */
439 /* make a spotlight */
440 GetVectorForKey( e2, "origin", dest );
441 VectorSubtract( dest, light->origin, light->normal );
442 dist = VectorNormalize( light->normal, light->normal );
443 radius = FloatForKey( e, "radius" );
448 light->radiusByDist = (radius + 16) / dist;
449 light->type = EMIT_SPOT;
451 /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
452 light->flags &= ~LIGHT_ATTEN_LINEAR;
453 light->flags |= LIGHT_ATTEN_ANGLE;
456 /* ydnar: is this a sun? */
457 _sun = ValueForKey( e, "_sun" );
458 if( _sun[ 0 ] == '1' )
460 /* not a spot light */
463 /* unlink this light */
464 lights = light->next;
467 VectorScale( light->normal, -1.0f, sun.direction );
468 VectorCopy( light->color, sun.color );
469 sun.photons = (intensity / pointScale);
470 sun.deviance = deviance / 180.0f * Q_PI;
471 sun.numSamples = numSamples;
472 sun.style = noStyles ? LS_NORMAL : light->style;
475 /* make a sun light */
476 CreateSunLight( &sun );
478 /* free original light */
482 /* skip the rest of this love story */
488 /* jitter the light */
489 for( j = 1; j < numSamples; j++ )
492 light2 = safe_malloc( sizeof( *light ) );
493 memcpy( light2, light, sizeof( *light ) );
494 light2->next = lights;
498 if( light->type == EMIT_SPOT )
504 light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
505 light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
506 light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
514 CreateSurfaceLights() - ydnar
515 this hijacks the radiosity code to generate surface lights for first pass
518 #define APPROX_BOUNCE 1.0f
520 void CreateSurfaceLights( void )
523 bspDrawSurface_t *ds;
533 /* get sun shader supressor */
534 nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
536 /* walk the list of surfaces */
537 for( i = 0; i < numBSPDrawSurfaces; i++ )
539 /* get surface and other bits */
540 ds = &bspDrawSurfaces[ i ];
541 info = &surfaceInfos[ i ];
545 if( si->sun != NULL && nss[ 0 ] != '1' )
547 Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
548 CreateSunLight( si->sun );
549 si->sun = NULL; /* FIXME: leak! */
553 if( si->skyLightValue > 0.0f )
555 Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
556 CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius, si->lightStyle );
557 si->skyLightValue = 0.0f; /* FIXME: hack! */
560 /* try to early out */
564 /* autosprite shaders become point lights */
567 /* create an average xyz */
568 VectorAdd( info->mins, info->maxs, origin );
569 VectorScale( origin, 0.5f, origin );
572 light = safe_malloc( sizeof( *light ) );
573 memset( light, 0, sizeof( *light ) );
574 light->next = lights;
578 light->flags = LIGHT_Q3A_DEFAULT;
579 light->type = EMIT_POINT;
580 light->photons = si->value * pointScale;
583 VectorCopy( origin, light->origin );
584 VectorCopy( si->color, light->color );
585 light->falloffTolerance = falloffTolerance;
586 light->style = si->lightStyle;
588 /* add to point light count and continue */
593 /* get subdivision amount */
594 if( si->lightSubdivide > 0 )
595 subdivide = si->lightSubdivide;
597 subdivide = defaultLightSubdivide;
600 switch( ds->surfaceType )
603 case MST_TRIANGLE_SOUP:
604 RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
608 RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
621 find the offset values for inline models
624 void SetEntityOrigins( void )
632 bspDrawSurface_t *ds;
635 /* ydnar: copy drawverts into private storage for nefarious purposes */
636 yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
637 memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
639 /* set the entity origins */
640 for( i = 0; i < numEntities; i++ )
642 /* get entity and model */
644 key = ValueForKey( e, "model" );
645 if( key[ 0 ] != '*' )
647 modelnum = atoi( key + 1 );
648 dm = &bspModels[ modelnum ];
650 /* get entity origin */
651 key = ValueForKey( e, "origin" );
652 if( key[ 0 ] == '\0' )
654 GetVectorForKey( e, "origin", origin );
656 /* set origin for all surfaces for this model */
657 for( j = 0; j < dm->numBSPSurfaces; j++ )
660 ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
663 for( k = 0; k < ds->numVerts; k++ )
665 f = ds->firstVert + k;
666 VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
675 PointToPolygonFormFactor()
676 calculates the area over a point/normal hemisphere a winding covers
677 ydnar: fixme: there has to be a faster way to calculate this
678 without the expensive per-vert sqrts and transcendental functions
679 ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
680 between this and the approximation
683 #define ONE_OVER_2PI 0.159154942f //% (1.0f / (2.0f * 3.141592657f))
685 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
687 vec3_t triVector, triNormal;
689 vec3_t dirs[ MAX_POINTS_ON_WINDING ];
691 float dot, angle, facing;
694 /* this is expensive */
695 for( i = 0; i < w->numpoints; i++ )
697 VectorSubtract( w->p[ i ], point, dirs[ i ] );
698 VectorNormalize( dirs[ i ], dirs[ i ] );
701 /* duplicate first vertex to avoid mod operation */
702 VectorCopy( dirs[ 0 ], dirs[ i ] );
704 /* calculcate relative area */
706 for( i = 0; i < w->numpoints; i++ )
710 dot = DotProduct( dirs[ i ], dirs[ j ] );
712 /* roundoff can cause slight creep, which gives an IND from acos */
715 else if( dot < -1.0f )
721 CrossProduct( dirs[ i ], dirs[ j ], triVector );
722 if( VectorNormalize( triVector, triNormal ) < 0.0001f )
725 facing = DotProduct( normal, triNormal );
726 total += facing * angle;
728 /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
729 if( total > 6.3f || total < -6.3f )
733 /* now in the range of 0 to 1 over the entire incoming hemisphere */
734 //% total /= (2.0f * 3.141592657f);
735 total *= ONE_OVER_2PI;
742 LightContributionTosample()
743 determines the amount of light reaching a sample (luxel or vertex) from a given light
746 int LightContributionToSample( trace_t *trace )
755 light = trace->light;
758 VectorClear( trace->color );
759 VectorClear( trace->colorNoShadow );
761 /* ydnar: early out */
762 if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
765 /* do some culling checks */
766 if( light->type != EMIT_SUN )
768 /* MrE: if the light is behind the surface */
769 if( trace->twoSided == qfalse )
770 if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
773 /* ydnar: test pvs */
774 if( !ClusterVisible( trace->cluster, light->cluster ) )
778 /* exact point to polygon form factor */
779 if( light->type == EMIT_AREA )
785 /* project sample point into light plane */
786 d = DotProduct( trace->origin, light->normal ) - light->dist;
789 /* sample point behind plane? */
790 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
793 /* sample plane coincident? */
794 if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
798 /* nudge the point so that it is clearly forward of the light */
799 /* so that surfaces meeting a light emiter don't get black edges */
800 if( d > -8.0f && d < 8.0f )
801 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
803 VectorCopy( trace->origin, pushedOrigin );
805 /* get direction and distance */
806 VectorCopy( light->origin, trace->end );
807 dist = SetupTrace( trace );
808 if( dist >= light->envelope )
811 /* ptpff approximation */
814 /* angle attenuation */
815 angle = DotProduct( trace->normal, trace->direction );
817 /* twosided lighting */
818 if( trace->twoSided )
819 angle = fabs( angle );
822 angle *= -DotProduct( light->normal, trace->direction );
825 else if( angle < 0.0f &&
826 (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
829 /* clamp the distance to prevent super hot spots */
830 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
834 add = light->photons / (dist * dist) * angle;
838 /* calculate the contribution */
839 factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
842 else if( factor < 0.0f )
844 /* twosided lighting */
845 if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
849 /* push light origin to other side of the plane */
850 VectorMA( light->origin, -2.0f, light->normal, trace->end );
851 dist = SetupTrace( trace );
852 if( dist >= light->envelope )
859 /* ydnar: moved to here */
860 add = factor * light->add;
864 /* point/spot lights */
865 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
867 /* get direction and distance */
868 VectorCopy( light->origin, trace->end );
869 dist = SetupTrace( trace );
870 if( dist >= light->envelope )
873 /* clamp the distance to prevent super hot spots */
874 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
878 /* angle attenuation */
879 if( light->flags & LIGHT_ATTEN_ANGLE )
881 /* standard Lambert attenuation */
882 float dot = DotProduct( trace->normal, trace->direction );
884 /* twosided lighting */
885 if( trace->twoSided )
888 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
891 if( dot > 0.001f ) // skip coplanar
893 if( dot > 1.0f ) dot = 1.0f;
894 dot = ( dot * 0.5f ) + 0.5f;
906 if( light->angleScale != 0.0f )
908 angle /= light->angleScale;
914 if( light->flags & LIGHT_ATTEN_LINEAR )
916 add = angle * light->photons * linearScale - (dist * light->fade);
921 add = (light->photons / (dist * dist)) * angle;
923 /* handle spotlights */
924 if( light->type == EMIT_SPOT )
926 float distByNormal, radiusAtDist, sampleRadius;
927 vec3_t pointAtDist, distToSample;
929 /* do cone calculation */
930 distByNormal = -DotProduct( trace->displacement, light->normal );
931 if( distByNormal < 0.0f )
933 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
934 radiusAtDist = light->radiusByDist * distByNormal;
935 VectorSubtract( trace->origin, pointAtDist, distToSample );
936 sampleRadius = VectorLength( distToSample );
938 /* outside the cone */
939 if( sampleRadius >= radiusAtDist )
943 if( sampleRadius > (radiusAtDist - 32.0f) )
944 add *= ((radiusAtDist - sampleRadius) / 32.0f);
948 /* ydnar: sunlight */
949 else if( light->type == EMIT_SUN )
951 /* get origin and direction */
952 VectorAdd( trace->origin, light->origin, trace->end );
953 dist = SetupTrace( trace );
955 /* angle attenuation */
956 if( light->flags & LIGHT_ATTEN_ANGLE )
958 /* standard Lambert attenuation */
959 float dot = DotProduct( trace->normal, trace->direction );
961 /* twosided lighting */
962 if( trace->twoSided )
965 /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
968 if( dot > 0.001f ) // skip coplanar
970 if( dot > 1.0f ) dot = 1.0f;
971 dot = ( dot * 0.5f ) + 0.5f;
984 add = light->photons * angle;
988 /* VorteX: set noShadow color */
989 VectorScale(light->color, add, trace->colorNoShadow);
992 trace->testAll = qtrue;
993 VectorScale( light->color, add, trace->color );
996 if( trace->testOcclusion && !trace->forceSunlight )
1000 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1002 VectorClear( trace->color );
1007 /* return to sender */
1011 /* VorteX: set noShadow color */
1012 VectorScale(light->color, add, trace->colorNoShadow);
1014 /* ydnar: changed to a variable number */
1015 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1019 trace->testAll = qfalse;
1020 VectorScale( light->color, add, trace->color );
1024 if( trace->passSolid || trace->opaque )
1026 VectorClear( trace->color );
1030 /* return to sender */
1038 determines the amount of light reaching a sample (luxel or vertex)
1041 void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
1047 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1048 VectorClear( colors[ lightmapNum ] );
1050 /* ydnar: normalmap */
1053 colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
1054 colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
1055 colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
1059 /* ydnar: don't bounce ambient all the time */
1061 VectorCopy( ambientColor, colors[ 0 ] );
1063 /* ydnar: trace to all the list of lights pre-stored in tw */
1064 for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
1067 trace->light = trace->lights[ i ];
1070 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1072 if( styles[ lightmapNum ] == trace->light->style ||
1073 styles[ lightmapNum ] == LS_NONE )
1077 /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
1078 if( lightmapNum >= MAX_LIGHTMAPS )
1082 LightContributionToSample( trace );
1083 if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
1086 /* handle negative light */
1087 if( trace->light->flags & LIGHT_NEGATIVE )
1088 VectorScale( trace->color, -1.0f, trace->color );
1091 styles[ lightmapNum ] = trace->light->style;
1094 VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
1098 colors[ 0 ][ 0 ] >= 255.0f &&
1099 colors[ 0 ][ 1 ] >= 255.0f &&
1100 colors[ 0 ][ 2 ] >= 255.0f )
1108 LightContributionToPoint()
1109 for a given light, how much light/color reaches a given point in space (with no facing)
1110 note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
1113 int LightContributionToPoint( trace_t *trace )
1120 light = trace->light;
1123 VectorClear( trace->color );
1125 /* ydnar: early out */
1126 if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
1129 /* is this a sun? */
1130 if( light->type != EMIT_SUN )
1137 if( !ClusterVisible( trace->cluster, light->cluster ) )
1141 /* ydnar: check origin against light's pvs envelope */
1142 if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
1143 trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
1144 trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
1150 /* set light origin */
1151 if( light->type == EMIT_SUN )
1152 VectorAdd( trace->origin, light->origin, trace->end );
1154 VectorCopy( light->origin, trace->end );
1157 dist = SetupTrace( trace );
1160 if( dist > light->envelope )
1162 gridEnvelopeCulled++;
1166 /* ptpff approximation */
1167 if( light->type == EMIT_AREA && faster )
1169 /* clamp the distance to prevent super hot spots */
1170 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1175 add = light->photons / (dist * dist);
1178 /* exact point to polygon form factor */
1179 else if( light->type == EMIT_AREA )
1182 vec3_t pushedOrigin;
1185 /* see if the point is behind the light */
1186 d = DotProduct( trace->origin, light->normal ) - light->dist;
1187 if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
1190 /* nudge the point so that it is clearly forward of the light */
1191 /* so that surfaces meeting a light emiter don't get black edges */
1192 if( d > -8.0f && d < 8.0f )
1193 VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
1195 VectorCopy( trace->origin, pushedOrigin );
1197 /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
1198 factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
1199 if( factor == 0.0f )
1201 else if( factor < 0.0f )
1203 if( light->flags & LIGHT_TWOSIDED )
1209 /* ydnar: moved to here */
1210 add = factor * light->add;
1213 /* point/spot lights */
1214 else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
1216 /* clamp the distance to prevent super hot spots */
1217 dist = sqrt(dist * dist + light->extraDist * light->extraDist);
1222 if( light->flags & LIGHT_ATTEN_LINEAR )
1224 add = light->photons * linearScale - (dist * light->fade);
1229 add = light->photons / (dist * dist);
1231 /* handle spotlights */
1232 if( light->type == EMIT_SPOT )
1234 float distByNormal, radiusAtDist, sampleRadius;
1235 vec3_t pointAtDist, distToSample;
1238 /* do cone calculation */
1239 distByNormal = -DotProduct( trace->displacement, light->normal );
1240 if( distByNormal < 0.0f )
1242 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
1243 radiusAtDist = light->radiusByDist * distByNormal;
1244 VectorSubtract( trace->origin, pointAtDist, distToSample );
1245 sampleRadius = VectorLength( distToSample );
1247 /* outside the cone */
1248 if( sampleRadius >= radiusAtDist )
1252 if( sampleRadius > (radiusAtDist - 32.0f) )
1253 add *= ((radiusAtDist - sampleRadius) / 32.0f);
1257 /* ydnar: sunlight */
1258 else if( light->type == EMIT_SUN )
1261 add = light->photons;
1266 trace->testAll = qtrue;
1267 VectorScale( light->color, add, trace->color );
1269 /* trace to point */
1270 if( trace->testOcclusion && !trace->forceSunlight )
1274 if( !(trace->compileFlags & C_SKY) || trace->opaque )
1276 VectorClear( trace->color );
1281 /* return to sender */
1285 /* unknown light type */
1289 /* ydnar: changed to a variable number */
1290 if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
1294 trace->testAll = qfalse;
1295 VectorScale( light->color, add, trace->color );
1299 if( trace->passSolid )
1301 VectorClear( trace->color );
1305 /* we have a valid sample */
1313 grid samples are for quickly determining the lighting
1314 of dynamically placed entities in the world
1317 #define MAX_CONTRIBUTIONS 32768
1327 void TraceGrid( int num )
1329 int i, j, x, y, z, mod, numCon, numStyles;
1331 vec3_t baseOrigin, cheapColor, color, thisdir;
1333 bspGridPoint_t *bgp;
1334 contribution_t contributions[ MAX_CONTRIBUTIONS ];
1337 /* get grid points */
1338 gp = &rawGridPoints[ num ];
1339 bgp = &bspGridPoints[ num ];
1341 /* get grid origin */
1343 z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
1344 mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
1345 y = mod / gridBounds[ 0 ];
1346 mod -= y * gridBounds[ 0 ];
1349 trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
1350 trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
1351 trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
1353 /* set inhibit sphere */
1354 if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
1355 trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
1356 else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
1357 trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
1359 trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
1361 /* find point cluster */
1362 trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
1363 if( trace.cluster < 0 )
1365 /* try to nudge the origin around to find a valid point */
1366 VectorCopy( trace.origin, baseOrigin );
1367 for( step = 0; (step += 0.005) <= 1.0; )
1369 VectorCopy( baseOrigin, trace.origin );
1370 trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
1371 trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
1372 trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
1374 /* ydnar: changed to find cluster num */
1375 trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
1376 if( trace.cluster >= 0 )
1380 /* can't find a valid point at all */
1386 trace.testOcclusion = !noTrace;
1387 trace.forceSunlight = qfalse;
1388 trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
1389 trace.numSurfaces = 0;
1390 trace.surfaces = NULL;
1391 trace.numLights = 0;
1392 trace.lights = NULL;
1396 VectorClear( cheapColor );
1398 /* trace to all the lights, find the major light direction, and divide the
1399 total light between that along the direction and the remaining in the ambient */
1400 for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
1406 if( !LightContributionToPoint( &trace ) )
1409 /* handle negative light */
1410 if( trace.light->flags & LIGHT_NEGATIVE )
1411 VectorScale( trace.color, -1.0f, trace.color );
1413 /* add a contribution */
1414 VectorCopy( trace.color, contributions[ numCon ].color );
1415 VectorCopy( trace.direction, contributions[ numCon ].dir );
1416 contributions[ numCon ].style = trace.light->style;
1419 /* push average direction around */
1420 addSize = VectorLength( trace.color );
1421 VectorMA( gp->dir, addSize, trace.direction, gp->dir );
1423 /* stop after a while */
1424 if( numCon >= (MAX_CONTRIBUTIONS - 1) )
1427 /* ydnar: cheap mode */
1428 VectorAdd( cheapColor, trace.color, cheapColor );
1429 if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
1433 /////// Floodlighting for point //////////////////
1434 //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1440 col[0]=col[1]=col[2]=floodlightIntensity;
1444 trace.testOcclusion = qtrue;
1445 trace.forceSunlight = qfalse;
1446 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1447 trace.testAll = qtrue;
1451 if (q==0) //upper hemisphere
1457 else //lower hemisphere
1464 f = FloodLightForSample(&trace, floodlightDistance, floodlight_lowquality);
1466 contributions[ numCon ].color[0]=col[0]*f;
1467 contributions[ numCon ].color[1]=col[1]*f;
1468 contributions[ numCon ].color[2]=col[2]*f;
1470 contributions[ numCon ].dir[0]=dir[0];
1471 contributions[ numCon ].dir[1]=dir[1];
1472 contributions[ numCon ].dir[2]=dir[2];
1474 contributions[ numCon ].style = 0;
1476 /* push average direction around */
1477 addSize = VectorLength( col );
1478 VectorMA( gp->dir, addSize, dir, gp->dir );
1481 /////////////////////
1483 /* normalize to get primary light direction */
1484 VectorNormalize( gp->dir, thisdir );
1486 /* now that we have identified the primary light direction,
1487 go back and separate all the light into directed and ambient */
1490 for( i = 0; i < numCon; i++ )
1492 /* get relative directed strength */
1493 d = DotProduct( contributions[ i ].dir, thisdir );
1494 /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
1495 d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
1499 /* find appropriate style */
1500 for( j = 0; j < numStyles; j++ )
1502 if( gp->styles[ j ] == contributions[ i ].style )
1506 /* style not found? */
1507 if( j >= numStyles )
1509 /* add a new style */
1510 if( numStyles < MAX_LIGHTMAPS )
1512 gp->styles[ numStyles ] = contributions[ i ].style;
1513 bgp->styles[ numStyles ] = contributions[ i ].style;
1515 //% Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
1523 /* add the directed color */
1524 VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
1526 /* ambient light will be at 1/4 the value of directed light */
1527 /* (ydnar: nuke this in favor of more dramatic lighting?) */
1528 /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
1530 /* (Hobbes: always setting it to .25 is hardly any better) */
1531 d = 0.25f * (1.0f - d);
1532 VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
1536 * the total light average = ambient value + 0.25 * sum of all directional values
1537 * we can also get the total light average as 0.25 * the sum of all contributions
1539 * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
1542 * ambient == 0.25 * sum((1 - d_i) contribution_i)
1544 * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
1549 /* store off sample */
1550 for( i = 0; i < MAX_LIGHTMAPS; i++ )
1553 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
1555 VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
1558 /* set minimum light and copy off to bytes */
1559 VectorCopy( gp->ambient[ i ], color );
1560 for( j = 0; j < 3; j++ )
1561 if( color[ j ] < minGridLight[ j ] )
1562 color[ j ] = minGridLight[ j ];
1564 /* vortex: apply gridscale and gridambientscale here */
1565 ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
1566 ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
1571 //% Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
1572 Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
1574 gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
1575 gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
1578 /* store direction */
1579 NormalToLatLong( thisdir, bgp->latLong );
1586 calculates the size of the lightgrid and allocates memory
1589 void SetupGrid( void )
1592 vec3_t maxs, oldGridSize;
1597 /* don't do this if not grid lighting */
1598 if( noGridLighting )
1601 /* ydnar: set grid size */
1602 value = ValueForKey( &entities[ 0 ], "gridsize" );
1603 if( value[ 0 ] != '\0' )
1604 sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
1607 VectorCopy( gridSize, oldGridSize );
1608 for( i = 0; i < 3; i++ )
1609 gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
1611 /* ydnar: increase gridSize until grid count is smaller than max allowed */
1612 numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
1614 while( numRawGridPoints > MAX_MAP_LIGHTGRID )
1616 /* get world bounds */
1617 for( i = 0; i < 3; i++ )
1619 gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
1620 maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
1621 gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
1625 numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
1627 /* increase grid size a bit */
1628 if( numRawGridPoints > MAX_MAP_LIGHTGRID )
1629 gridSize[ j++ % 3 ] += 16.0f;
1633 Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1636 if( !VectorCompare( gridSize, oldGridSize ) )
1638 sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
1639 SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
1640 Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
1643 /* 2nd variable. fixme: is this silly? */
1644 numBSPGridPoints = numRawGridPoints;
1646 /* allocate lightgrid */
1647 rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
1648 memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
1650 if( bspGridPoints != NULL )
1651 free( bspGridPoints );
1652 bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
1653 memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
1655 /* clear lightgrid */
1656 for( i = 0; i < numRawGridPoints; i++ )
1658 VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
1659 rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1660 bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
1661 for( j = 1; j < MAX_LIGHTMAPS; j++ )
1663 rawGridPoints[ i ].styles[ j ] = LS_NONE;
1664 bspGridPoints[ i ].styles[ j ] = LS_NONE;
1669 Sys_Printf( "%9d grid points\n", numRawGridPoints );
1676 does what it says...
1679 void LightWorld( void )
1684 qboolean minVertex, minGrid, ps;
1688 /* ydnar: smooth normals */
1691 Sys_Printf( "--- SmoothNormals ---\n" );
1695 /* determine the number of grid points */
1696 Sys_Printf( "--- SetupGrid ---\n" );
1699 /* find the optional minimum lighting values */
1700 GetVectorForKey( &entities[ 0 ], "_color", color );
1701 if( VectorLength( color ) == 0.0f )
1702 VectorSet( color, 1.0, 1.0, 1.0 );
1705 f = FloatForKey( &entities[ 0 ], "_ambient" );
1707 f = FloatForKey( &entities[ 0 ], "ambient" );
1708 VectorScale( color, f, ambientColor );
1710 /* minvertexlight */
1712 value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
1713 if( value[ 0 ] != '\0' )
1717 VectorScale( color, f, minVertexLight );
1722 value = ValueForKey( &entities[ 0 ], "_mingridlight" );
1723 if( value[ 0 ] != '\0' )
1727 VectorScale( color, f, minGridLight );
1731 value = ValueForKey( &entities[ 0 ], "_minlight" );
1732 if( value[ 0 ] != '\0' )
1735 VectorScale( color, f, minLight );
1736 if( minVertex == qfalse )
1737 VectorScale( color, f, minVertexLight );
1738 if( minGrid == qfalse )
1739 VectorScale( color, f, minGridLight );
1742 /* create world lights */
1743 Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
1744 CreateEntityLights();
1745 CreateSurfaceLights();
1746 Sys_Printf( "%9d point lights\n", numPointLights );
1747 Sys_Printf( "%9d spotlights\n", numSpotLights );
1748 Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
1749 Sys_Printf( "%9d sun/sky lights\n", numSunLights );
1751 /* calculate lightgrid */
1752 if( !noGridLighting )
1754 /* ydnar: set up light envelopes */
1755 SetupEnvelopes( qtrue, fastgrid );
1757 Sys_Printf( "--- TraceGrid ---\n" );
1759 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1761 Sys_Printf( "%d x %d x %d = %d grid\n",
1762 gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
1764 /* ydnar: emit statistics on light culling */
1765 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1766 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1769 /* slight optimization to remove a sqrt */
1770 subdivideThreshold *= subdivideThreshold;
1772 /* map the world luxels */
1773 Sys_Printf( "--- MapRawLightmap ---\n" );
1774 RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
1775 Sys_Printf( "%9d luxels\n", numLuxels );
1776 Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
1777 Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
1782 Sys_Printf( "--- DirtyRawLightmap ---\n" );
1783 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1786 /* floodlight pass */
1787 FloodlightRawLightmaps();
1789 /* ydnar: set up light envelopes */
1790 SetupEnvelopes( qfalse, fast );
1792 /* light up my world */
1793 lightsPlaneCulled = 0;
1794 lightsEnvelopeCulled = 0;
1795 lightsBoundsCulled = 0;
1796 lightsClusterCulled = 0;
1798 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1799 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1800 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1802 StitchSurfaceLightmaps();
1804 Sys_Printf( "--- IlluminateVertexes ---\n" );
1805 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1806 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1808 /* ydnar: emit statistics on light culling */
1809 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1810 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1811 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1812 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1819 /* store off the bsp between bounces */
1820 StoreSurfaceLightmaps();
1822 Sys_Printf( "Writing %s\n", source );
1823 WriteBSPFile( source );
1826 Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
1830 VectorClear( ambientColor );
1831 floodlighty = qfalse;
1833 /* generate diffuse lights */
1835 RadCreateDiffuseLights();
1837 /* setup light envelopes */
1838 SetupEnvelopes( qfalse, fastbounce );
1839 if( numLights == 0 )
1841 Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
1845 /* add to lightgrid */
1848 gridEnvelopeCulled = 0;
1849 gridBoundsCulled = 0;
1851 Sys_Printf( "--- BounceGrid ---\n" );
1853 RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
1855 Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
1856 Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
1859 /* light up my world */
1860 lightsPlaneCulled = 0;
1861 lightsEnvelopeCulled = 0;
1862 lightsBoundsCulled = 0;
1863 lightsClusterCulled = 0;
1865 Sys_Printf( "--- IlluminateRawLightmap ---\n" );
1866 RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
1867 Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
1868 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1870 StitchSurfaceLightmaps();
1872 Sys_Printf( "--- IlluminateVertexes ---\n" );
1873 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
1874 Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
1876 /* ydnar: emit statistics on light culling */
1877 Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
1878 Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
1879 Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
1880 Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
1892 main routine for light processing
1895 int LightMain( int argc, char **argv )
1899 char mapSource[ 1024 ];
1901 int lightmapMergeSize = 0;
1905 Sys_Printf( "--- Light ---\n" );
1906 Sys_Printf( "--- ProcessGameSpecific ---\n" );
1908 /* set standard game flags */
1909 wolfLight = game->wolfLight;
1910 if (wolfLight == qtrue)
1911 Sys_Printf( " lightning model: wolf\n" );
1913 Sys_Printf( " lightning model: quake3\n" );
1915 lmCustomSize = game->lightmapSize;
1916 Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
1918 lightmapGamma = game->lightmapGamma;
1919 Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
1921 lightmapCompensate = game->lightmapCompensate;
1922 Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
1924 lightmapExposure = game->lightmapExposure;
1925 Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
1927 gridScale = game->gridScale;
1928 Sys_Printf( " lightgrid scale: %f\n", gridScale );
1930 gridAmbientScale = game->gridAmbientScale;
1931 Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
1933 lightAngleHL = game->lightAngleHL;
1935 Sys_Printf( " half lambert light angle attenuation enabled \n" );
1937 noStyles = game->noStyles;
1938 if (noStyles == qtrue)
1939 Sys_Printf( " shader lightstyles hack: disabled\n" );
1941 Sys_Printf( " shader lightstyles hack: enabled\n" );
1943 keepLights = game->keepLights;
1944 if (keepLights == qtrue)
1945 Sys_Printf( " keep lights: enabled\n" );
1947 Sys_Printf( " keep lights: disabled\n" );
1949 patchShadows = game->patchShadows;
1950 if (patchShadows == qtrue)
1951 Sys_Printf( " patch shadows: enabled\n" );
1953 Sys_Printf( " patch shadows: disabled\n" );
1955 deluxemap = game->deluxeMap;
1956 deluxemode = game->deluxeMode;
1957 if (deluxemap == qtrue)
1960 Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
1962 Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
1965 Sys_Printf( " deluxemapping: disabled\n" );
1967 Sys_Printf( "--- ProcessCommandLine ---\n" );
1969 /* process commandline arguments */
1970 for( i = 1; i < (argc - 1); i++ )
1972 /* lightsource scaling */
1973 if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
1975 f = atof( argv[ i + 1 ] );
1977 Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
1981 else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
1983 f = atof( argv[ i + 1 ] );
1985 Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
1989 else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
1991 f = atof( argv[ i + 1 ] );
1993 Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
1997 else if( !strcmp( argv[ i ], "-bouncescale" ) )
1999 f = atof( argv[ i + 1 ] );
2001 Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
2005 else if( !strcmp( argv[ i ], "-scale" ) )
2007 f = atof( argv[ i + 1 ] );
2012 Sys_Printf( "All light scaled by %f\n", f );
2016 else if( !strcmp( argv[ i ], "-gridscale" ) )
2018 f = atof( argv[ i + 1 ] );
2019 Sys_Printf( "Grid lightning scaled by %f\n", f );
2024 else if( !strcmp( argv[ i ], "-gridambientscale" ) )
2026 f = atof( argv[ i + 1 ] );
2027 Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
2028 gridAmbientScale *= f;
2032 else if( !strcmp( argv[ i ], "-griddirectionality" ) )
2034 f = atof( argv[ i + 1 ] );
2036 if(f > gridAmbientDirectionality) f = gridAmbientDirectionality;
2037 Sys_Printf( "Grid directionality is %f\n", f );
2038 gridDirectionality *= f;
2042 else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
2044 f = atof( argv[ i + 1 ] );
2045 if(f > gridDirectionality) f = gridDirectionality;
2047 Sys_Printf( "Grid ambient directionality is %f\n", f );
2048 gridAmbientDirectionality *= f;
2052 else if( !strcmp( argv[ i ], "-gamma" ) )
2054 f = atof( argv[ i + 1 ] );
2056 Sys_Printf( "Lighting gamma set to %f\n", lightmapGamma );
2060 else if( !strcmp( argv[ i ], "-exposure" ) )
2062 f = atof( argv[ i + 1 ] );
2063 lightmapExposure = f;
2064 Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2068 else if( !strcmp( argv[ i ], "-compensate" ) )
2070 f = atof( argv[ i + 1 ] );
2073 lightmapCompensate = f;
2074 Sys_Printf( "Lighting compensation set to 1/%f\n", lightmapCompensate );
2078 /* ydnar switches */
2079 else if( !strcmp( argv[ i ], "-bounce" ) )
2081 bounce = atoi( argv[ i + 1 ] );
2084 else if( bounce > 0 )
2085 Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
2089 else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
2091 superSample = atoi( argv[ i + 1 ] );
2092 if( superSample < 1 )
2094 else if( superSample > 1 )
2095 Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
2099 else if( !strcmp( argv[ i ], "-samples" ) )
2101 lightSamples = atoi( argv[ i + 1 ] );
2102 if( lightSamples < 1 )
2104 else if( lightSamples > 1 )
2105 Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
2109 else if( !strcmp( argv[ i ], "-filter" ) )
2112 Sys_Printf( "Lightmap filtering enabled\n" );
2115 else if( !strcmp( argv[ i ], "-dark" ) )
2118 Sys_Printf( "Dark lightmap seams enabled\n" );
2121 else if( !strcmp( argv[ i ], "-shadeangle" ) )
2123 shadeAngleDegrees = atof( argv[ i + 1 ] );
2124 if( shadeAngleDegrees < 0.0f )
2125 shadeAngleDegrees = 0.0f;
2126 else if( shadeAngleDegrees > 0.0f )
2129 Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
2134 else if( !strcmp( argv[ i ], "-thresh" ) )
2136 subdivideThreshold = atof( argv[ i + 1 ] );
2137 if( subdivideThreshold < 0 )
2138 subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
2140 Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
2144 else if( !strcmp( argv[ i ], "-approx" ) )
2146 approximateTolerance = atoi( argv[ i + 1 ] );
2147 if( approximateTolerance < 0 )
2148 approximateTolerance = 0;
2149 else if( approximateTolerance > 0 )
2150 Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
2153 else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
2156 Sys_Printf( "Generating deluxemaps for average light direction\n" );
2158 else if( !strcmp( argv[ i ], "-deluxemode" ))
2160 deluxemode = atoi( argv[ i + 1 ] );
2161 if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
2163 Sys_Printf( "Generating modelspace deluxemaps\n" );
2167 Sys_Printf( "Generating tangentspace deluxemaps\n" );
2170 else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
2173 Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
2175 else if( !strcmp( argv[ i ], "-external" ) )
2177 externalLightmaps = qtrue;
2178 Sys_Printf( "Storing all lightmaps externally\n" );
2181 else if( !strcmp( argv[ i ], "-lightmapsize" ) )
2183 lmCustomSize = atoi( argv[ i + 1 ] );
2185 /* must be a power of 2 and greater than 2 */
2186 if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
2188 Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
2189 lmCustomSize = game->lightmapSize;
2192 Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
2194 /* enable external lightmaps */
2195 if( lmCustomSize != game->lightmapSize )
2197 externalLightmaps = qtrue;
2198 Sys_Printf( "Storing all lightmaps externally\n" );
2202 else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
2204 lmLimitSize = atoi( argv[ i + 1 ] );
2207 Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
2210 else if( !strcmp( argv[ i ], "-lightmapdir" ) )
2212 lmCustomDir = argv[i + 1];
2214 Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
2215 externalLightmaps = qtrue;
2216 Sys_Printf( "Storing all lightmaps externally\n" );
2219 /* ydnar: add this to suppress warnings */
2220 else if( !strcmp( argv[ i ], "-custinfoparms") )
2222 Sys_Printf( "Custom info parms enabled\n" );
2223 useCustomInfoParms = qtrue;
2226 else if( !strcmp( argv[ i ], "-wolf" ) )
2228 /* -game should already be set */
2230 Sys_Printf( "Enabling Wolf lighting model (linear default)\n" );
2233 else if( !strcmp( argv[ i ], "-q3" ) )
2235 /* -game should already be set */
2237 Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
2240 else if( !strcmp( argv[ i ], "-extradist" ) )
2242 extraDist = atof( argv[ i + 1 ] );
2246 Sys_Printf( "Default extra radius set to %f units\n", extraDist );
2249 else if( !strcmp( argv[ i ], "-sunonly" ) )
2252 Sys_Printf( "Only computing sunlight\n" );
2255 else if( !strcmp( argv[ i ], "-bounceonly" ) )
2258 Sys_Printf( "Storing bounced light (radiosity) only\n" );
2261 else if( !strcmp( argv[ i ], "-nocollapse" ) )
2264 Sys_Printf( "Identical lightmap collapsing disabled\n" );
2267 else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
2269 lightmapSearchBlockSize = 1;
2270 Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
2273 else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
2275 lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
2277 Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
2280 else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
2282 lightmapSearchBlockSize = atoi(argv[i+1]);
2284 Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
2287 else if( !strcmp( argv[ i ], "-shade" ) )
2290 Sys_Printf( "Phong shading enabled\n" );
2293 else if( !strcmp( argv[ i ], "-bouncegrid") )
2297 Sys_Printf( "Grid lighting with radiosity enabled\n" );
2300 else if( !strcmp( argv[ i ], "-smooth" ) )
2302 lightSamples = EXTRA_SCALE;
2303 Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
2306 else if( !strcmp( argv[ i ], "-fast" ) )
2311 Sys_Printf( "Fast mode enabled\n" );
2314 else if( !strcmp( argv[ i ], "-faster" ) )
2320 Sys_Printf( "Faster mode enabled\n" );
2323 else if( !strcmp( argv[ i ], "-fastgrid" ) )
2326 Sys_Printf( "Fast grid lighting enabled\n" );
2329 else if( !strcmp( argv[ i ], "-fastbounce" ) )
2332 Sys_Printf( "Fast bounce mode enabled\n" );
2335 else if( !strcmp( argv[ i ], "-cheap" ) )
2339 Sys_Printf( "Cheap mode enabled\n" );
2342 else if( !strcmp( argv[ i ], "-cheapgrid" ) )
2345 Sys_Printf( "Cheap grid mode enabled\n" );
2348 else if( !strcmp( argv[ i ], "-normalmap" ) )
2351 Sys_Printf( "Storing normal map instead of lightmap\n" );
2354 else if( !strcmp( argv[ i ], "-trisoup" ) )
2357 Sys_Printf( "Converting brush faces to triangle soup\n" );
2360 else if( !strcmp( argv[ i ], "-debug" ) )
2363 Sys_Printf( "Lightmap debugging enabled\n" );
2366 else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
2368 debugSurfaces = qtrue;
2369 Sys_Printf( "Lightmap surface debugging enabled\n" );
2372 else if( !strcmp( argv[ i ], "-debugunused" ) )
2374 debugUnused = qtrue;
2375 Sys_Printf( "Unused luxel debugging enabled\n" );
2378 else if( !strcmp( argv[ i ], "-debugaxis" ) )
2381 Sys_Printf( "Lightmap axis debugging enabled\n" );
2384 else if( !strcmp( argv[ i ], "-debugcluster" ) )
2386 debugCluster = qtrue;
2387 Sys_Printf( "Luxel cluster debugging enabled\n" );
2390 else if( !strcmp( argv[ i ], "-debugorigin" ) )
2392 debugOrigin = qtrue;
2393 Sys_Printf( "Luxel origin debugging enabled\n" );
2396 else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
2399 debugDeluxemap = qtrue;
2400 Sys_Printf( "Deluxemap debugging enabled\n" );
2403 else if( !strcmp( argv[ i ], "-export" ) )
2405 exportLightmaps = qtrue;
2406 Sys_Printf( "Exporting lightmaps\n" );
2409 else if( !strcmp(argv[ i ], "-notrace" ))
2412 Sys_Printf( "Shadow occlusion disabled\n" );
2414 else if( !strcmp(argv[ i ], "-patchshadows" ) )
2416 patchShadows = qtrue;
2417 Sys_Printf( "Patch shadow casting enabled\n" );
2419 else if( !strcmp( argv[ i ], "-extra" ) )
2421 superSample = EXTRA_SCALE; /* ydnar */
2422 Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
2424 else if( !strcmp( argv[ i ], "-extrawide" ) )
2426 superSample = EXTRAWIDE_SCALE; /* ydnar */
2427 filter = qtrue; /* ydnar */
2428 Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
2430 else if( !strcmp( argv[ i ], "-samplesize" ) )
2432 sampleSize = atoi( argv[ i + 1 ] );
2433 if( sampleSize < 1 )
2436 Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
2438 else if( !strcmp( argv[ i ], "-minsamplesize" ) )
2440 minSampleSize = atoi( argv[ i + 1 ] );
2441 if( minSampleSize < 1 )
2444 Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
2446 else if( !strcmp( argv[ i ], "-samplescale" ) )
2448 sampleScale = atoi( argv[ i + 1 ] );
2450 Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
2452 else if( !strcmp( argv[ i ], "-novertex" ) )
2454 noVertexLighting = qtrue;
2455 Sys_Printf( "Disabling vertex lighting\n" );
2457 else if( !strcmp( argv[ i ], "-nogrid" ) )
2459 noGridLighting = qtrue;
2460 Sys_Printf( "Disabling grid lighting\n" );
2462 else if( !strcmp( argv[ i ], "-border" ) )
2464 lightmapBorder = qtrue;
2465 Sys_Printf( "Adding debug border to lightmaps\n" );
2467 else if( !strcmp( argv[ i ], "-nosurf" ) )
2470 Sys_Printf( "Not tracing against surfaces\n" );
2472 else if( !strcmp( argv[ i ], "-dump" ) )
2475 Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
2477 else if( !strcmp( argv[ i ], "-lomem" ) )
2480 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
2482 else if( !strcmp( argv[ i ], "-lightanglehl" ) )
2484 if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
2486 lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
2488 Sys_Printf( "Enabling half lambert light angle attenuation\n" );
2490 Sys_Printf( "Disabling half lambert light angle attenuation\n" );
2493 else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
2496 Sys_Printf( "Disabling lightstyles\n" );
2498 else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
2501 Sys_Printf( "Enabling lightstyles\n" );
2503 else if( !strcmp( argv[ i ], "-keeplights" ))
2506 Sys_Printf( "Leaving light entities on map after compile\n" );
2508 else if( !strcmp( argv[ i ], "-cpma" ) )
2511 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
2513 else if( !strcmp( argv[ i ], "-floodlight" ) )
2515 floodlighty = qtrue;
2516 Sys_Printf( "FloodLighting enabled\n" );
2518 else if( !strcmp( argv[ i ], "-debugnormals" ) )
2520 debugnormals = qtrue;
2521 Sys_Printf( "DebugNormals enabled\n" );
2523 else if( !strcmp( argv[ i ], "-lowquality" ) )
2525 floodlight_lowquality = qtrue;
2526 Sys_Printf( "Low Quality FloodLighting enabled\n" );
2529 /* r7: dirtmapping */
2530 else if( !strcmp( argv[ i ], "-dirty" ) )
2533 Sys_Printf( "Dirtmapping enabled\n" );
2535 else if( !strcmp( argv[ i ], "-dirtdebug" ) || !strcmp( argv[ i ], "-debugdirt" ) )
2538 Sys_Printf( "Dirtmap debugging enabled\n" );
2540 else if( !strcmp( argv[ i ], "-dirtmode" ) )
2542 dirtMode = atoi( argv[ i + 1 ] );
2543 if( dirtMode != 0 && dirtMode != 1 )
2546 Sys_Printf( "Enabling randomized dirtmapping\n" );
2548 Sys_Printf( "Enabling ordered dir mapping\n" );
2551 else if( !strcmp( argv[ i ], "-dirtdepth" ) )
2553 dirtDepth = atof( argv[ i + 1 ] );
2554 if( dirtDepth <= 0.0f )
2556 Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
2559 else if( !strcmp( argv[ i ], "-dirtscale" ) )
2561 dirtScale = atof( argv[ i + 1 ] );
2562 if( dirtScale <= 0.0f )
2564 Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
2567 else if( !strcmp( argv[ i ], "-dirtgain" ) )
2569 dirtGain = atof( argv[ i + 1 ] );
2570 if( dirtGain <= 0.0f )
2572 Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
2575 else if( !strcmp( argv[ i ], "-trianglecheck" ) )
2577 lightmapTriangleCheck = qtrue;
2579 else if( !strcmp( argv[ i ], "-extravisnudge" ) )
2581 lightmapExtraVisClusterNudge = qtrue;
2583 /* unhandled args */
2586 Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
2591 /* fix up lightmap search power */
2592 if(lightmapMergeSize)
2594 lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
2595 if(lightmapSearchBlockSize < 1)
2596 lightmapSearchBlockSize = 1;
2598 Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
2601 /* clean up map name */
2602 strcpy( source, ExpandArg( argv[ i ] ) );
2603 StripExtension( source );
2604 DefaultExtension( source, ".bsp" );
2605 strcpy( mapSource, ExpandArg( argv[ i ] ) );
2606 StripExtension( mapSource );
2607 DefaultExtension( mapSource, ".map" );
2609 /* ydnar: set default sample size */
2610 SetDefaultSampleSize( sampleSize );
2612 /* ydnar: handle shaders */
2613 BeginMapShaderFile( source );
2617 Sys_Printf( "Loading %s\n", source );
2619 /* ydnar: load surface file */
2620 LoadSurfaceExtraFile( source );
2623 LoadBSPFile( source );
2625 /* parse bsp entities */
2628 /* inject command line parameters */
2629 InjectCommandLine(argv, 0, argc - 1);
2632 value = ValueForKey( &entities[ 0 ], "_keepLights" );
2633 if( value[ 0 ] != '1' )
2634 LoadMapFile( mapSource, qtrue );
2636 /* set the entity/model origins and init yDrawVerts */
2639 /* ydnar: set up optimization */
2643 SetupSurfaceLightmaps();
2645 /* initialize the surface facet tracing */
2648 /* light the world */
2651 /* ydnar: store off lightmaps */
2652 StoreSurfaceLightmaps();
2654 /* write out the bsp */
2656 Sys_Printf( "Writing %s\n", source );
2657 WriteBSPFile( source );
2659 /* ydnar: export lightmaps */
2660 if( exportLightmaps && !externalLightmaps )
2663 /* return to sender */