]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/light.c
eol style
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light.c
index 9ee61bea1412d8e07de0e705fd28ebca6d61e68d..670c9a0ed21ce2935b9ce45293dcf365c5e614a6 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-\r
-----------------------------------------------------------------------------------\r
-\r
-This code has been altered significantly from its original form, to support\r
-several games based on the Quake III Arena engine, in the form of "Q3Map2."\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-\r
-/* marker */\r
-#define LIGHT_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "q3map2.h"\r
-\r
-\r
-\r
-/*\r
-CreateSunLight() - ydnar\r
-this creates a sun light\r
-*/\r
-\r
-static void CreateSunLight( sun_t *sun )\r
-{\r
-       int                     i;\r
-       float           photons, d, angle, elevation, da, de;\r
-       vec3_t          direction;\r
-       light_t         *light;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( sun == NULL )\r
-               return;\r
-       \r
-       /* fixup */\r
-       if( sun->numSamples < 1 )\r
-               sun->numSamples = 1;\r
-       \r
-       /* set photons */\r
-       photons = sun->photons / sun->numSamples;\r
-       \r
-       /* create the right number of suns */\r
-       for( i = 0; i < sun->numSamples; i++ )\r
-       {\r
-               /* calculate sun direction */\r
-               if( i == 0 )\r
-                       VectorCopy( sun->direction, direction );\r
-               else\r
-               {\r
-                       /*\r
-                               sun->direction[ 0 ] = cos( angle ) * cos( elevation );\r
-                               sun->direction[ 1 ] = sin( angle ) * cos( elevation );\r
-                               sun->direction[ 2 ] = sin( elevation );\r
-                               \r
-                               xz_dist   = sqrt( x*x + z*z )\r
-                               latitude  = atan2( xz_dist, y ) * RADIANS\r
-                               longitude = atan2( x,       z ) * RADIANS\r
-                       */\r
-                       \r
-                       d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );\r
-                       angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );\r
-                       elevation = atan2( sun->direction[ 2 ], d );\r
-                       \r
-                       /* jitter the angles (loop to keep random sample within sun->deviance steridians) */\r
-                       do\r
-                       {\r
-                               da = (Random() * 2.0f - 1.0f) * sun->deviance;\r
-                               de = (Random() * 2.0f - 1.0f) * sun->deviance;\r
-                       }\r
-                       while( (da * da + de * de) > (sun->deviance * sun->deviance) );\r
-                       angle += da;\r
-                       elevation += de;\r
-                       \r
-                       /* debug code */\r
-                       //%     Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );\r
-                       \r
-                       /* create new vector */\r
-                       direction[ 0 ] = cos( angle ) * cos( elevation );\r
-                       direction[ 1 ] = sin( angle ) * cos( elevation );\r
-                       direction[ 2 ] = sin( elevation );\r
-               }\r
-               \r
-               /* create a light */\r
-               numSunLights++;\r
-               light = safe_malloc( sizeof( *light ) );\r
-               memset( light, 0, sizeof( *light ) );\r
-               light->next = lights;\r
-               lights = light;\r
-               \r
-               /* initialize the light */\r
-               light->flags = LIGHT_SUN_DEFAULT;\r
-               light->type = EMIT_SUN;\r
-               light->fade = 1.0f;\r
-               light->falloffTolerance = falloffTolerance;\r
-               light->filterRadius = sun->filterRadius / sun->numSamples;\r
-               \r
-               /* set the light's position out to infinity */\r
-               VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin );    /* MAX_WORLD_COORD * 2.0f */\r
-               \r
-               /* set the facing to be the inverse of the sun direction */\r
-               VectorScale( direction, -1.0, light->normal );\r
-               light->dist = DotProduct( light->origin, light->normal );\r
-               \r
-               /* set color and photons */\r
-               VectorCopy( sun->color, light->color );\r
-               light->photons = photons * skyScale;\r
-       }\r
-\r
-       /* another sun? */\r
-       if( sun->next != NULL )\r
-               CreateSunLight( sun->next );\r
-}\r
-\r
-\r
-\r
-/*\r
-CreateSkyLights() - ydnar\r
-simulates sky light with multiple suns\r
-*/\r
-\r
-static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius )\r
-{\r
-       int                     c, i, j, k, numSuns;\r
-       float           step, start;\r
-       vec3_t          in;\r
-       sun_t           sun;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( value <= 0.0f || iterations < 2 )\r
-               return;\r
-       \r
-       /* calculate some stuff */\r
-       step = 2.0f / (iterations - 1);\r
-       start = -1.0f;\r
-       \r
-       /* basic sun setup */\r
-       VectorCopy( color, sun.color );\r
-       sun.deviance = 0.0f;\r
-       sun.filterRadius = filterRadius;\r
-       sun.numSamples = 1;\r
-       sun.next = NULL;\r
-       \r
-       /* iterate */\r
-       numSuns = 0;\r
-       for( c = 0; c < 2; c++ )\r
-       {\r
-               for( k = 0, in[ 2 ] = start; k < iterations; k++, in[ 2 ] += step )\r
-               {\r
-                       /* don't create sky light below the horizon */\r
-                       if( in[ 2 ] <= 0.0f )\r
-                               continue;\r
-                       \r
-                       for( j = 0, in[ 1 ] = start; j < iterations; j++, in[ 1 ] += step )\r
-                       {\r
-                               for( i = 0, in[ 0 ] = start; i < iterations; i++, in[ 0 ] += step )\r
-                               {\r
-                                       if( VectorNormalize( in, sun.direction ) )\r
-                                       {\r
-                                               if( c > 0 && numSuns > 0 )\r
-                                               {\r
-                                                       sun.photons = value / numSuns;\r
-                                                       CreateSunLight( &sun );\r
-                                               }\r
-                                               else\r
-                                                       numSuns++;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-CreateEntityLights()\r
-creates lights from light entities\r
-*/\r
-\r
-void CreateEntityLights( void )\r
-{\r
-       int                             i, j;\r
-       light_t                 *light, *light2;\r
-       entity_t                *e, *e2;\r
-       const char              *name;\r
-       const char              *target;\r
-       vec3_t                  dest;\r
-       const char              *_color;\r
-       float                   intensity, scale, deviance, filterRadius;\r
-       int                             spawnflags, flags, numSamples;\r
-       qboolean                junior;\r
-\r
-       \r
-       /* go throught entity list and find lights */\r
-       for( i = 0; i < numEntities; i++ )\r
-       {\r
-               /* get entity */\r
-               e = &entities[ i ];\r
-               name = ValueForKey( e, "classname" );\r
-               \r
-               /* ydnar: check for lightJunior */\r
-               if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )\r
-                       junior = qtrue;\r
-               else if( Q_strncasecmp( name, "light", 5 ) == 0 )\r
-                       junior = qfalse;\r
-               else\r
-                       continue;\r
-               \r
-               /* lights with target names (and therefore styles) are only parsed from BSP */\r
-               target = ValueForKey( e, "targetname" );\r
-               if( target[ 0 ] != '\0' && i >= numBSPEntities )\r
-                       continue;\r
-               \r
-               /* create a light */\r
-               numPointLights++;\r
-               light = safe_malloc( sizeof( *light ) );\r
-               memset( light, 0, sizeof( *light ) );\r
-               light->next = lights;\r
-               lights = light;\r
-               \r
-               /* handle spawnflags */\r
-               spawnflags = IntForKey( e, "spawnflags" );\r
-               \r
-               /* ydnar: quake 3+ light behavior */\r
-               if( game->wolfLight == qfalse )\r
-               {\r
-                       /* set default flags */\r
-                       flags = LIGHT_Q3A_DEFAULT;\r
-                       \r
-                       /* linear attenuation? */\r
-                       if( spawnflags & 1 )\r
-                       {\r
-                               flags |= LIGHT_ATTEN_LINEAR;\r
-                               flags &= ~LIGHT_ATTEN_ANGLE;\r
-                       }\r
-                       \r
-                       /* no angle attenuate? */\r
-                       if( spawnflags & 2 )\r
-                               flags &= ~LIGHT_ATTEN_ANGLE;\r
-               }\r
-               \r
-               /* ydnar: wolf light behavior */\r
-               else\r
-               {\r
-                       /* set default flags */\r
-                       flags = LIGHT_WOLF_DEFAULT;\r
-                       \r
-                       /* inverse distance squared attenuation? */\r
-                       if( spawnflags & 1 )\r
-                       {\r
-                               flags &= ~LIGHT_ATTEN_LINEAR;\r
-                               flags |= LIGHT_ATTEN_ANGLE;\r
-                       }\r
-                       \r
-                       /* angle attenuate? */\r
-                       if( spawnflags & 2 )\r
-                               flags |= LIGHT_ATTEN_ANGLE;\r
-               }\r
-               \r
-               /* other flags (borrowed from wolf) */\r
-               \r
-               /* wolf dark light? */\r
-               if( (spawnflags & 4) || (spawnflags & 8) )\r
-                       flags |= LIGHT_DARK;\r
-               \r
-               /* nogrid? */\r
-               if( spawnflags & 16 )\r
-                       flags &= ~LIGHT_GRID;\r
-               \r
-               /* junior? */\r
-               if( junior )\r
-               {\r
-                       flags |= LIGHT_GRID;\r
-                       flags &= ~LIGHT_SURFACES;\r
-               }\r
-               \r
-               /* store the flags */\r
-               light->flags = flags;\r
-               \r
-               /* ydnar: set fade key (from wolf) */\r
-               light->fade = 1.0f;\r
-               if( light->flags & LIGHT_ATTEN_LINEAR )\r
-               {\r
-                       light->fade = FloatForKey( e, "fade" );\r
-                       if( light->fade == 0.0f )\r
-                               light->fade = 1.0f;\r
-               }\r
-               \r
-               /* ydnar: set angle scaling (from vlight) */\r
-               light->angleScale = FloatForKey( e, "_anglescale" );\r
-               if( light->angleScale != 0.0f )\r
-                       light->flags |= LIGHT_ATTEN_ANGLE;\r
-               \r
-               /* set origin */\r
-               GetVectorForKey( e, "origin", light->origin);\r
-               light->style = IntForKey( e, "_style" );\r
-               if( light->style == 0 )\r
-                       light->style = IntForKey( e, "style" );\r
-               if( light->style < LS_NORMAL || light->style >= LS_NONE )\r
-                       Error( "Invalid lightstyle (%d) on entity %d", light->style, i );\r
-               \r
-               /* set light intensity */\r
-               intensity = FloatForKey( e, "_light" );\r
-               if( intensity == 0.0f )\r
-                       intensity = FloatForKey( e, "light" );\r
-               if( intensity == 0.0f)\r
-                       intensity = 300.0f;\r
-               \r
-               /* ydnar: set light scale (sof2) */\r
-               scale = FloatForKey( e, "scale" );\r
-               if( scale == 0.0f )\r
-                       scale = 1.0f;\r
-               intensity *= scale;\r
-               \r
-               /* ydnar: get deviance and samples */\r
-               deviance = FloatForKey( e, "_deviance" );\r
-               if( deviance == 0.0f )\r
-                       deviance = FloatForKey( e, "_deviation" );\r
-               if( deviance == 0.0f )\r
-                       deviance = FloatForKey( e, "_jitter" );\r
-               numSamples = IntForKey( e, "_samples" );\r
-               if( deviance < 0.0f || numSamples < 1 )\r
-               {\r
-                       deviance = 0.0f;\r
-                       numSamples = 1;\r
-               }\r
-               intensity /= numSamples;\r
-               \r
-               /* ydnar: get filter radius */\r
-               filterRadius = FloatForKey( e, "_filterradius" );\r
-               if( filterRadius == 0.0f )\r
-                       filterRadius = FloatForKey( e, "_filteradius" );\r
-               if( filterRadius == 0.0f )\r
-                       filterRadius = FloatForKey( e, "_filter" );\r
-               if( filterRadius < 0.0f )\r
-                       filterRadius = 0.0f;\r
-               light->filterRadius = filterRadius;\r
-               \r
-               /* set light color */\r
-               _color = ValueForKey( e, "_color" );\r
-               if( _color && _color[ 0 ] )\r
-               {\r
-                       sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );\r
-                       ColorNormalize( light->color, light->color );\r
-               }\r
-               else\r
-                       light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;\r
-               \r
-               intensity = intensity * pointScale;\r
-               light->photons = intensity;\r
-               \r
-               light->type = EMIT_POINT;\r
-               \r
-               /* set falloff threshold */\r
-               light->falloffTolerance = falloffTolerance / numSamples;\r
-               \r
-               /* lights with a target will be spotlights */\r
-               target = ValueForKey( e, "target" );\r
-               if( target[ 0 ] )\r
-               {\r
-                       float           radius;\r
-                       float           dist;\r
-                       sun_t           sun;\r
-                       const char      *_sun;\r
-                       \r
-                       \r
-                       /* get target */\r
-                       e2 = FindTargetEntity( target );\r
-                       if( e2 == NULL )\r
-                       {\r
-                               Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",\r
-                                       (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* not a point light */\r
-                               numPointLights--;\r
-                               numSpotLights++;\r
-                               \r
-                               /* make a spotlight */\r
-                               GetVectorForKey( e2, "origin", dest );\r
-                               VectorSubtract( dest, light->origin, light->normal );\r
-                               dist = VectorNormalize( light->normal, light->normal );\r
-                               radius = FloatForKey( e, "radius" );\r
-                               if( !radius )\r
-                                       radius = 64;\r
-                               if( !dist )\r
-                                       dist = 64;\r
-                               light->radiusByDist = (radius + 16) / dist;\r
-                               light->type = EMIT_SPOT;\r
-                               \r
-                               /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */\r
-                               light->flags &= ~LIGHT_ATTEN_LINEAR;\r
-                               light->flags |= LIGHT_ATTEN_ANGLE;\r
-                               light->fade = 1.0f;\r
-                               \r
-                               /* ydnar: is this a sun? */\r
-                               _sun = ValueForKey( e, "_sun" );\r
-                               if( _sun[ 0 ] == '1' )\r
-                               {\r
-                                       /* not a spot light */\r
-                                       numSpotLights--;\r
-                                       \r
-                                       /* unlink this light */\r
-                                       lights = light->next;\r
-                                       \r
-                                       /* make a sun */\r
-                                       VectorScale( light->normal, -1.0f, sun.direction );\r
-                                       VectorCopy( light->color, sun.color );\r
-                                       sun.photons = (intensity / pointScale);\r
-                                       sun.deviance = deviance / 180.0f * Q_PI;\r
-                                       sun.numSamples = numSamples;\r
-                                       sun.next = NULL;\r
-                                       \r
-                                       /* make a sun light */\r
-                                       CreateSunLight( &sun );\r
-                                       \r
-                                       /* free original light */\r
-                                       free( light );\r
-                                       light = NULL;\r
-                                       \r
-                                       /* skip the rest of this love story */\r
-                                       continue;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* jitter the light */\r
-               for( j = 1; j < numSamples; j++ )\r
-               {\r
-                       /* create a light */\r
-                       light2 = safe_malloc( sizeof( *light ) );\r
-                       memcpy( light2, light, sizeof( *light ) );\r
-                       light2->next = lights;\r
-                       lights = light2;\r
-                       \r
-                       /* add to counts */\r
-                       if( light->type == EMIT_SPOT )\r
-                               numSpotLights++;\r
-                       else\r
-                               numPointLights++;\r
-                       \r
-                       /* jitter it */\r
-                       light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;\r
-                       light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;\r
-                       light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-CreateSurfaceLights() - ydnar\r
-this hijacks the radiosity code to generate surface lights for first pass\r
-*/\r
-\r
-#define APPROX_BOUNCE  1.0f\r
-\r
-void CreateSurfaceLights( void )\r
-{\r
-       int                                     i;\r
-       bspDrawSurface_t        *ds;\r
-       surfaceInfo_t           *info;\r
-       shaderInfo_t            *si;\r
-       light_t                         *light;\r
-       float                           subdivide;\r
-       vec3_t                          origin;\r
-       clipWork_t                      cw;\r
-       const char                      *nss;\r
-       \r
-       \r
-       /* get sun shader supressor */\r
-       nss = ValueForKey( &entities[ 0 ], "_noshadersun" );\r
-       \r
-       /* walk the list of surfaces */\r
-       for( i = 0; i < numBSPDrawSurfaces; i++ )\r
-       {\r
-               /* get surface and other bits */\r
-               ds = &bspDrawSurfaces[ i ];\r
-               info = &surfaceInfos[ i ];\r
-               si = info->si;\r
-               \r
-               /* sunlight? */\r
-               if( si->sun != NULL && nss[ 0 ] != '1' )\r
-               {\r
-                       Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );\r
-                       CreateSunLight( si->sun );\r
-                       si->sun = NULL; /* FIXME: leak! */\r
-               }\r
-               \r
-               /* sky light? */\r
-               if( si->skyLightValue > 0.0f )\r
-               {\r
-                       Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );\r
-                       CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius );\r
-                       si->skyLightValue = 0.0f;       /* FIXME: hack! */\r
-               }\r
-               \r
-               /* try to early out */\r
-               if( si->value <= 0 )\r
-                       continue;\r
-               \r
-               /* autosprite shaders become point lights */\r
-               if( si->autosprite )\r
-               {\r
-                       /* create an average xyz */\r
-                       VectorAdd( info->mins, info->maxs, origin );\r
-                       VectorScale( origin, 0.5f, origin );\r
-                       \r
-                       /* create a light */\r
-                       light = safe_malloc( sizeof( *light ) );\r
-                       memset( light, 0, sizeof( *light ) );\r
-                       light->next = lights;\r
-                       lights = light;\r
-                       \r
-                       /* set it up */\r
-                       light->flags = LIGHT_Q3A_DEFAULT;\r
-                       light->type = EMIT_POINT;\r
-                       light->photons = si->value * pointScale;\r
-                       light->fade = 1.0f;\r
-                       light->si = si;\r
-                       VectorCopy( origin, light->origin );\r
-                       VectorCopy( si->color, light->color );\r
-                       light->falloffTolerance = falloffTolerance;\r
-                       light->style = light->style;\r
-                       \r
-                       /* add to point light count and continue */\r
-                       numPointLights++;\r
-                       continue;\r
-               }\r
-               \r
-               /* get subdivision amount */\r
-               if( si->lightSubdivide > 0 )\r
-                       subdivide = si->lightSubdivide;\r
-               else\r
-                       subdivide = defaultLightSubdivide;\r
-               \r
-               /* switch on type */\r
-               switch( ds->surfaceType )\r
-               {\r
-                       case MST_PLANAR:\r
-                       case MST_TRIANGLE_SOUP:\r
-                               RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );\r
-                               break;\r
-                       \r
-                       case MST_PATCH:\r
-                               RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );\r
-                               break;\r
-                       \r
-                       default:\r
-                               break;\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-SetEntityOrigins()\r
-find the offset values for inline models\r
-*/\r
-\r
-void SetEntityOrigins( void )\r
-{\r
-       int                                     i, j, k, f;\r
-       entity_t                        *e;\r
-       vec3_t                          origin;\r
-       const char                      *key;\r
-       int                                     modelnum;\r
-       bspModel_t                      *dm;\r
-       bspDrawSurface_t        *ds;\r
-       \r
-       \r
-       /* ydnar: copy drawverts into private storage for nefarious purposes */\r
-       yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );\r
-       memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );\r
-       \r
-       /* set the entity origins */\r
-       for( i = 0; i < numEntities; i++ )\r
-       {\r
-               /* get entity and model */\r
-               e = &entities[ i ];\r
-               key = ValueForKey( e, "model" );\r
-               if( key[ 0 ] != '*' )\r
-                       continue;\r
-               modelnum = atoi( key + 1 );\r
-               dm = &bspModels[ modelnum ];\r
-               \r
-               /* get entity origin */\r
-               key = ValueForKey( e, "origin" );\r
-               if( key[ 0 ] == '\0' )\r
-                       continue;\r
-               GetVectorForKey( e, "origin", origin );\r
-               \r
-               /* set origin for all surfaces for this model */\r
-               for( j = 0; j < dm->numBSPSurfaces; j++ )\r
-               {\r
-                       /* get drawsurf */\r
-                       ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];\r
-                       \r
-                       /* set its verts */\r
-                       for( k = 0; k < ds->numVerts; k++ )\r
-                       {\r
-                               f = ds->firstVert + k;\r
-                               VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-PointToPolygonFormFactor()\r
-calculates the area over a point/normal hemisphere a winding covers\r
-ydnar: fixme: there has to be a faster way to calculate this\r
-without the expensive per-vert sqrts and transcendental functions\r
-ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%\r
-between this and the approximation\r
-*/\r
-\r
-#define ONE_OVER_2PI   0.159154942f    //% (1.0f / (2.0f * 3.141592657f))\r
-\r
-float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )\r
-{\r
-       vec3_t          triVector, triNormal;\r
-       int                     i, j;\r
-       vec3_t          dirs[ MAX_POINTS_ON_WINDING ];\r
-       float           total;\r
-       float           dot, angle, facing;\r
-       \r
-       \r
-       /* this is expensive */\r
-       for( i = 0; i < w->numpoints; i++ )\r
-       {\r
-               VectorSubtract( w->p[ i ], point, dirs[ i ] );\r
-               VectorNormalize( dirs[ i ], dirs[ i ] );\r
-       }\r
-       \r
-       /* duplicate first vertex to avoid mod operation */\r
-       VectorCopy( dirs[ 0 ], dirs[ i ] );\r
-       \r
-       /* calculcate relative area */\r
-       total = 0.0f;\r
-       for( i = 0; i < w->numpoints; i++ )\r
-       {\r
-               /* get a triangle */\r
-               j = i + 1;\r
-               dot = DotProduct( dirs[ i ], dirs[ j ] );\r
-               \r
-               /* roundoff can cause slight creep, which gives an IND from acos */\r
-               if( dot > 1.0f )\r
-                       dot = 1.0f;\r
-               else if( dot < -1.0f )\r
-                       dot = -1.0f;\r
-               \r
-               /* get the angle */\r
-               angle = acos( dot );\r
-               \r
-               CrossProduct( dirs[ i ], dirs[ j ], triVector );\r
-               if( VectorNormalize( triVector, triNormal ) < 0.0001f )\r
-                       continue;\r
-               \r
-               facing = DotProduct( normal, triNormal );\r
-               total += facing * angle;\r
-               \r
-               /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */\r
-               if( total > 6.3f || total < -6.3f )\r
-                       return 0.0f;\r
-       }\r
-       \r
-       /* now in the range of 0 to 1 over the entire incoming hemisphere */\r
-       //%     total /= (2.0f * 3.141592657f);\r
-       total *= ONE_OVER_2PI;\r
-       return total;\r
-}\r
-\r
-\r
-\r
-/*\r
-LightContributionTosample()\r
-determines the amount of light reaching a sample (luxel or vertex) from a given light\r
-*/\r
-\r
-int LightContributionToSample( trace_t *trace )\r
-{\r
-       light_t                 *light;\r
-       float                   angle;\r
-       float                   add;\r
-       float                   dist;\r
-       \r
-       \r
-       /* get light */\r
-       light = trace->light;\r
-       \r
-       /* clear color */\r
-       VectorClear( trace->color );\r
-       \r
-       /* ydnar: early out */\r
-       if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )\r
-               return 0;\r
-       \r
-       /* do some culling checks */\r
-       if( light->type != EMIT_SUN )\r
-       {\r
-               /* MrE: if the light is behind the surface */\r
-               if( trace->twoSided == qfalse )\r
-                       if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )\r
-                               return 0;\r
-               \r
-               /* ydnar: test pvs */\r
-               if( !ClusterVisible( trace->cluster, light->cluster ) )\r
-                       return 0;\r
-       }\r
-       \r
-       /* ptpff approximation */\r
-       if( light->type == EMIT_AREA && faster )\r
-       {\r
-               /* get direction and distance */\r
-               VectorCopy( light->origin, trace->end );\r
-               dist = SetupTrace( trace );\r
-               if( dist >= light->envelope )\r
-                       return 0;\r
-               \r
-               /* clamp the distance to prevent super hot spots */\r
-               if( dist < 16.0f )\r
-                       dist = 16.0f;\r
-               \r
-               /* angle attenuation */\r
-               angle = DotProduct( trace->normal, trace->direction );\r
-               \r
-               /* twosided lighting */\r
-               if( trace->twoSided )\r
-                       angle = fabs( angle );\r
-               \r
-               /* attenuate */\r
-               angle *= -DotProduct( light->normal, trace->direction );\r
-               if( angle <= 0.0f )\r
-                       return 0;\r
-               add = light->photons / (dist * dist) * angle;\r
-       }\r
-       \r
-       /* exact point to polygon form factor */\r
-       else if( light->type == EMIT_AREA )\r
-       {\r
-               float           factor;\r
-               float           d;\r
-               vec3_t          pushedOrigin;\r
-               \r
-               \r
-               /* project sample point into light plane */\r
-               d = DotProduct( trace->origin, light->normal ) - light->dist;\r
-               //%     if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )\r
-               //%             return 0;\r
-               if( d < 3.0f )\r
-               {\r
-                       /* sample point behind plane? */\r
-                       if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )\r
-                               return 0;\r
-                       \r
-                       /* sample plane coincident? */\r
-                       if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )\r
-                               return 0;\r
-               }\r
-               \r
-               /* nudge the point so that it is clearly forward of the light */\r
-               /* so that surfaces meeting a light emiter don't get black edges */\r
-               if( d > -8.0f && d < 8.0f )\r
-                       VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             \r
-               else\r
-                       VectorCopy( trace->origin, pushedOrigin );\r
-               \r
-               /* get direction and distance */\r
-               VectorCopy( light->origin, trace->end );\r
-               dist = SetupTrace( trace );\r
-               if( dist >= light->envelope )\r
-                       return 0;\r
-               \r
-               /* calculate the contribution */\r
-               factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );\r
-               if( factor == 0.0f )\r
-                       return 0;\r
-               else if( factor < 0.0f )\r
-               {\r
-                       /* twosided lighting */\r
-                       if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )\r
-                       {\r
-                               factor = -factor;\r
-\r
-                               /* push light origin to other side of the plane */\r
-                               VectorMA( light->origin, -2.0f, light->normal, trace->end );\r
-                               dist = SetupTrace( trace );\r
-                               if( dist >= light->envelope )\r
-                                       return 0;\r
-                       }\r
-                       else\r
-                               return 0;\r
-               }\r
-               \r
-               /* ydnar: moved to here */\r
-               add = factor * light->add;\r
-       }\r
-       \r
-       /* point/spot lights */\r
-       else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )\r
-       {\r
-               /* get direction and distance */\r
-               VectorCopy( light->origin, trace->end );\r
-               dist = SetupTrace( trace );\r
-               if( dist >= light->envelope )\r
-                       return 0;\r
-               \r
-               /* clamp the distance to prevent super hot spots */\r
-               if( dist < 16.0f )\r
-                       dist = 16.0f;\r
-               \r
-               /* angle attenuation */\r
-               angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f;\r
-               if( light->angleScale != 0.0f )\r
-               {\r
-                       angle /= light->angleScale;\r
-                       if( angle > 1.0f )\r
-                               angle = 1.0f;\r
-               }\r
-               \r
-               /* twosided lighting */\r
-               if( trace->twoSided )\r
-                       angle = fabs( angle );\r
-               \r
-               /* attenuate */\r
-               if( light->flags & LIGHT_ATTEN_LINEAR )\r
-               {\r
-                       add = angle * light->photons * linearScale - (dist * light->fade);\r
-                       if( add < 0.0f )\r
-                               add = 0.0f;\r
-               }\r
-               else\r
-                       add = light->photons / (dist * dist) * angle;\r
-               \r
-               /* handle spotlights */\r
-               if( light->type == EMIT_SPOT )\r
-               {\r
-                       float   distByNormal, radiusAtDist, sampleRadius;\r
-                       vec3_t  pointAtDist, distToSample;\r
-                       \r
-                       \r
-                       /* do cone calculation */\r
-                       distByNormal = -DotProduct( trace->displacement, light->normal );\r
-                       if( distByNormal < 0.0f )\r
-                               return 0;\r
-                       VectorMA( light->origin, distByNormal, light->normal, pointAtDist );\r
-                       radiusAtDist = light->radiusByDist * distByNormal;\r
-                       VectorSubtract( trace->origin, pointAtDist, distToSample );\r
-                       sampleRadius = VectorLength( distToSample );\r
-                       \r
-                       /* outside the cone */\r
-                       if( sampleRadius >= radiusAtDist )\r
-                               return 0;\r
-                       \r
-                       /* attenuate */\r
-                       if( sampleRadius > (radiusAtDist - 32.0f) )\r
-                               add *= ((radiusAtDist - sampleRadius) / 32.0f);\r
-               }\r
-       }\r
-       \r
-       /* ydnar: sunlight */\r
-       else if( light->type == EMIT_SUN )\r
-       {\r
-               /* get origin and direction */\r
-               VectorAdd( trace->origin, light->origin, trace->end );\r
-               dist = SetupTrace( trace );\r
-               \r
-               /* angle attenuation */\r
-               angle = (light->flags & LIGHT_ATTEN_ANGLE)\r
-                       ? DotProduct( trace->normal, trace->direction )\r
-                       : 1.0f;\r
-               \r
-               /* twosided lighting */\r
-               if( trace->twoSided )\r
-                       angle = fabs( angle );\r
-               \r
-               /* attenuate */\r
-               add = light->photons * angle;\r
-               if( add <= 0.0f )\r
-                       return 0;\r
-               \r
-               /* setup trace */\r
-               trace->testAll = qtrue;\r
-               VectorScale( light->color, add, trace->color );\r
-               \r
-               /* trace to point */\r
-               if( trace->testOcclusion && !trace->forceSunlight )\r
-               {\r
-                       /* trace */\r
-                       TraceLine( trace );\r
-                       if( !(trace->compileFlags & C_SKY) || trace->opaque )\r
-                       {\r
-                               VectorClear( trace->color );\r
-                               return -1;\r
-                       }\r
-               }\r
-               \r
-               /* return to sender */\r
-               return 1;\r
-       }\r
-       \r
-       /* ydnar: changed to a variable number */\r
-       if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )\r
-               return 0;\r
-       \r
-       /* setup trace */\r
-       trace->testAll = qfalse;\r
-       VectorScale( light->color, add, trace->color );\r
-       \r
-       /* raytrace */\r
-       TraceLine( trace );\r
-       if( trace->passSolid || trace->opaque )\r
-       {\r
-               VectorClear( trace->color );\r
-               return -1;\r
-       }\r
-       \r
-       /* return to sender */\r
-       return 1;\r
-}\r
-\r
-\r
-\r
-/*\r
-LightingAtSample()\r
-determines the amount of light reaching a sample (luxel or vertex)\r
-*/\r
-\r
-void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )\r
-{\r
-       int                             i, lightmapNum;\r
-       \r
-       \r
-       /* clear colors */\r
-       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               VectorClear( colors[ lightmapNum ] );\r
-       \r
-       /* ydnar: normalmap */\r
-       if( normalmap )\r
-       {\r
-               colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;\r
-               colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;\r
-               colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;\r
-               return;\r
-       }\r
-       \r
-       /* ydnar: don't bounce ambient all the time */\r
-       if( !bouncing )\r
-               VectorCopy( ambientColor, colors[ 0 ] );\r
-       \r
-       /* ydnar: trace to all the list of lights pre-stored in tw */\r
-       for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )\r
-       {\r
-               /* set light */\r
-               trace->light = trace->lights[ i ];\r
-               \r
-               /* style check */\r
-               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               {\r
-                       if( styles[ lightmapNum ] == trace->light->style ||\r
-                               styles[ lightmapNum ] == LS_NONE )\r
-                               break;\r
-               }\r
-               \r
-               /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */\r
-               if( lightmapNum >= MAX_LIGHTMAPS )\r
-                       continue;\r
-               \r
-               /* sample light */\r
-               LightContributionToSample( trace );\r
-               if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )\r
-                       continue;\r
-               \r
-               /* handle negative light */\r
-               if( trace->light->flags & LIGHT_NEGATIVE )\r
-                       VectorScale( trace->color, -1.0f, trace->color );\r
-               \r
-               /* set style */\r
-               styles[ lightmapNum ] = trace->light->style;\r
-               \r
-               /* add it */\r
-               VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );\r
-               \r
-               /* cheap mode */\r
-               if( cheap &&\r
-                       colors[ 0 ][ 0 ] >= 255.0f &&\r
-                       colors[ 0 ][ 1 ] >= 255.0f &&\r
-                       colors[ 0 ][ 2 ] >= 255.0f )\r
-                       break;\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-LightContributionToPoint()\r
-for a given light, how much light/color reaches a given point in space (with no facing)\r
-note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling\r
-*/\r
-\r
-int LightContributionToPoint( trace_t *trace )\r
-{\r
-       light_t         *light;\r
-       float           add, dist;\r
-       \r
-       \r
-       /* get light */\r
-       light = trace->light;\r
-       \r
-       /* clear color */\r
-       VectorClear( trace->color );\r
-       \r
-       /* ydnar: early out */\r
-       if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )\r
-               return qfalse;\r
-       \r
-       /* is this a sun? */\r
-       if( light->type != EMIT_SUN )\r
-       {\r
-               /* sun only? */\r
-               if( sunOnly )\r
-                       return qfalse;\r
-               \r
-               /* test pvs */\r
-               if( !ClusterVisible( trace->cluster, light->cluster ) )\r
-                       return qfalse;\r
-       }\r
-       \r
-       /* ydnar: check origin against light's pvs envelope */\r
-       if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||\r
-               trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||\r
-               trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )\r
-       {\r
-               gridBoundsCulled++;\r
-               return qfalse;\r
-       }\r
-       \r
-       /* set light origin */\r
-       if( light->type == EMIT_SUN )\r
-               VectorAdd( trace->origin, light->origin, trace->end );\r
-       else\r
-               VectorCopy( light->origin, trace->end );\r
-       \r
-       /* set direction */\r
-       dist = SetupTrace( trace );\r
-       \r
-       /* test envelope */\r
-       if( dist > light->envelope )\r
-       {\r
-               gridEnvelopeCulled++;\r
-               return qfalse;\r
-       }\r
-       \r
-       /* ptpff approximation */\r
-       if( light->type == EMIT_AREA && faster )\r
-       {\r
-               /* clamp the distance to prevent super hot spots */\r
-               if( dist < 16.0f )\r
-                       dist = 16.0f;\r
-               \r
-               /* attenuate */\r
-               add = light->photons / (dist * dist);\r
-       }\r
-       \r
-       /* exact point to polygon form factor */\r
-       else if( light->type == EMIT_AREA )\r
-       {\r
-               float           factor, d;\r
-               vec3_t          pushedOrigin;\r
-               \r
-               \r
-               /* see if the point is behind the light */\r
-               d = DotProduct( trace->origin, light->normal ) - light->dist;\r
-               if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )\r
-                       return qfalse;\r
-               \r
-               /* nudge the point so that it is clearly forward of the light */\r
-               /* so that surfaces meeting a light emiter don't get black edges */\r
-               if( d > -8.0f && d < 8.0f )\r
-                       VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             \r
-               else\r
-                       VectorCopy( trace->origin, pushedOrigin );\r
-               \r
-               /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */\r
-               factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );\r
-               if( factor == 0.0f )\r
-                       return qfalse;\r
-               else if( factor < 0.0f )\r
-               {\r
-                       if( light->flags & LIGHT_TWOSIDED )\r
-                               factor = -factor;\r
-                       else\r
-                               return qfalse;\r
-               }\r
-               \r
-               /* ydnar: moved to here */\r
-               add = factor * light->add;\r
-       }\r
-       \r
-       /* point/spot lights */\r
-       else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )\r
-       {\r
-               /* clamp the distance to prevent super hot spots */\r
-               if( dist < 16.0f )\r
-                       dist = 16.0f;\r
-               \r
-               /* attenuate */\r
-               if( light->flags & LIGHT_ATTEN_LINEAR )\r
-               {\r
-                       add = light->photons * linearScale - (dist * light->fade);\r
-                       if( add < 0.0f )\r
-                               add = 0.0f;\r
-               }\r
-               else\r
-                       add = light->photons / (dist * dist);\r
-               \r
-               /* handle spotlights */\r
-               if( light->type == EMIT_SPOT )\r
-               {\r
-                       float   distByNormal, radiusAtDist, sampleRadius;\r
-                       vec3_t  pointAtDist, distToSample;\r
-                       \r
-                       \r
-                       /* do cone calculation */\r
-                       distByNormal = -DotProduct( trace->displacement, light->normal );\r
-                       if( distByNormal < 0.0f )\r
-                               return qfalse;\r
-                       VectorMA( light->origin, distByNormal, light->normal, pointAtDist );\r
-                       radiusAtDist = light->radiusByDist * distByNormal;\r
-                       VectorSubtract( trace->origin, pointAtDist, distToSample );\r
-                       sampleRadius = VectorLength( distToSample );\r
-                       \r
-                       /* outside the cone */\r
-                       if( sampleRadius >= radiusAtDist )\r
-                               return qfalse;\r
-                       \r
-                       /* attenuate */\r
-                       if( sampleRadius > (radiusAtDist - 32.0f) )\r
-                               add *= ((radiusAtDist - sampleRadius) / 32.0f);\r
-               }\r
-       }\r
-       \r
-       /* ydnar: sunlight */\r
-       else if( light->type == EMIT_SUN )\r
-       {\r
-               /* attenuate */\r
-               add = light->photons;\r
-               if( add <= 0.0f )\r
-                       return qfalse;\r
-               \r
-               /* setup trace */\r
-               trace->testAll = qtrue;\r
-               VectorScale( light->color, add, trace->color );\r
-               \r
-               /* trace to point */\r
-               if( trace->testOcclusion && !trace->forceSunlight )\r
-               {\r
-                       /* trace */\r
-                       TraceLine( trace );\r
-                       if( !(trace->compileFlags & C_SKY) || trace->opaque )\r
-                       {\r
-                               VectorClear( trace->color );\r
-                               return -1;\r
-                       }\r
-               }\r
-               \r
-               /* return to sender */\r
-               return qtrue;\r
-       }\r
-       \r
-       /* unknown light type */\r
-       else\r
-               return qfalse;\r
-       \r
-       /* ydnar: changed to a variable number */\r
-       if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )\r
-               return qfalse;\r
-       \r
-       /* setup trace */\r
-       trace->testAll = qfalse;\r
-       VectorScale( light->color, add, trace->color );\r
-       \r
-       /* trace */\r
-       TraceLine( trace );\r
-       if( trace->passSolid )\r
-       {\r
-               VectorClear( trace->color );\r
-               return qfalse;\r
-       }\r
-       \r
-       /* we have a valid sample */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-TraceGrid()\r
-grid samples are for quickly determining the lighting\r
-of dynamically placed entities in the world\r
-*/\r
-\r
-#define        MAX_CONTRIBUTIONS       1024\r
-\r
-typedef struct\r
-{\r
-       vec3_t          dir;\r
-       vec3_t          color;\r
-       int                     style;\r
-}\r
-contribution_t;\r
-\r
-void TraceGrid( int num )\r
-{\r
-       int                                             i, j, x, y, z, mod, step, numCon, numStyles;\r
-       float                                   d;\r
-       vec3_t                                  baseOrigin, cheapColor, color;\r
-       rawGridPoint_t                  *gp;\r
-       bspGridPoint_t                  *bgp;\r
-       contribution_t                  contributions[ MAX_CONTRIBUTIONS ];\r
-       trace_t                                 trace;\r
-       \r
-       \r
-       /* get grid points */\r
-       gp = &rawGridPoints[ num ];\r
-       bgp = &bspGridPoints[ num ];\r
-       \r
-       /* get grid origin */\r
-       mod = num;\r
-       z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);\r
-       mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);\r
-       y = mod / gridBounds[ 0 ];\r
-       mod -= y * gridBounds[ 0 ];\r
-       x = mod;\r
-       \r
-       trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];\r
-       trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];\r
-       trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];\r
-       \r
-       /* set inhibit sphere */\r
-       if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )\r
-               trace.inhibitRadius = gridSize[ 0 ] * 0.5f;\r
-       else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )\r
-               trace.inhibitRadius = gridSize[ 1 ] * 0.5f;\r
-       else\r
-               trace.inhibitRadius = gridSize[ 2 ] * 0.5f;\r
-       \r
-       /* find point cluster */\r
-       trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );\r
-       if( trace.cluster < 0 )\r
-       {\r
-               /* try to nudge the origin around to find a valid point */\r
-               VectorCopy( trace.origin, baseOrigin );\r
-               for( step = 9; step <= 18; step += 9 )\r
-               {\r
-                       for( i = 0; i < 8; i++ )\r
-                       {\r
-                               VectorCopy( baseOrigin, trace.origin );\r
-                               if( i & 1 )\r
-                                       trace.origin[ 0 ] += step;\r
-                               else\r
-                                       trace.origin[ 0 ] -= step;\r
-                               \r
-                               if( i & 2 )\r
-                                       trace.origin[ 1 ] += step;\r
-                               else\r
-                                       trace.origin[ 1 ] -= step;\r
-                               \r
-                               if( i & 4 )\r
-                                       trace.origin[ 2 ] += step;\r
-                               else\r
-                                       trace.origin[ 2 ] -= step;\r
-                               \r
-                               /* ydnar: changed to find cluster num */\r
-                               trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );\r
-                               if( trace.cluster >= 0 )\r
-                                       break;\r
-                       }\r
-                       \r
-                       if( i != 8 )\r
-                               break;\r
-               }\r
-               \r
-               /* can't find a valid point at all */\r
-               if( step > 18 )\r
-                       return;\r
-       }\r
-       \r
-       /* setup trace */\r
-       trace.testOcclusion = !noTrace;\r
-       trace.forceSunlight = qfalse;\r
-       trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;\r
-       trace.numSurfaces = 0;\r
-       trace.surfaces = NULL;\r
-       trace.numLights = 0;\r
-       trace.lights = NULL;\r
-       \r
-       /* clear */\r
-       numCon = 0;\r
-       VectorClear( cheapColor );\r
-       \r
-       /* trace to all the lights, find the major light direction, and divide the\r
-          total light between that along the direction and the remaining in the ambient */\r
-       for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )\r
-       {\r
-               float           addSize;\r
-               \r
-               \r
-               /* sample light */\r
-               if( !LightContributionToPoint( &trace ) )\r
-                       continue;\r
-               \r
-               /* handle negative light */\r
-               if( trace.light->flags & LIGHT_NEGATIVE )\r
-                       VectorScale( trace.color, -1.0f, trace.color );\r
-               \r
-               /* add a contribution */\r
-               VectorCopy( trace.color, contributions[ numCon ].color );\r
-               VectorCopy( trace.direction, contributions[ numCon ].dir );\r
-               contributions[ numCon ].style = trace.light->style;\r
-               numCon++;\r
-               \r
-               /* push average direction around */\r
-               addSize = VectorLength( trace.color );\r
-               VectorMA( gp->dir, addSize, trace.direction, gp->dir );\r
-               \r
-               /* stop after a while */\r
-               if( numCon >= (MAX_CONTRIBUTIONS - 1) )\r
-                       break;\r
-               \r
-               /* ydnar: cheap mode */\r
-               VectorAdd( cheapColor, trace.color, cheapColor );\r
-               if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )\r
-                       break;\r
-       }\r
-       \r
-       /* normalize to get primary light direction */\r
-       VectorNormalize( gp->dir, gp->dir );\r
-       \r
-       /* now that we have identified the primary light direction,\r
-          go back and separate all the light into directed and ambient */\r
-       numStyles = 1;\r
-       for( i = 0; i < numCon; i++ )\r
-       {\r
-               /* get relative directed strength */\r
-               d = DotProduct( contributions[ i ].dir, gp->dir );\r
-               if( d < 0.0f )\r
-                       d = 0.0f;\r
-               \r
-               /* find appropriate style */\r
-               for( j = 0; j < numStyles; j++ )\r
-               {\r
-                       if( gp->styles[ j ] == contributions[ i ].style )\r
-                               break;\r
-               }\r
-               \r
-               /* style not found? */\r
-               if( j >= numStyles )\r
-               {\r
-                       /* add a new style */\r
-                       if( numStyles < MAX_LIGHTMAPS )\r
-                       {\r
-                               gp->styles[ numStyles ] = contributions[ i ].style;\r
-                               bgp->styles[ numStyles ] = contributions[ i ].style;\r
-                               numStyles++;\r
-                               //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );\r
-                       }\r
-                       \r
-                       /* fallback */\r
-                       else\r
-                               j = 0;\r
-               }\r
-               \r
-               /* add the directed color */\r
-               VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );\r
-               \r
-               /* ambient light will be at 1/4 the value of directed light */\r
-               /* (ydnar: nuke this in favor of more dramatic lighting?) */\r
-               d = 0.25f * (1.0f - d);\r
-               VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );\r
-       }\r
-       \r
-       \r
-       /* store off sample */\r
-       for( i = 0; i < MAX_LIGHTMAPS; i++ )\r
-       {\r
-               /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */\r
-               if( !bouncing )\r
-                       VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );\r
-               \r
-               /* set minimum light and copy off to bytes */\r
-               VectorCopy( gp->ambient[ i ], color );\r
-               for( j = 0; j < 3; j++ )\r
-                       if( color[ j ] < minGridLight[ j ] )\r
-                               color[ j ] = minGridLight[ j ];\r
-               ColorToBytes( color, bgp->ambient[ i ], 1.0f );\r
-               ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );\r
-       }\r
-       \r
-       /* debug code */\r
-       #if 0\r
-               //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );\r
-               Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",\r
-                       num,\r
-                       gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],\r
-                       gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );\r
-       #endif\r
-       \r
-       /* store direction */\r
-       NormalToLatLong( gp->dir, bgp->latLong );\r
-}\r
-\r
-\r
-\r
-/*\r
-SetupGrid()\r
-calculates the size of the lightgrid and allocates memory\r
-*/\r
-\r
-void SetupGrid( void )\r
-{\r
-       int                     i, j;\r
-       vec3_t          maxs, oldGridSize;\r
-       const char      *value;\r
-       char            temp[ 64 ];\r
-       \r
-        \r
-       /* don't do this if not grid lighting */\r
-       if( noGridLighting )\r
-               return;\r
-       \r
-       /* ydnar: set grid size */\r
-       value = ValueForKey( &entities[ 0 ], "gridsize" );\r
-       if( value[ 0 ] != '\0' )\r
-               sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );\r
-       \r
-       /* quantize it */\r
-       VectorCopy( gridSize, oldGridSize );\r
-       for( i = 0; i < 3; i++ )\r
-               gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;\r
-       \r
-       /* ydnar: increase gridSize until grid count is smaller than max allowed */\r
-       numRawGridPoints = MAX_MAP_LIGHTGRID + 1;\r
-       j = 0;\r
-       while( numRawGridPoints > MAX_MAP_LIGHTGRID )\r
-       {\r
-               /* get world bounds */\r
-               for( i = 0; i < 3; i++ )\r
-               {\r
-                       gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );\r
-                       maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );\r
-                       gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;\r
-               }\r
-       \r
-               /* set grid size */\r
-               numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];\r
-               \r
-               /* increase grid size a bit */\r
-               if( numRawGridPoints > MAX_MAP_LIGHTGRID )\r
-                       gridSize[ j++ % 3 ] += 16.0f;\r
-       }\r
-       \r
-       /* print it */\r
-       Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );\r
-       \r
-       /* different? */\r
-       if( !VectorCompare( gridSize, oldGridSize ) )\r
-       {\r
-               sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );\r
-               SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );\r
-               Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );\r
-       }\r
-       \r
-       /* 2nd variable. fixme: is this silly? */\r
-       numBSPGridPoints = numRawGridPoints;\r
-       \r
-       /* allocate lightgrid */\r
-       rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );\r
-       memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );\r
-       \r
-       if( bspGridPoints != NULL )\r
-               free( bspGridPoints );\r
-       bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );\r
-       memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );\r
-       \r
-       /* clear lightgrid */\r
-       for( i = 0; i < numRawGridPoints; i++ )\r
-       {\r
-               VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );\r
-               rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;\r
-               bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;\r
-               for( j = 1; j < MAX_LIGHTMAPS; j++ )\r
-               {\r
-                       rawGridPoints[ i ].styles[ j ] = LS_NONE;\r
-                       bspGridPoints[ i ].styles[ j ] = LS_NONE;\r
-               }\r
-       }\r
-       \r
-       /* note it */\r
-       Sys_Printf( "%9d grid points\n", numRawGridPoints );\r
-}\r
-\r
-\r
-\r
-/*\r
-LightWorld()\r
-does what it says...\r
-*/\r
-\r
-void LightWorld( void )\r
-{\r
-       vec3_t          color;\r
-       float           f;\r
-       int                     b, bt;\r
-       qboolean        minVertex, minGrid;\r
-       const char      *value;\r
-       \r
-\r
-       /* ydnar: smooth normals */\r
-       if( shade )\r
-       {\r
-               Sys_Printf( "--- SmoothNormals ---\n" );\r
-               SmoothNormals();\r
-       }\r
-       \r
-       /* determine the number of grid points */\r
-       Sys_Printf( "--- SetupGrid ---\n" );\r
-       SetupGrid();\r
-       \r
-       /* find the optional minimum lighting values */\r
-       GetVectorForKey( &entities[ 0 ], "_color", color );\r
-       if( VectorLength( color ) == 0.0f )\r
-               VectorSet( color, 1.0, 1.0, 1.0 );\r
-       \r
-       /* ambient */\r
-       f = FloatForKey( &entities[ 0 ], "_ambient" );\r
-       if( f == 0.0f )\r
-               f = FloatForKey( &entities[ 0 ], "ambient" );\r
-       VectorScale( color, f, ambientColor );\r
-       \r
-       /* minvertexlight */\r
-       minVertex = qfalse;\r
-       value = ValueForKey( &entities[ 0 ], "_minvertexlight" );\r
-       if( value[ 0 ] != '\0' )\r
-       {\r
-               minVertex = qtrue;\r
-               f = atof( value );\r
-               VectorScale( color, f, minVertexLight );\r
-       }\r
-       \r
-       /* mingridlight */\r
-       minGrid = qfalse;\r
-       value = ValueForKey( &entities[ 0 ], "_mingridlight" );\r
-       if( value[ 0 ] != '\0' )\r
-       {\r
-               minGrid = qtrue;\r
-               f = atof( value );\r
-               VectorScale( color, f, minGridLight );\r
-       }\r
-       \r
-       /* minlight */\r
-       value = ValueForKey( &entities[ 0 ], "_minlight" );\r
-       if( value[ 0 ] != '\0' )\r
-       {\r
-               f = atof( value );\r
-               VectorScale( color, f, minLight );\r
-               if( minVertex == qfalse )\r
-                       VectorScale( color, f, minVertexLight );\r
-               if( minGrid == qfalse )\r
-                       VectorScale( color, f, minGridLight );\r
-       }\r
-       \r
-       /* create world lights */\r
-       Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );\r
-       CreateEntityLights();\r
-       CreateSurfaceLights();\r
-       Sys_Printf( "%9d point lights\n", numPointLights );\r
-       Sys_Printf( "%9d spotlights\n", numSpotLights );\r
-       Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );\r
-       Sys_Printf( "%9d sun/sky lights\n", numSunLights );\r
-       \r
-       /* calculate lightgrid */\r
-       if( !noGridLighting )\r
-       {\r
-               /* ydnar: set up light envelopes */\r
-               SetupEnvelopes( qtrue, fastgrid );\r
-               \r
-               Sys_Printf( "--- TraceGrid ---\n" );\r
-               RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );\r
-               Sys_Printf( "%d x %d x %d = %d grid\n",\r
-                       gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );\r
-               \r
-               /* ydnar: emit statistics on light culling */\r
-               Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );\r
-               Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );\r
-       }\r
-       \r
-       /* slight optimization to remove a sqrt */\r
-       subdivideThreshold *= subdivideThreshold;\r
-       \r
-       /* map the world luxels */\r
-       Sys_Printf( "--- MapRawLightmap ---\n" );\r
-       RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );\r
-       Sys_Printf( "%9d luxels\n", numLuxels );\r
-       Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );\r
-       Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );\r
-\r
-       /* ydnar: set up light envelopes */\r
-       SetupEnvelopes( qfalse, fast );\r
-       \r
-       /* light up my world */\r
-       lightsPlaneCulled = 0;\r
-       lightsEnvelopeCulled = 0;\r
-       lightsBoundsCulled = 0;\r
-       lightsClusterCulled = 0;\r
-       \r
-       Sys_Printf( "--- IlluminateRawLightmap ---\n" );\r
-       RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );\r
-       Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );\r
-       \r
-       StitchSurfaceLightmaps();\r
-       \r
-       Sys_Printf( "--- IlluminateVertexes ---\n" );\r
-       RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );\r
-       Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );\r
-       \r
-       /* ydnar: emit statistics on light culling */\r
-       Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );\r
-       Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );\r
-       Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );\r
-       Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );\r
-       \r
-       /* radiosity */\r
-       b = 1;\r
-       bt = bounce;\r
-       while( bounce > 0 )\r
-       {\r
-               /* store off the bsp between bounces */\r
-               StoreSurfaceLightmaps();\r
-               Sys_Printf( "Writing %s\n", source );\r
-               WriteBSPFile( source );\r
-               \r
-               /* note it */\r
-               Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );\r
-               \r
-               /* flag bouncing */\r
-               bouncing = qtrue;\r
-               VectorClear( ambientColor );\r
-               \r
-               /* generate diffuse lights */\r
-               RadFreeLights();\r
-               RadCreateDiffuseLights();\r
-               \r
-               /* setup light envelopes */\r
-               SetupEnvelopes( qfalse, fastbounce );\r
-               if( numLights == 0 )\r
-               {\r
-                       Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );\r
-                       break;\r
-               }\r
-               \r
-               /* add to lightgrid */\r
-               if( bouncegrid )\r
-               {\r
-                       gridEnvelopeCulled = 0;\r
-                       gridBoundsCulled = 0;\r
-                       \r
-                       Sys_Printf( "--- BounceGrid ---\n" );\r
-                       RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );\r
-                       Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );\r
-                       Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );\r
-               }\r
-               \r
-               /* light up my world */\r
-               lightsPlaneCulled = 0;\r
-               lightsEnvelopeCulled = 0;\r
-               lightsBoundsCulled = 0;\r
-               lightsClusterCulled = 0;\r
-               \r
-               Sys_Printf( "--- IlluminateRawLightmap ---\n" );\r
-               RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );\r
-               Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );\r
-               Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );\r
-               \r
-               StitchSurfaceLightmaps();\r
-               \r
-               Sys_Printf( "--- IlluminateVertexes ---\n" );\r
-               RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );\r
-               Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );\r
-               \r
-               /* ydnar: emit statistics on light culling */\r
-               Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );\r
-               Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );\r
-               Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );\r
-               Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );\r
-               \r
-               /* interate */\r
-               bounce--;\r
-               b++;\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-LightMain()\r
-main routine for light processing\r
-*/\r
-\r
-int LightMain( int argc, char **argv )\r
-{\r
-       int                     i;\r
-       float           f;\r
-       char            mapSource[ 1024 ];\r
-       const char      *value;\r
-       \r
-       \r
-       /* note it */\r
-       Sys_Printf( "--- Light ---\n" );\r
-       \r
-       /* process commandline arguments */\r
-       for( i = 1; i < (argc - 1); i++ )\r
-       {\r
-               /* lightsource scaling */\r
-               if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )\r
-               {\r
-                       f = atof( argv[ i + 1 ] );\r
-                       pointScale *= f;\r
-                       Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )\r
-               {\r
-                       f = atof( argv[ i + 1 ] );\r
-                       areaScale *= f;\r
-                       Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )\r
-               {\r
-                       f = atof( argv[ i + 1 ] );\r
-                       skyScale *= f;\r
-                       Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-bouncescale" ) )\r
-               {\r
-                       f = atof( argv[ i + 1 ] );\r
-                       bounceScale *= f;\r
-                       Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-scale" ) )\r
-               {\r
-                       f = atof( argv[ i + 1 ] );\r
-                       pointScale *= f;\r
-                       areaScale *= f;\r
-                       skyScale *= f;\r
-                       bounceScale *= f;\r
-                       Sys_Printf( "All light scaled by %f\n", f );\r
-                       i++;\r
-               }\r
-               \r
-               /* ydnar switches */\r
-               else if( !strcmp( argv[ i ], "-bounce" ) )\r
-               {\r
-                       bounce = atoi( argv[ i + 1 ] );\r
-                       if( bounce < 0 )\r
-                               bounce = 0;\r
-                       else if( bounce > 0 )\r
-                               Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )\r
-               {\r
-                       superSample = atoi( argv[ i + 1 ] );\r
-                       if( superSample < 1 )\r
-                               superSample = 1;\r
-                       else if( superSample > 1 )\r
-                               Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-samples" ) )\r
-               {\r
-                       lightSamples = atoi( argv[ i + 1 ] );\r
-                       if( lightSamples < 1 )\r
-                               lightSamples = 1;\r
-                       else if( lightSamples > 1 )\r
-                               Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-filter" ) )\r
-               {\r
-                       filter = qtrue;\r
-                       Sys_Printf( "Lightmap filtering enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-shadeangle" ) )\r
-               {\r
-                       shadeAngleDegrees = atof( argv[ i + 1 ] );\r
-                       if( shadeAngleDegrees < 0.0f )\r
-                               shadeAngleDegrees = 0.0f;\r
-                       else if( shadeAngleDegrees > 0.0f )\r
-                       {\r
-                               shade = qtrue;\r
-                               Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );\r
-                       }\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-thresh" ) )\r
-               {\r
-                       subdivideThreshold = atof( argv[ i + 1 ] );\r
-                       if( subdivideThreshold < 0 )\r
-                               subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;\r
-                       else\r
-                               Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-approx" ) )\r
-               {\r
-                       approximateTolerance = atoi( argv[ i + 1 ] );\r
-                       if( approximateTolerance < 0 )\r
-                               approximateTolerance = 0;\r
-                       else if( approximateTolerance > 0 )\r
-                               Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );\r
-                       i++;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )\r
-               {\r
-                       deluxemap = qtrue;\r
-                       Sys_Printf( "Generating deluxemaps for average light direction\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-external" ) )\r
-               {\r
-                       externalLightmaps = qtrue;\r
-                       Sys_Printf( "Storing all lightmaps externally\n" );\r
-               }\r
-\r
-               else if( !strcmp( argv[ i ], "-lightmapsize" ) )\r
-               {\r
-                       lmCustomSize = atoi( argv[ i + 1 ] );\r
-                       \r
-                       /* must be a power of 2 and greater than 2 */\r
-                       if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )\r
-                       {\r
-                               Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );\r
-                               lmCustomSize = LIGHTMAP_WIDTH;\r
-                       }\r
-                       i++;\r
-                       Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );\r
-                       \r
-                       /* enable external lightmaps */\r
-                       if( lmCustomSize != LIGHTMAP_WIDTH )\r
-                       {\r
-                               externalLightmaps = qtrue;\r
-                               Sys_Printf( "Storing all lightmaps externally\n" );\r
-                       }\r
-               }\r
-               \r
-               /* ydnar: add this to suppress warnings */\r
-               else if( !strcmp( argv[ i ],  "-custinfoparms") )\r
-               {\r
-                       Sys_Printf( "Custom info parms enabled\n" );\r
-                       useCustomInfoParms = qtrue;\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-wolf" ) )\r
-               {\r
-                       /* -game should already be set */\r
-                       game->wolfLight = qtrue;\r
-                       Sys_Printf( "Enabling Wolf lighting model\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-sunonly" ) )\r
-               {\r
-                       sunOnly = qtrue;\r
-                       Sys_Printf( "Only computing sunlight\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-bounceonly" ) )\r
-               {\r
-                       bounceOnly = qtrue;\r
-                       Sys_Printf( "Storing bounced light (radiosity) only\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-nocollapse" ) )\r
-               {\r
-                       noCollapse = qtrue;\r
-                       Sys_Printf( "Identical lightmap collapsing disabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-shade" ) )\r
-               {\r
-                       shade = qtrue;\r
-                       Sys_Printf( "Phong shading enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-bouncegrid") )\r
-               {\r
-                       bouncegrid = qtrue;\r
-                       if( bounce > 0 )\r
-                               Sys_Printf( "Grid lighting with radiosity enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-smooth" ) )\r
-               {\r
-                       smooth = qtrue;\r
-                       lightSamples = EXTRA_SCALE;\r
-                       Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-fast" ) )\r
-               {\r
-                       fast = qtrue;\r
-                       fastgrid = qtrue;\r
-                       fastbounce = qtrue;\r
-                       Sys_Printf( "Fast mode enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-faster" ) )\r
-               {\r
-                       faster = qtrue;\r
-                       fast = qtrue;\r
-                       fastgrid = qtrue;\r
-                       fastbounce = qtrue;\r
-                       Sys_Printf( "Faster mode enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-fastgrid" ) )\r
-               {\r
-                       fastgrid = qtrue;\r
-                       Sys_Printf( "Fast grid lighting enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-fastbounce" ) )\r
-               {\r
-                       fastbounce = qtrue;\r
-                       Sys_Printf( "Fast bounce mode enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-cheap" ) )\r
-               {\r
-                       cheap = qtrue;\r
-                       cheapgrid = qtrue;\r
-                       Sys_Printf( "Cheap mode enabled\n" );\r
-               }\r
-\r
-               else if( !strcmp( argv[ i ], "-cheapgrid" ) )\r
-               {\r
-                       cheapgrid = qtrue;\r
-                       Sys_Printf( "Cheap grid mode enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-normalmap" ) )\r
-               {\r
-                       normalmap = qtrue;\r
-                       Sys_Printf( "Storing normal map instead of lightmap\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-trisoup" ) )\r
-               {\r
-                       trisoup = qtrue;\r
-                       Sys_Printf( "Converting brush faces to triangle soup\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-debug" ) )\r
-               {\r
-                       debug = qtrue;\r
-                       Sys_Printf( "Lightmap debugging enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )\r
-               {\r
-                       debugSurfaces = qtrue;\r
-                       Sys_Printf( "Lightmap surface debugging enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-debugunused" ) )\r
-               {\r
-                       debugUnused = qtrue;\r
-                       Sys_Printf( "Unused luxel debugging enabled\n" );\r
-               }\r
-\r
-               else if( !strcmp( argv[ i ], "-debugaxis" ) )\r
-               {\r
-                       debugAxis = qtrue;\r
-                       Sys_Printf( "Lightmap axis debugging enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-debugcluster" ) )\r
-               {\r
-                       debugCluster = qtrue;\r
-                       Sys_Printf( "Luxel cluster debugging enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-debugorigin" ) )\r
-               {\r
-                       debugOrigin = qtrue;\r
-                       Sys_Printf( "Luxel origin debugging enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-debugdeluxe" ) )\r
-               {\r
-                       deluxemap = qtrue;\r
-                       debugDeluxemap = qtrue;\r
-                       Sys_Printf( "Deluxemap debugging enabled\n" );\r
-               }\r
-               \r
-               else if( !strcmp( argv[ i ], "-export" ) )\r
-               {\r
-                       exportLightmaps = qtrue;\r
-                       Sys_Printf( "Exporting lightmaps\n" );\r
-               }\r
-               \r
-               else if( !strcmp(argv[ i ], "-notrace" )) \r
-               {\r
-                       noTrace = qtrue;\r
-                       Sys_Printf( "Shadow occlusion disabled\n" );\r
-               }\r
-               else if( !strcmp(argv[ i ], "-patchshadows" ) )\r
-               {\r
-                       patchShadows = qtrue;\r
-                       Sys_Printf( "Patch shadow casting enabled\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-extra" ) )\r
-               {\r
-                       extra = qtrue;\r
-                       superSample = EXTRA_SCALE;              /* ydnar */\r
-                       Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-extrawide" ) )\r
-               {\r
-                       extra = qtrue;\r
-                       extraWide = qtrue;\r
-                       superSample = EXTRAWIDE_SCALE;  /* ydnar */\r
-                       filter = qtrue;                                 /* ydnar */\r
-                       Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");\r
-               }\r
-               else if( !strcmp( argv[ i ], "-samplesize" ) )\r
-               {\r
-                       sampleSize = atoi( argv[ i + 1 ] );\r
-                       if( sampleSize < 1 )\r
-                               sampleSize = 1;\r
-                       i++;\r
-                       Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-novertex" ) )\r
-               {\r
-                       noVertexLighting = qtrue;\r
-                       Sys_Printf( "Disabling vertex lighting\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-nogrid" ) )\r
-               {\r
-                       noGridLighting = qtrue;\r
-                       Sys_Printf( "Disabling grid lighting\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-border" ) )\r
-               {\r
-                       lightmapBorder = qtrue;\r
-                       Sys_Printf( "Adding debug border to lightmaps\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-nosurf" ) )\r
-               {\r
-                       noSurfaces = qtrue;\r
-                       Sys_Printf( "Not tracing against surfaces\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-dump" ) )\r
-               {\r
-                       dump = qtrue;\r
-                       Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );\r
-               }\r
-               else if( !strcmp( argv[ i ], "-lomem" ) )\r
-               {\r
-                       loMem = qtrue;\r
-                       Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );\r
-               }\r
-               \r
-               else\r
-                       Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );\r
-       }\r
-       \r
-       /* clean up map name */\r
-       strcpy( source, ExpandArg( argv[ i ] ) );\r
-       StripExtension( source );\r
-       DefaultExtension( source, ".bsp" );\r
-       strcpy( mapSource, ExpandArg( argv[ i ] ) );\r
-       StripExtension( mapSource );\r
-       DefaultExtension( mapSource, ".map" );\r
-       \r
-       /* ydnar: set default sample size */\r
-       SetDefaultSampleSize( sampleSize );\r
-       \r
-       /* ydnar: handle shaders */\r
-       BeginMapShaderFile( source );\r
-       LoadShaderInfo();\r
-       \r
-       /* note loading */\r
-       Sys_Printf( "Loading %s\n", source );\r
-       \r
-       /* ydnar: load surface file */\r
-       LoadSurfaceExtraFile( source );\r
-       \r
-       /* load bsp file */\r
-       LoadBSPFile( source );\r
-       \r
-       /* parse bsp entities */\r
-       ParseEntities();\r
-       \r
-       /* load map file */\r
-       value = ValueForKey( &entities[ 0 ], "_keepLights" );\r
-       if( value[ 0 ] != '1' )\r
-               LoadMapFile( mapSource, qtrue );\r
-       \r
-       /* set the entity/model origins and init yDrawVerts */\r
-       SetEntityOrigins();\r
-       \r
-       /* ydnar: set up optimization */\r
-       SetupBrushes();\r
-       SetupSurfaceLightmaps();\r
-       \r
-       /* initialize the surface facet tracing */\r
-       SetupTraceNodes();\r
-       \r
-       /* light the world */\r
-       LightWorld();\r
-       \r
-       /* ydnar: store off lightmaps */\r
-       StoreSurfaceLightmaps();\r
-       \r
-       /* write out the bsp */\r
-       UnparseEntities();\r
-       Sys_Printf( "Writing %s\n", source );\r
-       WriteBSPFile( source );\r
-       \r
-       /* ydnar: export lightmaps */\r
-       if( exportLightmaps && !externalLightmaps )\r
-               ExportLightmaps();\r
-       \r
-       /* return to sender */\r
-       return 0;\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define LIGHT_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+/*
+CreateSunLight() - ydnar
+this creates a sun light
+*/
+
+static void CreateSunLight( sun_t *sun )
+{
+       int                     i;
+       float           photons, d, angle, elevation, da, de;
+       vec3_t          direction;
+       light_t         *light;
+       
+       
+       /* dummy check */
+       if( sun == NULL )
+               return;
+       
+       /* fixup */
+       if( sun->numSamples < 1 )
+               sun->numSamples = 1;
+       
+       /* set photons */
+       photons = sun->photons / sun->numSamples;
+       
+       /* create the right number of suns */
+       for( i = 0; i < sun->numSamples; i++ )
+       {
+               /* calculate sun direction */
+               if( i == 0 )
+                       VectorCopy( sun->direction, direction );
+               else
+               {
+                       /*
+                               sun->direction[ 0 ] = cos( angle ) * cos( elevation );
+                               sun->direction[ 1 ] = sin( angle ) * cos( elevation );
+                               sun->direction[ 2 ] = sin( elevation );
+                               
+                               xz_dist   = sqrt( x*x + z*z )
+                               latitude  = atan2( xz_dist, y ) * RADIANS
+                               longitude = atan2( x,       z ) * RADIANS
+                       */
+                       
+                       d = sqrt( sun->direction[ 0 ] * sun->direction[ 0 ] + sun->direction[ 1 ] * sun->direction[ 1 ] );
+                       angle = atan2( sun->direction[ 1 ], sun->direction[ 0 ] );
+                       elevation = atan2( sun->direction[ 2 ], d );
+                       
+                       /* jitter the angles (loop to keep random sample within sun->deviance steridians) */
+                       do
+                       {
+                               da = (Random() * 2.0f - 1.0f) * sun->deviance;
+                               de = (Random() * 2.0f - 1.0f) * sun->deviance;
+                       }
+                       while( (da * da + de * de) > (sun->deviance * sun->deviance) );
+                       angle += da;
+                       elevation += de;
+                       
+                       /* debug code */
+                       //%     Sys_Printf( "%d: Angle: %3.4f Elevation: %3.3f\n", sun->numSamples, (angle / Q_PI * 180.0f), (elevation / Q_PI * 180.0f) );
+                       
+                       /* create new vector */
+                       direction[ 0 ] = cos( angle ) * cos( elevation );
+                       direction[ 1 ] = sin( angle ) * cos( elevation );
+                       direction[ 2 ] = sin( elevation );
+               }
+               
+               /* create a light */
+               numSunLights++;
+               light = safe_malloc( sizeof( *light ) );
+               memset( light, 0, sizeof( *light ) );
+               light->next = lights;
+               lights = light;
+               
+               /* initialize the light */
+               light->flags = LIGHT_SUN_DEFAULT;
+               light->type = EMIT_SUN;
+               light->fade = 1.0f;
+               light->falloffTolerance = falloffTolerance;
+               light->filterRadius = sun->filterRadius / sun->numSamples;
+               
+               /* set the light's position out to infinity */
+               VectorMA( vec3_origin, (MAX_WORLD_COORD * 8.0f), direction, light->origin );    /* MAX_WORLD_COORD * 2.0f */
+               
+               /* set the facing to be the inverse of the sun direction */
+               VectorScale( direction, -1.0, light->normal );
+               light->dist = DotProduct( light->origin, light->normal );
+               
+               /* set color and photons */
+               VectorCopy( sun->color, light->color );
+               light->photons = photons * skyScale;
+       }
+
+       /* another sun? */
+       if( sun->next != NULL )
+               CreateSunLight( sun->next );
+}
+
+
+
+/*
+CreateSkyLights() - ydnar
+simulates sky light with multiple suns
+*/
+
+static void CreateSkyLights( vec3_t color, float value, int iterations, float filterRadius )
+{
+       int                     c, i, j, k, numSuns;
+       float           step, start;
+       vec3_t          in;
+       sun_t           sun;
+       
+       
+       /* dummy check */
+       if( value <= 0.0f || iterations < 2 )
+               return;
+       
+       /* calculate some stuff */
+       step = 2.0f / (iterations - 1);
+       start = -1.0f;
+       
+       /* basic sun setup */
+       VectorCopy( color, sun.color );
+       sun.deviance = 0.0f;
+       sun.filterRadius = filterRadius;
+       sun.numSamples = 1;
+       sun.next = NULL;
+       
+       /* iterate */
+       numSuns = 0;
+       for( c = 0; c < 2; c++ )
+       {
+               for( k = 0, in[ 2 ] = start; k < iterations; k++, in[ 2 ] += step )
+               {
+                       /* don't create sky light below the horizon */
+                       if( in[ 2 ] <= 0.0f )
+                               continue;
+                       
+                       for( j = 0, in[ 1 ] = start; j < iterations; j++, in[ 1 ] += step )
+                       {
+                               for( i = 0, in[ 0 ] = start; i < iterations; i++, in[ 0 ] += step )
+                               {
+                                       if( VectorNormalize( in, sun.direction ) )
+                                       {
+                                               if( c > 0 && numSuns > 0 )
+                                               {
+                                                       sun.photons = value / numSuns;
+                                                       CreateSunLight( &sun );
+                                               }
+                                               else
+                                                       numSuns++;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+
+/*
+CreateEntityLights()
+creates lights from light entities
+*/
+
+void CreateEntityLights( void )
+{
+       int                             i, j;
+       light_t                 *light, *light2;
+       entity_t                *e, *e2;
+       const char              *name;
+       const char              *target;
+       vec3_t                  dest;
+       const char              *_color;
+       float                   intensity, scale, deviance, filterRadius;
+       int                             spawnflags, flags, numSamples;
+       qboolean                junior;
+
+       
+       /* go throught entity list and find lights */
+       for( i = 0; i < numEntities; i++ )
+       {
+               /* get entity */
+               e = &entities[ i ];
+               name = ValueForKey( e, "classname" );
+               
+               /* ydnar: check for lightJunior */
+               if( Q_strncasecmp( name, "lightJunior", 11 ) == 0 )
+                       junior = qtrue;
+               else if( Q_strncasecmp( name, "light", 5 ) == 0 )
+                       junior = qfalse;
+               else
+                       continue;
+               
+               /* lights with target names (and therefore styles) are only parsed from BSP */
+               target = ValueForKey( e, "targetname" );
+               if( target[ 0 ] != '\0' && i >= numBSPEntities )
+                       continue;
+               
+               /* create a light */
+               numPointLights++;
+               light = safe_malloc( sizeof( *light ) );
+               memset( light, 0, sizeof( *light ) );
+               light->next = lights;
+               lights = light;
+               
+               /* handle spawnflags */
+               spawnflags = IntForKey( e, "spawnflags" );
+               
+               /* ydnar: quake 3+ light behavior */
+               if( game->wolfLight == qfalse )
+               {
+                       /* set default flags */
+                       flags = LIGHT_Q3A_DEFAULT;
+                       
+                       /* linear attenuation? */
+                       if( spawnflags & 1 )
+                       {
+                               flags |= LIGHT_ATTEN_LINEAR;
+                               flags &= ~LIGHT_ATTEN_ANGLE;
+                       }
+                       
+                       /* no angle attenuate? */
+                       if( spawnflags & 2 )
+                               flags &= ~LIGHT_ATTEN_ANGLE;
+               }
+               
+               /* ydnar: wolf light behavior */
+               else
+               {
+                       /* set default flags */
+                       flags = LIGHT_WOLF_DEFAULT;
+                       
+                       /* inverse distance squared attenuation? */
+                       if( spawnflags & 1 )
+                       {
+                               flags &= ~LIGHT_ATTEN_LINEAR;
+                               flags |= LIGHT_ATTEN_ANGLE;
+                       }
+                       
+                       /* angle attenuate? */
+                       if( spawnflags & 2 )
+                               flags |= LIGHT_ATTEN_ANGLE;
+               }
+               
+               /* other flags (borrowed from wolf) */
+               
+               /* wolf dark light? */
+               if( (spawnflags & 4) || (spawnflags & 8) )
+                       flags |= LIGHT_DARK;
+               
+               /* nogrid? */
+               if( spawnflags & 16 )
+                       flags &= ~LIGHT_GRID;
+               
+               /* junior? */
+               if( junior )
+               {
+                       flags |= LIGHT_GRID;
+                       flags &= ~LIGHT_SURFACES;
+               }
+               
+               /* store the flags */
+               light->flags = flags;
+               
+               /* ydnar: set fade key (from wolf) */
+               light->fade = 1.0f;
+               if( light->flags & LIGHT_ATTEN_LINEAR )
+               {
+                       light->fade = FloatForKey( e, "fade" );
+                       if( light->fade == 0.0f )
+                               light->fade = 1.0f;
+               }
+               
+               /* ydnar: set angle scaling (from vlight) */
+               light->angleScale = FloatForKey( e, "_anglescale" );
+               if( light->angleScale != 0.0f )
+                       light->flags |= LIGHT_ATTEN_ANGLE;
+               
+               /* set origin */
+               GetVectorForKey( e, "origin", light->origin);
+               light->style = IntForKey( e, "_style" );
+               if( light->style == 0 )
+                       light->style = IntForKey( e, "style" );
+               if( light->style < LS_NORMAL || light->style >= LS_NONE )
+                       Error( "Invalid lightstyle (%d) on entity %d", light->style, i );
+               
+               /* set light intensity */
+               intensity = FloatForKey( e, "_light" );
+               if( intensity == 0.0f )
+                       intensity = FloatForKey( e, "light" );
+               if( intensity == 0.0f)
+                       intensity = 300.0f;
+               
+               /* ydnar: set light scale (sof2) */
+               scale = FloatForKey( e, "scale" );
+               if( scale == 0.0f )
+                       scale = 1.0f;
+               intensity *= scale;
+               
+               /* ydnar: get deviance and samples */
+               deviance = FloatForKey( e, "_deviance" );
+               if( deviance == 0.0f )
+                       deviance = FloatForKey( e, "_deviation" );
+               if( deviance == 0.0f )
+                       deviance = FloatForKey( e, "_jitter" );
+               numSamples = IntForKey( e, "_samples" );
+               if( deviance < 0.0f || numSamples < 1 )
+               {
+                       deviance = 0.0f;
+                       numSamples = 1;
+               }
+               intensity /= numSamples;
+               
+               /* ydnar: get filter radius */
+               filterRadius = FloatForKey( e, "_filterradius" );
+               if( filterRadius == 0.0f )
+                       filterRadius = FloatForKey( e, "_filteradius" );
+               if( filterRadius == 0.0f )
+                       filterRadius = FloatForKey( e, "_filter" );
+               if( filterRadius < 0.0f )
+                       filterRadius = 0.0f;
+               light->filterRadius = filterRadius;
+               
+               /* set light color */
+               _color = ValueForKey( e, "_color" );
+               if( _color && _color[ 0 ] )
+               {
+                       sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
+                       ColorNormalize( light->color, light->color );
+               }
+               else
+                       light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
+               
+               intensity = intensity * pointScale;
+               light->photons = intensity;
+               
+               light->type = EMIT_POINT;
+               
+               /* set falloff threshold */
+               light->falloffTolerance = falloffTolerance / numSamples;
+               
+               /* lights with a target will be spotlights */
+               target = ValueForKey( e, "target" );
+               if( target[ 0 ] )
+               {
+                       float           radius;
+                       float           dist;
+                       sun_t           sun;
+                       const char      *_sun;
+                       
+                       
+                       /* get target */
+                       e2 = FindTargetEntity( target );
+                       if( e2 == NULL )
+                       {
+                               Sys_Printf( "WARNING: light at (%i %i %i) has missing target\n",
+                                       (int) light->origin[ 0 ], (int) light->origin[ 1 ], (int) light->origin[ 2 ] );
+                       }
+                       else
+                       {
+                               /* not a point light */
+                               numPointLights--;
+                               numSpotLights++;
+                               
+                               /* make a spotlight */
+                               GetVectorForKey( e2, "origin", dest );
+                               VectorSubtract( dest, light->origin, light->normal );
+                               dist = VectorNormalize( light->normal, light->normal );
+                               radius = FloatForKey( e, "radius" );
+                               if( !radius )
+                                       radius = 64;
+                               if( !dist )
+                                       dist = 64;
+                               light->radiusByDist = (radius + 16) / dist;
+                               light->type = EMIT_SPOT;
+                               
+                               /* ydnar: wolf mods: spotlights always use nonlinear + angle attenuation */
+                               light->flags &= ~LIGHT_ATTEN_LINEAR;
+                               light->flags |= LIGHT_ATTEN_ANGLE;
+                               light->fade = 1.0f;
+                               
+                               /* ydnar: is this a sun? */
+                               _sun = ValueForKey( e, "_sun" );
+                               if( _sun[ 0 ] == '1' )
+                               {
+                                       /* not a spot light */
+                                       numSpotLights--;
+                                       
+                                       /* unlink this light */
+                                       lights = light->next;
+                                       
+                                       /* make a sun */
+                                       VectorScale( light->normal, -1.0f, sun.direction );
+                                       VectorCopy( light->color, sun.color );
+                                       sun.photons = (intensity / pointScale);
+                                       sun.deviance = deviance / 180.0f * Q_PI;
+                                       sun.numSamples = numSamples;
+                                       sun.next = NULL;
+                                       
+                                       /* make a sun light */
+                                       CreateSunLight( &sun );
+                                       
+                                       /* free original light */
+                                       free( light );
+                                       light = NULL;
+                                       
+                                       /* skip the rest of this love story */
+                                       continue;
+                               }
+                       }
+               }
+               
+               /* jitter the light */
+               for( j = 1; j < numSamples; j++ )
+               {
+                       /* create a light */
+                       light2 = safe_malloc( sizeof( *light ) );
+                       memcpy( light2, light, sizeof( *light ) );
+                       light2->next = lights;
+                       lights = light2;
+                       
+                       /* add to counts */
+                       if( light->type == EMIT_SPOT )
+                               numSpotLights++;
+                       else
+                               numPointLights++;
+                       
+                       /* jitter it */
+                       light2->origin[ 0 ] = light->origin[ 0 ] + (Random() * 2.0f - 1.0f) * deviance;
+                       light2->origin[ 1 ] = light->origin[ 1 ] + (Random() * 2.0f - 1.0f) * deviance;
+                       light2->origin[ 2 ] = light->origin[ 2 ] + (Random() * 2.0f - 1.0f) * deviance;
+               }
+       }
+}
+
+
+
+/*
+CreateSurfaceLights() - ydnar
+this hijacks the radiosity code to generate surface lights for first pass
+*/
+
+#define APPROX_BOUNCE  1.0f
+
+void CreateSurfaceLights( void )
+{
+       int                                     i;
+       bspDrawSurface_t        *ds;
+       surfaceInfo_t           *info;
+       shaderInfo_t            *si;
+       light_t                         *light;
+       float                           subdivide;
+       vec3_t                          origin;
+       clipWork_t                      cw;
+       const char                      *nss;
+       
+       
+       /* get sun shader supressor */
+       nss = ValueForKey( &entities[ 0 ], "_noshadersun" );
+       
+       /* walk the list of surfaces */
+       for( i = 0; i < numBSPDrawSurfaces; i++ )
+       {
+               /* get surface and other bits */
+               ds = &bspDrawSurfaces[ i ];
+               info = &surfaceInfos[ i ];
+               si = info->si;
+               
+               /* sunlight? */
+               if( si->sun != NULL && nss[ 0 ] != '1' )
+               {
+                       Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader );
+                       CreateSunLight( si->sun );
+                       si->sun = NULL; /* FIXME: leak! */
+               }
+               
+               /* sky light? */
+               if( si->skyLightValue > 0.0f )
+               {
+                       Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader );
+                       CreateSkyLights( si->color, si->skyLightValue, si->skyLightIterations, si->lightFilterRadius );
+                       si->skyLightValue = 0.0f;       /* FIXME: hack! */
+               }
+               
+               /* try to early out */
+               if( si->value <= 0 )
+                       continue;
+               
+               /* autosprite shaders become point lights */
+               if( si->autosprite )
+               {
+                       /* create an average xyz */
+                       VectorAdd( info->mins, info->maxs, origin );
+                       VectorScale( origin, 0.5f, origin );
+                       
+                       /* create a light */
+                       light = safe_malloc( sizeof( *light ) );
+                       memset( light, 0, sizeof( *light ) );
+                       light->next = lights;
+                       lights = light;
+                       
+                       /* set it up */
+                       light->flags = LIGHT_Q3A_DEFAULT;
+                       light->type = EMIT_POINT;
+                       light->photons = si->value * pointScale;
+                       light->fade = 1.0f;
+                       light->si = si;
+                       VectorCopy( origin, light->origin );
+                       VectorCopy( si->color, light->color );
+                       light->falloffTolerance = falloffTolerance;
+                       light->style = light->style;
+                       
+                       /* add to point light count and continue */
+                       numPointLights++;
+                       continue;
+               }
+               
+               /* get subdivision amount */
+               if( si->lightSubdivide > 0 )
+                       subdivide = si->lightSubdivide;
+               else
+                       subdivide = defaultLightSubdivide;
+               
+               /* switch on type */
+               switch( ds->surfaceType )
+               {
+                       case MST_PLANAR:
+                       case MST_TRIANGLE_SOUP:
+                               RadLightForTriangles( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
+                               break;
+                       
+                       case MST_PATCH:
+                               RadLightForPatch( i, 0, info->lm, si, APPROX_BOUNCE, subdivide, &cw );
+                               break;
+                       
+                       default:
+                               break;
+               }
+       }
+}
+
+
+
+/*
+SetEntityOrigins()
+find the offset values for inline models
+*/
+
+void SetEntityOrigins( void )
+{
+       int                                     i, j, k, f;
+       entity_t                        *e;
+       vec3_t                          origin;
+       const char                      *key;
+       int                                     modelnum;
+       bspModel_t                      *dm;
+       bspDrawSurface_t        *ds;
+       
+       
+       /* ydnar: copy drawverts into private storage for nefarious purposes */
+       yDrawVerts = safe_malloc( numBSPDrawVerts * sizeof( bspDrawVert_t ) );
+       memcpy( yDrawVerts, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVert_t ) );
+       
+       /* set the entity origins */
+       for( i = 0; i < numEntities; i++ )
+       {
+               /* get entity and model */
+               e = &entities[ i ];
+               key = ValueForKey( e, "model" );
+               if( key[ 0 ] != '*' )
+                       continue;
+               modelnum = atoi( key + 1 );
+               dm = &bspModels[ modelnum ];
+               
+               /* get entity origin */
+               key = ValueForKey( e, "origin" );
+               if( key[ 0 ] == '\0' )
+                       continue;
+               GetVectorForKey( e, "origin", origin );
+               
+               /* set origin for all surfaces for this model */
+               for( j = 0; j < dm->numBSPSurfaces; j++ )
+               {
+                       /* get drawsurf */
+                       ds = &bspDrawSurfaces[ dm->firstBSPSurface + j ];
+                       
+                       /* set its verts */
+                       for( k = 0; k < ds->numVerts; k++ )
+                       {
+                               f = ds->firstVert + k;
+                               VectorAdd( origin, bspDrawVerts[ f ].xyz, yDrawVerts[ f ].xyz );
+                       }
+               }
+       }
+}
+
+
+
+/*
+PointToPolygonFormFactor()
+calculates the area over a point/normal hemisphere a winding covers
+ydnar: fixme: there has to be a faster way to calculate this
+without the expensive per-vert sqrts and transcendental functions
+ydnar 2002-09-30: added -faster switch because only 19% deviance > 10%
+between this and the approximation
+*/
+
+#define ONE_OVER_2PI   0.159154942f    //% (1.0f / (2.0f * 3.141592657f))
+
+float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w )
+{
+       vec3_t          triVector, triNormal;
+       int                     i, j;
+       vec3_t          dirs[ MAX_POINTS_ON_WINDING ];
+       float           total;
+       float           dot, angle, facing;
+       
+       
+       /* this is expensive */
+       for( i = 0; i < w->numpoints; i++ )
+       {
+               VectorSubtract( w->p[ i ], point, dirs[ i ] );
+               VectorNormalize( dirs[ i ], dirs[ i ] );
+       }
+       
+       /* duplicate first vertex to avoid mod operation */
+       VectorCopy( dirs[ 0 ], dirs[ i ] );
+       
+       /* calculcate relative area */
+       total = 0.0f;
+       for( i = 0; i < w->numpoints; i++ )
+       {
+               /* get a triangle */
+               j = i + 1;
+               dot = DotProduct( dirs[ i ], dirs[ j ] );
+               
+               /* roundoff can cause slight creep, which gives an IND from acos */
+               if( dot > 1.0f )
+                       dot = 1.0f;
+               else if( dot < -1.0f )
+                       dot = -1.0f;
+               
+               /* get the angle */
+               angle = acos( dot );
+               
+               CrossProduct( dirs[ i ], dirs[ j ], triVector );
+               if( VectorNormalize( triVector, triNormal ) < 0.0001f )
+                       continue;
+               
+               facing = DotProduct( normal, triNormal );
+               total += facing * angle;
+               
+               /* ydnar: this was throwing too many errors with radiosity + crappy maps. ignoring it. */
+               if( total > 6.3f || total < -6.3f )
+                       return 0.0f;
+       }
+       
+       /* now in the range of 0 to 1 over the entire incoming hemisphere */
+       //%     total /= (2.0f * 3.141592657f);
+       total *= ONE_OVER_2PI;
+       return total;
+}
+
+
+
+/*
+LightContributionTosample()
+determines the amount of light reaching a sample (luxel or vertex) from a given light
+*/
+
+int LightContributionToSample( trace_t *trace )
+{
+       light_t                 *light;
+       float                   angle;
+       float                   add;
+       float                   dist;
+       
+       
+       /* get light */
+       light = trace->light;
+       
+       /* clear color */
+       VectorClear( trace->color );
+       
+       /* ydnar: early out */
+       if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
+               return 0;
+       
+       /* do some culling checks */
+       if( light->type != EMIT_SUN )
+       {
+               /* MrE: if the light is behind the surface */
+               if( trace->twoSided == qfalse )
+                       if( DotProduct( light->origin, trace->normal ) - DotProduct( trace->origin, trace->normal ) < 0.0f )
+                               return 0;
+               
+               /* ydnar: test pvs */
+               if( !ClusterVisible( trace->cluster, light->cluster ) )
+                       return 0;
+       }
+       
+       /* ptpff approximation */
+       if( light->type == EMIT_AREA && faster )
+       {
+               /* get direction and distance */
+               VectorCopy( light->origin, trace->end );
+               dist = SetupTrace( trace );
+               if( dist >= light->envelope )
+                       return 0;
+               
+               /* clamp the distance to prevent super hot spots */
+               if( dist < 16.0f )
+                       dist = 16.0f;
+               
+               /* angle attenuation */
+               angle = DotProduct( trace->normal, trace->direction );
+               
+               /* twosided lighting */
+               if( trace->twoSided )
+                       angle = fabs( angle );
+               
+               /* attenuate */
+               angle *= -DotProduct( light->normal, trace->direction );
+               if( angle <= 0.0f )
+                       return 0;
+               add = light->photons / (dist * dist) * angle;
+       }
+       
+       /* exact point to polygon form factor */
+       else if( light->type == EMIT_AREA )
+       {
+               float           factor;
+               float           d;
+               vec3_t          pushedOrigin;
+               
+               
+               /* project sample point into light plane */
+               d = DotProduct( trace->origin, light->normal ) - light->dist;
+               //%     if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
+               //%             return 0;
+               if( d < 3.0f )
+               {
+                       /* sample point behind plane? */
+                       if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
+                               return 0;
+                       
+                       /* sample plane coincident? */
+                       if( d > -3.0f && DotProduct( trace->normal, light->normal ) > 0.9f )
+                               return 0;
+               }
+               
+               /* nudge the point so that it is clearly forward of the light */
+               /* so that surfaces meeting a light emiter don't get black edges */
+               if( d > -8.0f && d < 8.0f )
+                       VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
+               else
+                       VectorCopy( trace->origin, pushedOrigin );
+               
+               /* get direction and distance */
+               VectorCopy( light->origin, trace->end );
+               dist = SetupTrace( trace );
+               if( dist >= light->envelope )
+                       return 0;
+               
+               /* calculate the contribution */
+               factor = PointToPolygonFormFactor( pushedOrigin, trace->normal, light->w );
+               if( factor == 0.0f )
+                       return 0;
+               else if( factor < 0.0f )
+               {
+                       /* twosided lighting */
+                       if( trace->twoSided || (light->flags & LIGHT_TWOSIDED) )
+                       {
+                               factor = -factor;
+
+                               /* push light origin to other side of the plane */
+                               VectorMA( light->origin, -2.0f, light->normal, trace->end );
+                               dist = SetupTrace( trace );
+                               if( dist >= light->envelope )
+                                       return 0;
+                       }
+                       else
+                               return 0;
+               }
+               
+               /* ydnar: moved to here */
+               add = factor * light->add;
+       }
+       
+       /* point/spot lights */
+       else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
+       {
+               /* get direction and distance */
+               VectorCopy( light->origin, trace->end );
+               dist = SetupTrace( trace );
+               if( dist >= light->envelope )
+                       return 0;
+               
+               /* clamp the distance to prevent super hot spots */
+               if( dist < 16.0f )
+                       dist = 16.0f;
+               
+               /* angle attenuation */
+               angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
+               if( light->angleScale != 0.0f )
+               {
+                       angle /= light->angleScale;
+                       if( angle > 1.0f )
+                               angle = 1.0f;
+               }
+               
+               /* twosided lighting */
+               if( trace->twoSided )
+                       angle = fabs( angle );
+               
+               /* attenuate */
+               if( light->flags & LIGHT_ATTEN_LINEAR )
+               {
+                       add = angle * light->photons * linearScale - (dist * light->fade);
+                       if( add < 0.0f )
+                               add = 0.0f;
+               }
+               else
+                       add = light->photons / (dist * dist) * angle;
+               
+               /* handle spotlights */
+               if( light->type == EMIT_SPOT )
+               {
+                       float   distByNormal, radiusAtDist, sampleRadius;
+                       vec3_t  pointAtDist, distToSample;
+                       
+                       
+                       /* do cone calculation */
+                       distByNormal = -DotProduct( trace->displacement, light->normal );
+                       if( distByNormal < 0.0f )
+                               return 0;
+                       VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
+                       radiusAtDist = light->radiusByDist * distByNormal;
+                       VectorSubtract( trace->origin, pointAtDist, distToSample );
+                       sampleRadius = VectorLength( distToSample );
+                       
+                       /* outside the cone */
+                       if( sampleRadius >= radiusAtDist )
+                               return 0;
+                       
+                       /* attenuate */
+                       if( sampleRadius > (radiusAtDist - 32.0f) )
+                               add *= ((radiusAtDist - sampleRadius) / 32.0f);
+               }
+       }
+       
+       /* ydnar: sunlight */
+       else if( light->type == EMIT_SUN )
+       {
+               /* get origin and direction */
+               VectorAdd( trace->origin, light->origin, trace->end );
+               dist = SetupTrace( trace );
+               
+               /* angle attenuation */
+               angle = (light->flags & LIGHT_ATTEN_ANGLE)
+                       ? DotProduct( trace->normal, trace->direction )
+                       : 1.0f;
+               
+               /* twosided lighting */
+               if( trace->twoSided )
+                       angle = fabs( angle );
+               
+               /* attenuate */
+               add = light->photons * angle;
+               if( add <= 0.0f )
+                       return 0;
+               
+               /* setup trace */
+               trace->testAll = qtrue;
+               VectorScale( light->color, add, trace->color );
+               
+               /* trace to point */
+               if( trace->testOcclusion && !trace->forceSunlight )
+               {
+                       /* trace */
+                       TraceLine( trace );
+                       if( !(trace->compileFlags & C_SKY) || trace->opaque )
+                       {
+                               VectorClear( trace->color );
+                               return -1;
+                       }
+               }
+               
+               /* return to sender */
+               return 1;
+       }
+       
+       /* ydnar: changed to a variable number */
+       if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
+               return 0;
+       
+       /* setup trace */
+       trace->testAll = qfalse;
+       VectorScale( light->color, add, trace->color );
+       
+       /* raytrace */
+       TraceLine( trace );
+       if( trace->passSolid || trace->opaque )
+       {
+               VectorClear( trace->color );
+               return -1;
+       }
+       
+       /* return to sender */
+       return 1;
+}
+
+
+
+/*
+LightingAtSample()
+determines the amount of light reaching a sample (luxel or vertex)
+*/
+
+void LightingAtSample( trace_t *trace, byte styles[ MAX_LIGHTMAPS ], vec3_t colors[ MAX_LIGHTMAPS ] )
+{
+       int                             i, lightmapNum;
+       
+       
+       /* clear colors */
+       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               VectorClear( colors[ lightmapNum ] );
+       
+       /* ydnar: normalmap */
+       if( normalmap )
+       {
+               colors[ 0 ][ 0 ] = (trace->normal[ 0 ] + 1.0f) * 127.5f;
+               colors[ 0 ][ 1 ] = (trace->normal[ 1 ] + 1.0f) * 127.5f;
+               colors[ 0 ][ 2 ] = (trace->normal[ 2 ] + 1.0f) * 127.5f;
+               return;
+       }
+       
+       /* ydnar: don't bounce ambient all the time */
+       if( !bouncing )
+               VectorCopy( ambientColor, colors[ 0 ] );
+       
+       /* ydnar: trace to all the list of lights pre-stored in tw */
+       for( i = 0; i < trace->numLights && trace->lights[ i ] != NULL; i++ )
+       {
+               /* set light */
+               trace->light = trace->lights[ i ];
+               
+               /* style check */
+               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               {
+                       if( styles[ lightmapNum ] == trace->light->style ||
+                               styles[ lightmapNum ] == LS_NONE )
+                               break;
+               }
+               
+               /* max of MAX_LIGHTMAPS (4) styles allowed to hit a sample */
+               if( lightmapNum >= MAX_LIGHTMAPS )
+                       continue;
+               
+               /* sample light */
+               LightContributionToSample( trace );
+               if( trace->color[ 0 ] == 0.0f && trace->color[ 1 ] == 0.0f && trace->color[ 2 ] == 0.0f )
+                       continue;
+               
+               /* handle negative light */
+               if( trace->light->flags & LIGHT_NEGATIVE )
+                       VectorScale( trace->color, -1.0f, trace->color );
+               
+               /* set style */
+               styles[ lightmapNum ] = trace->light->style;
+               
+               /* add it */
+               VectorAdd( colors[ lightmapNum ], trace->color, colors[ lightmapNum ] );
+               
+               /* cheap mode */
+               if( cheap &&
+                       colors[ 0 ][ 0 ] >= 255.0f &&
+                       colors[ 0 ][ 1 ] >= 255.0f &&
+                       colors[ 0 ][ 2 ] >= 255.0f )
+                       break;
+       }
+}
+
+
+
+/*
+LightContributionToPoint()
+for a given light, how much light/color reaches a given point in space (with no facing)
+note: this is similar to LightContributionToSample() but optimized for omnidirectional sampling
+*/
+
+int LightContributionToPoint( trace_t *trace )
+{
+       light_t         *light;
+       float           add, dist;
+       
+       
+       /* get light */
+       light = trace->light;
+       
+       /* clear color */
+       VectorClear( trace->color );
+       
+       /* ydnar: early out */
+       if( !(light->flags & LIGHT_GRID) || light->envelope <= 0.0f )
+               return qfalse;
+       
+       /* is this a sun? */
+       if( light->type != EMIT_SUN )
+       {
+               /* sun only? */
+               if( sunOnly )
+                       return qfalse;
+               
+               /* test pvs */
+               if( !ClusterVisible( trace->cluster, light->cluster ) )
+                       return qfalse;
+       }
+       
+       /* ydnar: check origin against light's pvs envelope */
+       if( trace->origin[ 0 ] > light->maxs[ 0 ] || trace->origin[ 0 ] < light->mins[ 0 ] ||
+               trace->origin[ 1 ] > light->maxs[ 1 ] || trace->origin[ 1 ] < light->mins[ 1 ] ||
+               trace->origin[ 2 ] > light->maxs[ 2 ] || trace->origin[ 2 ] < light->mins[ 2 ] )
+       {
+               gridBoundsCulled++;
+               return qfalse;
+       }
+       
+       /* set light origin */
+       if( light->type == EMIT_SUN )
+               VectorAdd( trace->origin, light->origin, trace->end );
+       else
+               VectorCopy( light->origin, trace->end );
+       
+       /* set direction */
+       dist = SetupTrace( trace );
+       
+       /* test envelope */
+       if( dist > light->envelope )
+       {
+               gridEnvelopeCulled++;
+               return qfalse;
+       }
+       
+       /* ptpff approximation */
+       if( light->type == EMIT_AREA && faster )
+       {
+               /* clamp the distance to prevent super hot spots */
+               if( dist < 16.0f )
+                       dist = 16.0f;
+               
+               /* attenuate */
+               add = light->photons / (dist * dist);
+       }
+       
+       /* exact point to polygon form factor */
+       else if( light->type == EMIT_AREA )
+       {
+               float           factor, d;
+               vec3_t          pushedOrigin;
+               
+               
+               /* see if the point is behind the light */
+               d = DotProduct( trace->origin, light->normal ) - light->dist;
+               if( !(light->flags & LIGHT_TWOSIDED) && d < -1.0f )
+                       return qfalse;
+               
+               /* nudge the point so that it is clearly forward of the light */
+               /* so that surfaces meeting a light emiter don't get black edges */
+               if( d > -8.0f && d < 8.0f )
+                       VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );                             
+               else
+                       VectorCopy( trace->origin, pushedOrigin );
+               
+               /* calculate the contribution (ydnar 2002-10-21: [bug 642] bad normal calc) */
+               factor = PointToPolygonFormFactor( pushedOrigin, trace->direction, light->w );
+               if( factor == 0.0f )
+                       return qfalse;
+               else if( factor < 0.0f )
+               {
+                       if( light->flags & LIGHT_TWOSIDED )
+                               factor = -factor;
+                       else
+                               return qfalse;
+               }
+               
+               /* ydnar: moved to here */
+               add = factor * light->add;
+       }
+       
+       /* point/spot lights */
+       else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
+       {
+               /* clamp the distance to prevent super hot spots */
+               if( dist < 16.0f )
+                       dist = 16.0f;
+               
+               /* attenuate */
+               if( light->flags & LIGHT_ATTEN_LINEAR )
+               {
+                       add = light->photons * linearScale - (dist * light->fade);
+                       if( add < 0.0f )
+                               add = 0.0f;
+               }
+               else
+                       add = light->photons / (dist * dist);
+               
+               /* handle spotlights */
+               if( light->type == EMIT_SPOT )
+               {
+                       float   distByNormal, radiusAtDist, sampleRadius;
+                       vec3_t  pointAtDist, distToSample;
+                       
+                       
+                       /* do cone calculation */
+                       distByNormal = -DotProduct( trace->displacement, light->normal );
+                       if( distByNormal < 0.0f )
+                               return qfalse;
+                       VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
+                       radiusAtDist = light->radiusByDist * distByNormal;
+                       VectorSubtract( trace->origin, pointAtDist, distToSample );
+                       sampleRadius = VectorLength( distToSample );
+                       
+                       /* outside the cone */
+                       if( sampleRadius >= radiusAtDist )
+                               return qfalse;
+                       
+                       /* attenuate */
+                       if( sampleRadius > (radiusAtDist - 32.0f) )
+                               add *= ((radiusAtDist - sampleRadius) / 32.0f);
+               }
+       }
+       
+       /* ydnar: sunlight */
+       else if( light->type == EMIT_SUN )
+       {
+               /* attenuate */
+               add = light->photons;
+               if( add <= 0.0f )
+                       return qfalse;
+               
+               /* setup trace */
+               trace->testAll = qtrue;
+               VectorScale( light->color, add, trace->color );
+               
+               /* trace to point */
+               if( trace->testOcclusion && !trace->forceSunlight )
+               {
+                       /* trace */
+                       TraceLine( trace );
+                       if( !(trace->compileFlags & C_SKY) || trace->opaque )
+                       {
+                               VectorClear( trace->color );
+                               return -1;
+                       }
+               }
+               
+               /* return to sender */
+               return qtrue;
+       }
+       
+       /* unknown light type */
+       else
+               return qfalse;
+       
+       /* ydnar: changed to a variable number */
+       if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
+               return qfalse;
+       
+       /* setup trace */
+       trace->testAll = qfalse;
+       VectorScale( light->color, add, trace->color );
+       
+       /* trace */
+       TraceLine( trace );
+       if( trace->passSolid )
+       {
+               VectorClear( trace->color );
+               return qfalse;
+       }
+       
+       /* we have a valid sample */
+       return qtrue;
+}
+
+
+
+/*
+TraceGrid()
+grid samples are for quickly determining the lighting
+of dynamically placed entities in the world
+*/
+
+#define        MAX_CONTRIBUTIONS       1024
+
+typedef struct
+{
+       vec3_t          dir;
+       vec3_t          color;
+       int                     style;
+}
+contribution_t;
+
+void TraceGrid( int num )
+{
+       int                                             i, j, x, y, z, mod, step, numCon, numStyles;
+       float                                   d;
+       vec3_t                                  baseOrigin, cheapColor, color;
+       rawGridPoint_t                  *gp;
+       bspGridPoint_t                  *bgp;
+       contribution_t                  contributions[ MAX_CONTRIBUTIONS ];
+       trace_t                                 trace;
+       
+       
+       /* get grid points */
+       gp = &rawGridPoints[ num ];
+       bgp = &bspGridPoints[ num ];
+       
+       /* get grid origin */
+       mod = num;
+       z = mod / (gridBounds[ 0 ] * gridBounds[ 1 ]);
+       mod -= z * (gridBounds[ 0 ] * gridBounds[ 1 ]);
+       y = mod / gridBounds[ 0 ];
+       mod -= y * gridBounds[ 0 ];
+       x = mod;
+       
+       trace.origin[ 0 ] = gridMins[ 0 ] + x * gridSize[ 0 ];
+       trace.origin[ 1 ] = gridMins[ 1 ] + y * gridSize[ 1 ];
+       trace.origin[ 2 ] = gridMins[ 2 ] + z * gridSize[ 2 ];
+       
+       /* set inhibit sphere */
+       if( gridSize[ 0 ] > gridSize[ 1 ] && gridSize[ 0 ] > gridSize[ 2 ] )
+               trace.inhibitRadius = gridSize[ 0 ] * 0.5f;
+       else if( gridSize[ 1 ] > gridSize[ 0 ] && gridSize[ 1 ] > gridSize[ 2 ] )
+               trace.inhibitRadius = gridSize[ 1 ] * 0.5f;
+       else
+               trace.inhibitRadius = gridSize[ 2 ] * 0.5f;
+       
+       /* find point cluster */
+       trace.cluster = ClusterForPointExt( trace.origin, GRID_EPSILON );
+       if( trace.cluster < 0 )
+       {
+               /* try to nudge the origin around to find a valid point */
+               VectorCopy( trace.origin, baseOrigin );
+               for( step = 9; step <= 18; step += 9 )
+               {
+                       for( i = 0; i < 8; i++ )
+                       {
+                               VectorCopy( baseOrigin, trace.origin );
+                               if( i & 1 )
+                                       trace.origin[ 0 ] += step;
+                               else
+                                       trace.origin[ 0 ] -= step;
+                               
+                               if( i & 2 )
+                                       trace.origin[ 1 ] += step;
+                               else
+                                       trace.origin[ 1 ] -= step;
+                               
+                               if( i & 4 )
+                                       trace.origin[ 2 ] += step;
+                               else
+                                       trace.origin[ 2 ] -= step;
+                               
+                               /* ydnar: changed to find cluster num */
+                               trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
+                               if( trace.cluster >= 0 )
+                                       break;
+                       }
+                       
+                       if( i != 8 )
+                               break;
+               }
+               
+               /* can't find a valid point at all */
+               if( step > 18 )
+                       return;
+       }
+       
+       /* setup trace */
+       trace.testOcclusion = !noTrace;
+       trace.forceSunlight = qfalse;
+       trace.recvShadows = WORLDSPAWN_RECV_SHADOWS;
+       trace.numSurfaces = 0;
+       trace.surfaces = NULL;
+       trace.numLights = 0;
+       trace.lights = NULL;
+       
+       /* clear */
+       numCon = 0;
+       VectorClear( cheapColor );
+       
+       /* trace to all the lights, find the major light direction, and divide the
+          total light between that along the direction and the remaining in the ambient */
+       for( trace.light = lights; trace.light != NULL; trace.light = trace.light->next )
+       {
+               float           addSize;
+               
+               
+               /* sample light */
+               if( !LightContributionToPoint( &trace ) )
+                       continue;
+               
+               /* handle negative light */
+               if( trace.light->flags & LIGHT_NEGATIVE )
+                       VectorScale( trace.color, -1.0f, trace.color );
+               
+               /* add a contribution */
+               VectorCopy( trace.color, contributions[ numCon ].color );
+               VectorCopy( trace.direction, contributions[ numCon ].dir );
+               contributions[ numCon ].style = trace.light->style;
+               numCon++;
+               
+               /* push average direction around */
+               addSize = VectorLength( trace.color );
+               VectorMA( gp->dir, addSize, trace.direction, gp->dir );
+               
+               /* stop after a while */
+               if( numCon >= (MAX_CONTRIBUTIONS - 1) )
+                       break;
+               
+               /* ydnar: cheap mode */
+               VectorAdd( cheapColor, trace.color, cheapColor );
+               if( cheapgrid && cheapColor[ 0 ] >= 255.0f && cheapColor[ 1 ] >= 255.0f && cheapColor[ 2 ] >= 255.0f )
+                       break;
+       }
+       
+       /* normalize to get primary light direction */
+       VectorNormalize( gp->dir, gp->dir );
+       
+       /* now that we have identified the primary light direction,
+          go back and separate all the light into directed and ambient */
+       numStyles = 1;
+       for( i = 0; i < numCon; i++ )
+       {
+               /* get relative directed strength */
+               d = DotProduct( contributions[ i ].dir, gp->dir );
+               if( d < 0.0f )
+                       d = 0.0f;
+               
+               /* find appropriate style */
+               for( j = 0; j < numStyles; j++ )
+               {
+                       if( gp->styles[ j ] == contributions[ i ].style )
+                               break;
+               }
+               
+               /* style not found? */
+               if( j >= numStyles )
+               {
+                       /* add a new style */
+                       if( numStyles < MAX_LIGHTMAPS )
+                       {
+                               gp->styles[ numStyles ] = contributions[ i ].style;
+                               bgp->styles[ numStyles ] = contributions[ i ].style;
+                               numStyles++;
+                               //%     Sys_Printf( "(%d, %d) ", num, contributions[ i ].style );
+                       }
+                       
+                       /* fallback */
+                       else
+                               j = 0;
+               }
+               
+               /* add the directed color */
+               VectorMA( gp->directed[ j ], d, contributions[ i ].color, gp->directed[ j ] );
+               
+               /* ambient light will be at 1/4 the value of directed light */
+               /* (ydnar: nuke this in favor of more dramatic lighting?) */
+               d = 0.25f * (1.0f - d);
+               VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
+       }
+       
+       
+       /* store off sample */
+       for( i = 0; i < MAX_LIGHTMAPS; i++ )
+       {
+               /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
+               if( !bouncing )
+                       VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
+               
+               /* set minimum light and copy off to bytes */
+               VectorCopy( gp->ambient[ i ], color );
+               for( j = 0; j < 3; j++ )
+                       if( color[ j ] < minGridLight[ j ] )
+                               color[ j ] = minGridLight[ j ];
+               ColorToBytes( color, bgp->ambient[ i ], 1.0f );
+               ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );
+       }
+       
+       /* debug code */
+       #if 0
+               //%     Sys_FPrintf( SYS_VRB, "%10d %10d %10d ", &gp->ambient[ 0 ][ 0 ], &gp->ambient[ 0 ][ 1 ], &gp->ambient[ 0 ][ 2 ] );
+               Sys_FPrintf( SYS_VRB, "%9d Amb: (%03.1f %03.1f %03.1f) Dir: (%03.1f %03.1f %03.1f)\n",
+                       num,
+                       gp->ambient[ 0 ][ 0 ], gp->ambient[ 0 ][ 1 ], gp->ambient[ 0 ][ 2 ],
+                       gp->directed[ 0 ][ 0 ], gp->directed[ 0 ][ 1 ], gp->directed[ 0 ][ 2 ] );
+       #endif
+       
+       /* store direction */
+       NormalToLatLong( gp->dir, bgp->latLong );
+}
+
+
+
+/*
+SetupGrid()
+calculates the size of the lightgrid and allocates memory
+*/
+
+void SetupGrid( void )
+{
+       int                     i, j;
+       vec3_t          maxs, oldGridSize;
+       const char      *value;
+       char            temp[ 64 ];
+       
+        
+       /* don't do this if not grid lighting */
+       if( noGridLighting )
+               return;
+       
+       /* ydnar: set grid size */
+       value = ValueForKey( &entities[ 0 ], "gridsize" );
+       if( value[ 0 ] != '\0' )
+               sscanf( value, "%f %f %f", &gridSize[ 0 ], &gridSize[ 1 ], &gridSize[ 2 ] );
+       
+       /* quantize it */
+       VectorCopy( gridSize, oldGridSize );
+       for( i = 0; i < 3; i++ )
+               gridSize[ i ] = gridSize[ i ] >= 8.0f ? floor( gridSize[ i ] ) : 8.0f;
+       
+       /* ydnar: increase gridSize until grid count is smaller than max allowed */
+       numRawGridPoints = MAX_MAP_LIGHTGRID + 1;
+       j = 0;
+       while( numRawGridPoints > MAX_MAP_LIGHTGRID )
+       {
+               /* get world bounds */
+               for( i = 0; i < 3; i++ )
+               {
+                       gridMins[ i ] = gridSize[ i ] * ceil( bspModels[ 0 ].mins[ i ] / gridSize[ i ] );
+                       maxs[ i ] = gridSize[ i ] * floor( bspModels[ 0 ].maxs[ i ] / gridSize[ i ] );
+                       gridBounds[ i ] = (maxs[ i ] - gridMins[ i ]) / gridSize[ i ] + 1;
+               }
+       
+               /* set grid size */
+               numRawGridPoints = gridBounds[ 0 ] * gridBounds[ 1 ] * gridBounds[ 2 ];
+               
+               /* increase grid size a bit */
+               if( numRawGridPoints > MAX_MAP_LIGHTGRID )
+                       gridSize[ j++ % 3 ] += 16.0f;
+       }
+       
+       /* print it */
+       Sys_Printf( "Grid size = { %1.0f, %1.0f, %1.0f }\n", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
+       
+       /* different? */
+       if( !VectorCompare( gridSize, oldGridSize ) )
+       {
+               sprintf( temp, "%.0f %.0f %.0f", gridSize[ 0 ], gridSize[ 1 ], gridSize[ 2 ] );
+               SetKeyValue( &entities[ 0 ], "gridsize", (const char*) temp );
+               Sys_FPrintf( SYS_VRB, "Storing adjusted grid size\n" );
+       }
+       
+       /* 2nd variable. fixme: is this silly? */
+       numBSPGridPoints = numRawGridPoints;
+       
+       /* allocate lightgrid */
+       rawGridPoints = safe_malloc( numRawGridPoints * sizeof( *rawGridPoints ) );
+       memset( rawGridPoints, 0, numRawGridPoints * sizeof( *rawGridPoints ) );
+       
+       if( bspGridPoints != NULL )
+               free( bspGridPoints );
+       bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
+       memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
+       
+       /* clear lightgrid */
+       for( i = 0; i < numRawGridPoints; i++ )
+       {
+               VectorCopy( ambientColor, rawGridPoints[ i ].ambient[ j ] );
+               rawGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
+               bspGridPoints[ i ].styles[ 0 ] = LS_NORMAL;
+               for( j = 1; j < MAX_LIGHTMAPS; j++ )
+               {
+                       rawGridPoints[ i ].styles[ j ] = LS_NONE;
+                       bspGridPoints[ i ].styles[ j ] = LS_NONE;
+               }
+       }
+       
+       /* note it */
+       Sys_Printf( "%9d grid points\n", numRawGridPoints );
+}
+
+
+
+/*
+LightWorld()
+does what it says...
+*/
+
+void LightWorld( void )
+{
+       vec3_t          color;
+       float           f;
+       int                     b, bt;
+       qboolean        minVertex, minGrid;
+       const char      *value;
+       
+
+       /* ydnar: smooth normals */
+       if( shade )
+       {
+               Sys_Printf( "--- SmoothNormals ---\n" );
+               SmoothNormals();
+       }
+       
+       /* determine the number of grid points */
+       Sys_Printf( "--- SetupGrid ---\n" );
+       SetupGrid();
+       
+       /* find the optional minimum lighting values */
+       GetVectorForKey( &entities[ 0 ], "_color", color );
+       if( VectorLength( color ) == 0.0f )
+               VectorSet( color, 1.0, 1.0, 1.0 );
+       
+       /* ambient */
+       f = FloatForKey( &entities[ 0 ], "_ambient" );
+       if( f == 0.0f )
+               f = FloatForKey( &entities[ 0 ], "ambient" );
+       VectorScale( color, f, ambientColor );
+       
+       /* minvertexlight */
+       minVertex = qfalse;
+       value = ValueForKey( &entities[ 0 ], "_minvertexlight" );
+       if( value[ 0 ] != '\0' )
+       {
+               minVertex = qtrue;
+               f = atof( value );
+               VectorScale( color, f, minVertexLight );
+       }
+       
+       /* mingridlight */
+       minGrid = qfalse;
+       value = ValueForKey( &entities[ 0 ], "_mingridlight" );
+       if( value[ 0 ] != '\0' )
+       {
+               minGrid = qtrue;
+               f = atof( value );
+               VectorScale( color, f, minGridLight );
+       }
+       
+       /* minlight */
+       value = ValueForKey( &entities[ 0 ], "_minlight" );
+       if( value[ 0 ] != '\0' )
+       {
+               f = atof( value );
+               VectorScale( color, f, minLight );
+               if( minVertex == qfalse )
+                       VectorScale( color, f, minVertexLight );
+               if( minGrid == qfalse )
+                       VectorScale( color, f, minGridLight );
+       }
+       
+       /* create world lights */
+       Sys_FPrintf( SYS_VRB, "--- CreateLights ---\n" );
+       CreateEntityLights();
+       CreateSurfaceLights();
+       Sys_Printf( "%9d point lights\n", numPointLights );
+       Sys_Printf( "%9d spotlights\n", numSpotLights );
+       Sys_Printf( "%9d diffuse (area) lights\n", numDiffuseLights );
+       Sys_Printf( "%9d sun/sky lights\n", numSunLights );
+       
+       /* calculate lightgrid */
+       if( !noGridLighting )
+       {
+               /* ydnar: set up light envelopes */
+               SetupEnvelopes( qtrue, fastgrid );
+               
+               Sys_Printf( "--- TraceGrid ---\n" );
+               RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
+               Sys_Printf( "%d x %d x %d = %d grid\n",
+                       gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
+               
+               /* ydnar: emit statistics on light culling */
+               Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
+               Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
+       }
+       
+       /* slight optimization to remove a sqrt */
+       subdivideThreshold *= subdivideThreshold;
+       
+       /* map the world luxels */
+       Sys_Printf( "--- MapRawLightmap ---\n" );
+       RunThreadsOnIndividual( numRawLightmaps, qtrue, MapRawLightmap );
+       Sys_Printf( "%9d luxels\n", numLuxels );
+       Sys_Printf( "%9d luxels mapped\n", numLuxelsMapped );
+       Sys_Printf( "%9d luxels occluded\n", numLuxelsOccluded );
+
+       /* ydnar: set up light envelopes */
+       SetupEnvelopes( qfalse, fast );
+       
+       /* light up my world */
+       lightsPlaneCulled = 0;
+       lightsEnvelopeCulled = 0;
+       lightsBoundsCulled = 0;
+       lightsClusterCulled = 0;
+       
+       Sys_Printf( "--- IlluminateRawLightmap ---\n" );
+       RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
+       Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
+       
+       StitchSurfaceLightmaps();
+       
+       Sys_Printf( "--- IlluminateVertexes ---\n" );
+       RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
+       Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
+       
+       /* ydnar: emit statistics on light culling */
+       Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
+       Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
+       Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
+       Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
+       
+       /* radiosity */
+       b = 1;
+       bt = bounce;
+       while( bounce > 0 )
+       {
+               /* store off the bsp between bounces */
+               StoreSurfaceLightmaps();
+               Sys_Printf( "Writing %s\n", source );
+               WriteBSPFile( source );
+               
+               /* note it */
+               Sys_Printf( "\n--- Radiosity (bounce %d of %d) ---\n", b, bt );
+               
+               /* flag bouncing */
+               bouncing = qtrue;
+               VectorClear( ambientColor );
+               
+               /* generate diffuse lights */
+               RadFreeLights();
+               RadCreateDiffuseLights();
+               
+               /* setup light envelopes */
+               SetupEnvelopes( qfalse, fastbounce );
+               if( numLights == 0 )
+               {
+                       Sys_Printf( "No diffuse light to calculate, ending radiosity.\n" );
+                       break;
+               }
+               
+               /* add to lightgrid */
+               if( bouncegrid )
+               {
+                       gridEnvelopeCulled = 0;
+                       gridBoundsCulled = 0;
+                       
+                       Sys_Printf( "--- BounceGrid ---\n" );
+                       RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
+                       Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
+                       Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
+               }
+               
+               /* light up my world */
+               lightsPlaneCulled = 0;
+               lightsEnvelopeCulled = 0;
+               lightsBoundsCulled = 0;
+               lightsClusterCulled = 0;
+               
+               Sys_Printf( "--- IlluminateRawLightmap ---\n" );
+               RunThreadsOnIndividual( numRawLightmaps, qtrue, IlluminateRawLightmap );
+               Sys_Printf( "%9d luxels illuminated\n", numLuxelsIlluminated );
+               Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
+               
+               StitchSurfaceLightmaps();
+               
+               Sys_Printf( "--- IlluminateVertexes ---\n" );
+               RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, IlluminateVertexes );
+               Sys_Printf( "%9d vertexes illuminated\n", numVertsIlluminated );
+               
+               /* ydnar: emit statistics on light culling */
+               Sys_FPrintf( SYS_VRB, "%9d lights plane culled\n", lightsPlaneCulled );
+               Sys_FPrintf( SYS_VRB, "%9d lights envelope culled\n", lightsEnvelopeCulled );
+               Sys_FPrintf( SYS_VRB, "%9d lights bounds culled\n", lightsBoundsCulled );
+               Sys_FPrintf( SYS_VRB, "%9d lights cluster culled\n", lightsClusterCulled );
+               
+               /* interate */
+               bounce--;
+               b++;
+       }
+}
+
+
+
+/*
+LightMain()
+main routine for light processing
+*/
+
+int LightMain( int argc, char **argv )
+{
+       int                     i;
+       float           f;
+       char            mapSource[ 1024 ];
+       const char      *value;
+       
+       
+       /* note it */
+       Sys_Printf( "--- Light ---\n" );
+       
+       /* process commandline arguments */
+       for( i = 1; i < (argc - 1); i++ )
+       {
+               /* lightsource scaling */
+               if( !strcmp( argv[ i ], "-point" ) || !strcmp( argv[ i ], "-pointscale" ) )
+               {
+                       f = atof( argv[ i + 1 ] );
+                       pointScale *= f;
+                       Sys_Printf( "Point (entity) light scaled by %f to %f\n", f, pointScale );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-area" ) || !strcmp( argv[ i ], "-areascale" ) )
+               {
+                       f = atof( argv[ i + 1 ] );
+                       areaScale *= f;
+                       Sys_Printf( "Area (shader) light scaled by %f to %f\n", f, areaScale );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-sky" ) || !strcmp( argv[ i ], "-skyscale" ) )
+               {
+                       f = atof( argv[ i + 1 ] );
+                       skyScale *= f;
+                       Sys_Printf( "Sky/sun light scaled by %f to %f\n", f, skyScale );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-bouncescale" ) )
+               {
+                       f = atof( argv[ i + 1 ] );
+                       bounceScale *= f;
+                       Sys_Printf( "Bounce (radiosity) light scaled by %f to %f\n", f, bounceScale );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-scale" ) )
+               {
+                       f = atof( argv[ i + 1 ] );
+                       pointScale *= f;
+                       areaScale *= f;
+                       skyScale *= f;
+                       bounceScale *= f;
+                       Sys_Printf( "All light scaled by %f\n", f );
+                       i++;
+               }
+               
+               /* ydnar switches */
+               else if( !strcmp( argv[ i ], "-bounce" ) )
+               {
+                       bounce = atoi( argv[ i + 1 ] );
+                       if( bounce < 0 )
+                               bounce = 0;
+                       else if( bounce > 0 )
+                               Sys_Printf( "Radiosity enabled with %d bounce(s)\n", bounce );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-supersample" ) || !strcmp( argv[ i ], "-super" ) )
+               {
+                       superSample = atoi( argv[ i + 1 ] );
+                       if( superSample < 1 )
+                               superSample = 1;
+                       else if( superSample > 1 )
+                               Sys_Printf( "Ordered-grid supersampling enabled with %d sample(s) per lightmap texel\n", (superSample * superSample) );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-samples" ) )
+               {
+                       lightSamples = atoi( argv[ i + 1 ] );
+                       if( lightSamples < 1 )
+                               lightSamples = 1;
+                       else if( lightSamples > 1 )
+                               Sys_Printf( "Adaptive supersampling enabled with %d sample(s) per lightmap texel\n", lightSamples );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-filter" ) )
+               {
+                       filter = qtrue;
+                       Sys_Printf( "Lightmap filtering enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-shadeangle" ) )
+               {
+                       shadeAngleDegrees = atof( argv[ i + 1 ] );
+                       if( shadeAngleDegrees < 0.0f )
+                               shadeAngleDegrees = 0.0f;
+                       else if( shadeAngleDegrees > 0.0f )
+                       {
+                               shade = qtrue;
+                               Sys_Printf( "Phong shading enabled with a breaking angle of %f degrees\n", shadeAngleDegrees );
+                       }
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-thresh" ) )
+               {
+                       subdivideThreshold = atof( argv[ i + 1 ] );
+                       if( subdivideThreshold < 0 )
+                               subdivideThreshold = DEFAULT_SUBDIVIDE_THRESHOLD;
+                       else
+                               Sys_Printf( "Subdivision threshold set at %.3f\n", subdivideThreshold );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-approx" ) )
+               {
+                       approximateTolerance = atoi( argv[ i + 1 ] );
+                       if( approximateTolerance < 0 )
+                               approximateTolerance = 0;
+                       else if( approximateTolerance > 0 )
+                               Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
+                       i++;
+               }
+               
+               else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
+               {
+                       deluxemap = qtrue;
+                       Sys_Printf( "Generating deluxemaps for average light direction\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-external" ) )
+               {
+                       externalLightmaps = qtrue;
+                       Sys_Printf( "Storing all lightmaps externally\n" );
+               }
+
+               else if( !strcmp( argv[ i ], "-lightmapsize" ) )
+               {
+                       lmCustomSize = atoi( argv[ i + 1 ] );
+                       
+                       /* must be a power of 2 and greater than 2 */
+                       if( ((lmCustomSize - 1) & lmCustomSize) || lmCustomSize < 2 )
+                       {
+                               Sys_Printf( "WARNING: Lightmap size must be a power of 2, greater or equal to 2 pixels.\n" );
+                               lmCustomSize = LIGHTMAP_WIDTH;
+                       }
+                       i++;
+                       Sys_Printf( "Default lightmap size set to %d x %d pixels\n", lmCustomSize, lmCustomSize );
+                       
+                       /* enable external lightmaps */
+                       if( lmCustomSize != LIGHTMAP_WIDTH )
+                       {
+                               externalLightmaps = qtrue;
+                               Sys_Printf( "Storing all lightmaps externally\n" );
+                       }
+               }
+               
+               /* ydnar: add this to suppress warnings */
+               else if( !strcmp( argv[ i ],  "-custinfoparms") )
+               {
+                       Sys_Printf( "Custom info parms enabled\n" );
+                       useCustomInfoParms = qtrue;
+               }
+               
+               else if( !strcmp( argv[ i ], "-wolf" ) )
+               {
+                       /* -game should already be set */
+                       game->wolfLight = qtrue;
+                       Sys_Printf( "Enabling Wolf lighting model\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-sunonly" ) )
+               {
+                       sunOnly = qtrue;
+                       Sys_Printf( "Only computing sunlight\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-bounceonly" ) )
+               {
+                       bounceOnly = qtrue;
+                       Sys_Printf( "Storing bounced light (radiosity) only\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-nocollapse" ) )
+               {
+                       noCollapse = qtrue;
+                       Sys_Printf( "Identical lightmap collapsing disabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-shade" ) )
+               {
+                       shade = qtrue;
+                       Sys_Printf( "Phong shading enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-bouncegrid") )
+               {
+                       bouncegrid = qtrue;
+                       if( bounce > 0 )
+                               Sys_Printf( "Grid lighting with radiosity enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-smooth" ) )
+               {
+                       smooth = qtrue;
+                       lightSamples = EXTRA_SCALE;
+                       Sys_Printf( "The -smooth argument is deprecated, use \"-samples 2\" instead\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-fast" ) )
+               {
+                       fast = qtrue;
+                       fastgrid = qtrue;
+                       fastbounce = qtrue;
+                       Sys_Printf( "Fast mode enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-faster" ) )
+               {
+                       faster = qtrue;
+                       fast = qtrue;
+                       fastgrid = qtrue;
+                       fastbounce = qtrue;
+                       Sys_Printf( "Faster mode enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-fastgrid" ) )
+               {
+                       fastgrid = qtrue;
+                       Sys_Printf( "Fast grid lighting enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-fastbounce" ) )
+               {
+                       fastbounce = qtrue;
+                       Sys_Printf( "Fast bounce mode enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-cheap" ) )
+               {
+                       cheap = qtrue;
+                       cheapgrid = qtrue;
+                       Sys_Printf( "Cheap mode enabled\n" );
+               }
+
+               else if( !strcmp( argv[ i ], "-cheapgrid" ) )
+               {
+                       cheapgrid = qtrue;
+                       Sys_Printf( "Cheap grid mode enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-normalmap" ) )
+               {
+                       normalmap = qtrue;
+                       Sys_Printf( "Storing normal map instead of lightmap\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-trisoup" ) )
+               {
+                       trisoup = qtrue;
+                       Sys_Printf( "Converting brush faces to triangle soup\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-debug" ) )
+               {
+                       debug = qtrue;
+                       Sys_Printf( "Lightmap debugging enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-debugsurfaces" ) || !strcmp( argv[ i ], "-debugsurface" ) )
+               {
+                       debugSurfaces = qtrue;
+                       Sys_Printf( "Lightmap surface debugging enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-debugunused" ) )
+               {
+                       debugUnused = qtrue;
+                       Sys_Printf( "Unused luxel debugging enabled\n" );
+               }
+
+               else if( !strcmp( argv[ i ], "-debugaxis" ) )
+               {
+                       debugAxis = qtrue;
+                       Sys_Printf( "Lightmap axis debugging enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-debugcluster" ) )
+               {
+                       debugCluster = qtrue;
+                       Sys_Printf( "Luxel cluster debugging enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-debugorigin" ) )
+               {
+                       debugOrigin = qtrue;
+                       Sys_Printf( "Luxel origin debugging enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-debugdeluxe" ) )
+               {
+                       deluxemap = qtrue;
+                       debugDeluxemap = qtrue;
+                       Sys_Printf( "Deluxemap debugging enabled\n" );
+               }
+               
+               else if( !strcmp( argv[ i ], "-export" ) )
+               {
+                       exportLightmaps = qtrue;
+                       Sys_Printf( "Exporting lightmaps\n" );
+               }
+               
+               else if( !strcmp(argv[ i ], "-notrace" )) 
+               {
+                       noTrace = qtrue;
+                       Sys_Printf( "Shadow occlusion disabled\n" );
+               }
+               else if( !strcmp(argv[ i ], "-patchshadows" ) )
+               {
+                       patchShadows = qtrue;
+                       Sys_Printf( "Patch shadow casting enabled\n" );
+               }
+               else if( !strcmp( argv[ i ], "-extra" ) )
+               {
+                       extra = qtrue;
+                       superSample = EXTRA_SCALE;              /* ydnar */
+                       Sys_Printf( "The -extra argument is deprecated, use \"-super 2\" instead\n" );
+               }
+               else if( !strcmp( argv[ i ], "-extrawide" ) )
+               {
+                       extra = qtrue;
+                       extraWide = qtrue;
+                       superSample = EXTRAWIDE_SCALE;  /* ydnar */
+                       filter = qtrue;                                 /* ydnar */
+                       Sys_Printf( "The -extrawide argument is deprecated, use \"-filter [-super 2]\" instead\n");
+               }
+               else if( !strcmp( argv[ i ], "-samplesize" ) )
+               {
+                       sampleSize = atoi( argv[ i + 1 ] );
+                       if( sampleSize < 1 )
+                               sampleSize = 1;
+                       i++;
+                       Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
+               }
+               else if( !strcmp( argv[ i ], "-novertex" ) )
+               {
+                       noVertexLighting = qtrue;
+                       Sys_Printf( "Disabling vertex lighting\n" );
+               }
+               else if( !strcmp( argv[ i ], "-nogrid" ) )
+               {
+                       noGridLighting = qtrue;
+                       Sys_Printf( "Disabling grid lighting\n" );
+               }
+               else if( !strcmp( argv[ i ], "-border" ) )
+               {
+                       lightmapBorder = qtrue;
+                       Sys_Printf( "Adding debug border to lightmaps\n" );
+               }
+               else if( !strcmp( argv[ i ], "-nosurf" ) )
+               {
+                       noSurfaces = qtrue;
+                       Sys_Printf( "Not tracing against surfaces\n" );
+               }
+               else if( !strcmp( argv[ i ], "-dump" ) )
+               {
+                       dump = qtrue;
+                       Sys_Printf( "Dumping radiosity lights into numbered prefabs\n" );
+               }
+               else if( !strcmp( argv[ i ], "-lomem" ) )
+               {
+                       loMem = qtrue;
+                       Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
+               }
+               
+               else
+                       Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
+       }
+       
+       /* clean up map name */
+       strcpy( source, ExpandArg( argv[ i ] ) );
+       StripExtension( source );
+       DefaultExtension( source, ".bsp" );
+       strcpy( mapSource, ExpandArg( argv[ i ] ) );
+       StripExtension( mapSource );
+       DefaultExtension( mapSource, ".map" );
+       
+       /* ydnar: set default sample size */
+       SetDefaultSampleSize( sampleSize );
+       
+       /* ydnar: handle shaders */
+       BeginMapShaderFile( source );
+       LoadShaderInfo();
+       
+       /* note loading */
+       Sys_Printf( "Loading %s\n", source );
+       
+       /* ydnar: load surface file */
+       LoadSurfaceExtraFile( source );
+       
+       /* load bsp file */
+       LoadBSPFile( source );
+       
+       /* parse bsp entities */
+       ParseEntities();
+       
+       /* load map file */
+       value = ValueForKey( &entities[ 0 ], "_keepLights" );
+       if( value[ 0 ] != '1' )
+               LoadMapFile( mapSource, qtrue );
+       
+       /* set the entity/model origins and init yDrawVerts */
+       SetEntityOrigins();
+       
+       /* ydnar: set up optimization */
+       SetupBrushes();
+       SetupSurfaceLightmaps();
+       
+       /* initialize the surface facet tracing */
+       SetupTraceNodes();
+       
+       /* light the world */
+       LightWorld();
+       
+       /* ydnar: store off lightmaps */
+       StoreSurfaceLightmaps();
+       
+       /* write out the bsp */
+       UnparseEntities();
+       Sys_Printf( "Writing %s\n", source );
+       WriteBSPFile( source );
+       
+       /* ydnar: export lightmaps */
+       if( exportLightmaps && !externalLightmaps )
+               ExportLightmaps();
+       
+       /* return to sender */
+       return 0;
+}
+