Index: tools/quake3/q3map2/writebsp.c
===================================================================
--- tools/quake3/q3map2/writebsp.c	(revision 158)
+++ tools/quake3/q3map2/writebsp.c	(working copy)
@@ -136,7 +136,6 @@
 	bspLeaf_t		*leaf_p;
 	brush_t			*b;
 	drawSurfRef_t	*dsr;
-	int				i = 0;
 
 	
 	/* check limits */
Index: tools/quake3/q3map2/facebsp.c
===================================================================
--- tools/quake3/q3map2/facebsp.c	(revision 158)
+++ tools/quake3/q3map2/facebsp.c	(working copy)
@@ -180,7 +180,7 @@
 	
 
 	c = 0;
-	for( list; list != NULL; list = list->next )
+	for( ; list != NULL; list = list->next )
 		c++;
 	return c;
 }
Index: tools/quake3/q3map2/light_ydnar.c
===================================================================
--- tools/quake3/q3map2/light_ydnar.c	(revision 158)
+++ tools/quake3/q3map2/light_ydnar.c	(working copy)
@@ -49,6 +49,7 @@
 	int		i;
 	float	max, gamma;
 	vec3_t	sample;
+	float 	inv, dif;
 	
 	
 	/* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
@@ -72,16 +73,51 @@
 		/* gamma */
 		sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
 	}
+
+	if (lightmapExposure == 1)
+	{
+		/* clamp with color normalization */
+		max = sample[ 0 ];
+		if( sample[ 1 ] > max )
+			max = sample[ 1 ];
+		if( sample[ 2 ] > max )
+			max = sample[ 2 ];
+		if( max > 255.0f )
+			VectorScale( sample, (255.0f / max), sample );
+	}
+	else
+	{
+		if (lightmapExposure==0)
+		{
+			lightmapExposure=1.0f;
+		}
+		inv=1.f/lightmapExposure;
+		//Exposure
+    	
+		max = sample[ 0 ];
+		if( sample[ 1 ] > max )
+			max = sample[ 1 ];
+		if( sample[ 2 ] > max )
+			max = sample[ 2 ];  
+      
+		dif = (1-  exp(-max * inv) )  *  255;
+
+		if (max >0) 
+		{
+			dif = dif / max;
+		}
+		else
+		{
+			dif = 0;
+		}
+
+		for (i=0;i<3;i++)
+		{
+			sample[i]*=dif;
+		}
+	}
+
 	
-	/* clamp with color normalization */
-	max = sample[ 0 ];
-	if( sample[ 1 ] > max )
-		max = sample[ 1 ];
-	if( sample[ 2 ] > max )
-		max = sample[ 2 ];
-	if( max > 255.0f )
-		VectorScale( sample, (255.0f / max), sample );
-	
 	/* compensate for ingame overbrighting/bitshifting */
 	VectorScale( sample, (1.0f / lightmapCompensate), sample );
 	
@@ -384,7 +420,7 @@
 #define NUDGE			0.5f
 #define BOGUS_NUDGE		-99999.0f
 
-static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
+static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
 {
 	int				i, x, y, numClusters, *clusters, pointCluster, *cluster;
 	float			*luxel, *origin, *normal, d, lightmapSampleOffset;
@@ -392,6 +428,12 @@
 	vec3_t			pNormal;
 	vec3_t			vecs[ 3 ];
 	vec3_t			nudged;
+	vec3_t			cverts[ 3 ];
+	vec3_t			temp;
+	vec4_t			sideplane, hostplane;
+	vec3_t			origintwo;
+	int				j, next;
+	float			e;
 	float			*nudge;
 	static float	nudges[][ 2 ] =
 					{
@@ -485,6 +527,51 @@
 	/* non axial lightmap projection (explicit xyz) */
 	else
 		VectorCopy( dv->xyz, origin );
+
+	//////////////////////
+	//27's test to make sure samples stay within the triangle boundaries
+	//1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
+	//2) if it does, nudge it onto the correct side.
+
+	if (worldverts!=NULL)
+	{
+		for (j=0;j<3;j++)
+		{
+			VectorCopy(worldverts[j],cverts[j]);    
+		}
+		PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
+
+		for (j=0;j<3;j++)
+		{
+			for (i=0;i<3;i++)
+			{
+				//build plane using 2 edges and a normal
+				next=(i+1)%3;
+
+				VectorCopy(cverts[next],temp);
+				VectorAdd(temp,hostplane,temp);
+				PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
+
+				//planetest sample point  
+				e=DotProduct(origin,sideplane);
+				e=e-sideplane[3];
+				if (e>0)
+				{
+					//we're bad.
+					//VectorClear(origin);
+					//Move the sample point back inside triangle bounds
+					origin[0]-=sideplane[0]*(e+1);
+					origin[1]-=sideplane[1]*(e+1);
+					origin[2]-=sideplane[2]*(e+1);
+#ifdef DEBUG_27_1
+					VectorClear(origin);
+#endif 
+				}
+			}
+		}
+	}
+
+	////////////////////////
 	
 	/* planar surfaces have precalculated lightmap vectors for nudging */
 	if( lm->plane != NULL )
@@ -516,8 +603,13 @@
 	else
 		origin[ lm->axisNum ] += lightmapSampleOffset;
 	
+	VectorCopy(origin,origintwo);
+	origintwo[0]+=vecs[2][0];
+	origintwo[1]+=vecs[2][1];
+	origintwo[2]+=vecs[2][2];
+	
 	/* get cluster */
-	pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
+	pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
 	
 	/* another retarded hack, storing nudge count in luxel[ 1 ] */
 	luxel[ 1 ] = 0.0f;	
@@ -533,14 +625,14 @@
 			for( i = 0; i < 3; i++ )
 			{
 				/* set nudged point*/
-				nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
+				nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
 			}
 			nudge += 2;
 			
 			/* get pvs cluster */
 			pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
-			if( pointCluster >= 0 )	
-				VectorCopy( nudged, origin );
+			//if( pointCluster >= 0 )	
+   			//	VectorCopy( nudged, origin );
 			luxel[ 1 ] += 1.0f;
 		}
 	}
@@ -550,8 +642,8 @@
 	{
 		VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
 		pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
-		if( pointCluster >= 0 )
-			VectorCopy( nudged, origin );
+		//if( pointCluster >= 0 )
+		//	VectorCopy( nudged, origin );
 		luxel[ 1 ] += 1.0f;
 	}
 	
@@ -597,7 +689,7 @@
 than the distance between two luxels (thanks jc :)
 */
 
-static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
+static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
 {
 	bspDrawVert_t	mid, *dv2[ 3 ];
 	int				max;
@@ -645,7 +737,7 @@
 	
 	/* split the longest edge and map it */
 	LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
-	MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
+	MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
 	
 	/* push the point up a little bit to account for fp creep (fixme: revisit this) */
 	//%	VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
@@ -653,12 +745,12 @@
 	/* recurse to first triangle */
 	VectorCopy( dv, dv2 );
 	dv2[ max ] = &mid;
-	MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+	MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
 	
 	/* recurse to second triangle */
 	VectorCopy( dv, dv2 );
 	dv2[ (max + 1) % 3 ] = &mid;
-	MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+	MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
 }
 
 
@@ -674,6 +766,7 @@
 	int				i;
 	vec4_t			plane;
 	vec3_t			*stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
+	vec3_t			worldverts[ 3 ];
 	
 	
 	/* get plane if possible */
@@ -699,16 +792,20 @@
 		ttv = NULL;
 	}
 	
+	VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
+	VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
+	VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
+	
 	/* map the vertexes */
-	MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
-	MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
-	MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
+	MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
+	MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
+	MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
 	
 	/* 2002-11-20: prefer axial triangle edges */
 	if( mapNonAxial )
 	{
 		/* subdivide the triangle */
-		MapTriangle_r( lm, info, dv, plane, stv, ttv );
+		MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
 		return qtrue;
 	}
 	
@@ -730,7 +827,7 @@
 			dv2[ 2 ] = dv[ (i + 1) % 3 ];
 			
 			/* map the degenerate triangle */
-			MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+			MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
 		}
 	}
 	
@@ -792,8 +889,8 @@
 	LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
 	
 	/* map the vertexes */
-	MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
-	MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
+	MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
+	MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
 	
 	/* 0 and 2 */
 	if( max == 0 )
@@ -878,10 +975,10 @@
 	}
 	
 	/* map the vertexes */
-	MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
-	MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
-	MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
-	MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
+	MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
+	MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
+	MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
+	MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
 	
 	/* subdivide the quad */
 	MapQuad_r( lm, info, dv, plane, stv, ttv );
@@ -1173,7 +1270,7 @@
 					continue;
 				
 				/* map the fake vert */
-				MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
+				MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
 			}
 		}
 	}
@@ -1767,6 +1864,8 @@
 	float				tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
 	trace_t				trace;
 	float				stackLightLuxels[ STACK_LL_SIZE ];
+	vec3_t				flood;
+	float				*floodlight;
 	
 	
 	/* bail if this number exceeds the number of raw lightmaps */
@@ -1963,22 +2062,32 @@
 					deluxel = SUPER_DELUXEL( x, y );
 					origin = SUPER_ORIGIN( x, y );
 					normal = SUPER_NORMAL( x, y );
-					
-					/* set contribution count */
-					lightLuxel[ 3 ] = 1.0f;
-					
-					/* setup trace */
-					trace.cluster = *cluster;
-					VectorCopy( origin, trace.origin );
-					VectorCopy( normal, trace.normal );
-					
-					/* get light for this sample */
-					LightContributionToSample( &trace );
-					VectorCopy( trace.color, lightLuxel );
-					
-					/* add to count */
-					if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
+
+					////////// 27's temp hack for testing edge clipping ////
+					if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
+					{
+						lightLuxel[ 1 ] = 255;
+						lightLuxel[ 3 ] = 1.0f;
 						totalLighted++;
+					}
+					else
+					{
+						/* set contribution count */
+						lightLuxel[ 3 ] = 1.0f;
+						
+						/* setup trace */
+						trace.cluster = *cluster;
+						VectorCopy( origin, trace.origin );
+						VectorCopy( normal, trace.normal );
+						
+						/* get light for this sample */
+						LightContributionToSample( &trace );
+						VectorCopy( trace.color, lightLuxel );
+						
+						/* add to count */
+						if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
+							totalLighted++;
+					}
 					
 					/* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
 					if( deluxemap )
@@ -2223,6 +2332,78 @@
 	FreeTraceLights( &trace );
 	
 	/*	-----------------------------------------------------------------
+		floodlight pass
+		----------------------------------------------------------------- */
+
+	if( floodlighty )
+	{
+		/* walk lightmaps */
+		for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+		{
+			/* early out */
+			if( lm->superLuxels[ lightmapNum ] == NULL )
+				continue;
+			
+			/* apply floodlight to each luxel */
+			for( y = 0; y < lm->sh; y++ )
+			{
+				for( x = 0; x < lm->sw; x++ )
+				{
+					/* get cluster */
+					cluster	= SUPER_CLUSTER( x, y );
+					//%	if( *cluster < 0 )
+					//%		continue;
+					
+					/* get particulars */
+					luxel = SUPER_LUXEL( lightmapNum, x, y );
+					floodlight = SUPER_FLOODLIGHT( x, y );
+					
+					flood[0]=floodlightRGB[0]*floodlightIntensity;
+					flood[1]=floodlightRGB[1]*floodlightIntensity;
+					flood[2]=floodlightRGB[2]*floodlightIntensity;
+					             
+					/* scale light value */
+					VectorScale( flood, *floodlight, flood );
+					luxel[0]+=flood[0];
+					luxel[1]+=flood[1];
+					luxel[2]+=flood[2];
+					
+					if (luxel[3]==0) luxel[3]=1;
+				}
+			}
+		}
+	}
+
+	if (debugnormals)
+	{
+		for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+		{
+			/* early out */
+			if( lm->superLuxels[ lightmapNum ] == NULL )
+				continue;
+			
+			for( y = 0; y < lm->sh; y++ )
+			{
+				for( x = 0; x < lm->sw; x++ )
+				{
+					/* get cluster */
+					cluster	= SUPER_CLUSTER( x, y );
+					//%	if( *cluster < 0 )
+					//%		continue;
+					
+					/* get particulars */
+					luxel = SUPER_LUXEL( lightmapNum, x, y );
+					normal = SUPER_NORMAL (  x, y );
+               
+					luxel[0]=(normal[0]*127)+127;
+					luxel[1]=(normal[1]*127)+127;
+					luxel[2]=(normal[2]*127)+127;
+				}
+			}
+		}
+	}
+	
+	/*	-----------------------------------------------------------------
 		dirt pass
 		----------------------------------------------------------------- */
 	
@@ -3112,7 +3293,7 @@
 	int			i, x, y, z, x1, y1, z1;
 	light_t		*light, *light2, **owner;
 	bspLeaf_t	*leaf;
-	vec3_t		origin, dir, mins, maxs, nullVector = { 0, 0, 0 };
+	vec3_t		origin, dir, mins, maxs;
 	float		radius, intensity;
 	light_t		*buckets[ 256 ];
 	
@@ -3587,7 +3768,320 @@
 	CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
 }
 
+/////////////////////////////////////////////////////////////
 
+#define FLOODLIGHT_CONE_ANGLE			88	/* degrees */
+#define FLOODLIGHT_NUM_ANGLE_STEPS		16
+#define FLOODLIGHT_NUM_ELEVATION_STEPS	4
+#define FLOODLIGHT_NUM_VECTORS			(FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
 
+static vec3_t	floodVectors[ FLOODLIGHT_NUM_VECTORS ];
+static int		numFloodVectors = 0;
 
+void SetupFloodLight( void )
+{
+	int		i, j;
+	float	angle, elevation, angleStep, elevationStep;
+	const char	*value;
+	double v1,v2,v3,v4,v5;
+	
+	/* note it */
+	Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
+	
+	/* calculate angular steps */
+	angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
+	elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
+	
+	/* iterate angle */
+	angle = 0.0f;
+	for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
+	{
+		/* iterate elevation */
+		for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
+		{
+			floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
+			floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
+			floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
+			numFloodVectors++;
+		}
+	}
+	
+	/* emit some statistics */
+	Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
 
+      /* floodlight */
+	value = ValueForKey( &entities[ 0 ], "_floodlight" );
+	
+	if( value[ 0 ] != '\0' )
+	{
+		v1=v2=v3=0;
+		v4=floodlightDistance;
+		v5=floodlightIntensity;
+		
+		sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
+		
+		floodlightRGB[0]=v1;
+		floodlightRGB[1]=v2;
+		floodlightRGB[2]=v3;
+		
+		if (VectorLength(floodlightRGB)==0)
+		{
+			VectorSet(floodlightRGB,240,240,255);
+		}
+		
+		if (v4<1) v4=1024;
+		if (v5<1) v5=128;
+		
+		floodlightDistance=v4;
+		floodlightIntensity=v5;
+    
+		floodlighty = qtrue;
+		Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
+	}
+	else
+	{
+		VectorSet(floodlightRGB,240,240,255);
+		//floodlighty = qtrue;
+		//Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
+	}
+	VectorNormalize(floodlightRGB,floodlightRGB);
+}
+
+//27 - lighttracer style ambient occlusion light hack.
+//Kudos to the dirtmapping author for most of this source.
+void FloodLightRawLightmap( int rawLightmapNum )
+{
+	int					i, x, y, sx, sy, *cluster;
+	float				*origin, *normal, *floodlight, *floodlight2, average, samples;
+	rawLightmap_t		*lm;
+	surfaceInfo_t		*info;
+	trace_t				trace;
+	
+	/* bail if this number exceeds the number of raw lightmaps */
+	if( rawLightmapNum >= numRawLightmaps )
+		return;
+	
+	/* get lightmap */
+	lm = &rawLightmaps[ rawLightmapNum ];
+	
+	memset(&trace,0,sizeof(trace_t));
+	/* setup trace */
+	trace.testOcclusion = qtrue;
+	trace.forceSunlight = qfalse;
+	trace.twoSided = qtrue;
+	trace.recvShadows = lm->recvShadows;
+	trace.numSurfaces = lm->numLightSurfaces;
+	trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
+	trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+	trace.testAll = qfalse;
+	trace.distance = 1024;
+	
+	/* twosided lighting (may or may not be a good idea for lightmapped stuff) */
+	//trace.twoSided = qfalse;
+	for( i = 0; i < trace.numSurfaces; i++ )
+	{
+		/* get surface */
+		info = &surfaceInfos[ trace.surfaces[ i ] ];
+		
+		/* check twosidedness */
+		if( info->si->twoSided )
+		{
+			trace.twoSided = qtrue;
+			break;
+		}
+	}
+	
+	/* gather dirt */
+	for( y = 0; y < lm->sh; y++ )
+	{
+		for( x = 0; x < lm->sw; x++ )
+		{
+			/* get luxel */
+			cluster = SUPER_CLUSTER( x, y );
+			origin = SUPER_ORIGIN( x, y );
+			normal = SUPER_NORMAL( x, y );
+			floodlight = SUPER_FLOODLIGHT( x, y );
+			
+			/* set default dirt */
+			*floodlight = 0.0f;
+			
+			/* only look at mapped luxels */
+			if( *cluster < 0 )
+				continue;
+			
+			/* copy to trace */
+			trace.cluster = *cluster;
+			VectorCopy( origin, trace.origin );
+			VectorCopy( normal, trace.normal );
+         
+
+		
+			/* get dirt */
+			*floodlight = FloodLightForSample( &trace );
+		}
+	}
+	
+	/* testing no filtering */
+	return;
+	
+	/* filter "dirt" */
+	for( y = 0; y < lm->sh; y++ )
+	{
+		for( x = 0; x < lm->sw; x++ )
+		{
+			/* get luxel */
+			cluster = SUPER_CLUSTER( x, y );
+			floodlight = SUPER_FLOODLIGHT( x, y );
+			
+			/* filter dirt by adjacency to unmapped luxels */
+			average = *floodlight;
+			samples = 1.0f;
+			for( sy = (y - 1); sy <= (y + 1); sy++ )
+			{
+				if( sy < 0 || sy >= lm->sh )
+					continue;
+				
+				for( sx = (x - 1); sx <= (x + 1); sx++ )
+				{
+					if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
+						continue;
+					
+					/* get neighboring luxel */
+					cluster = SUPER_CLUSTER( sx, sy );
+					floodlight2 = SUPER_FLOODLIGHT( sx, sy );
+					if( *cluster < 0 || *floodlight2 <= 0.0f )
+						continue;
+					
+					/* add it */
+					average += *floodlight2;
+					samples += 1.0f;
+				}
+				
+				/* bail */
+				if( samples <= 0.0f )
+					break;
+			}
+			
+			/* bail */
+			if( samples <= 0.0f )
+				continue;
+			
+			/* scale dirt */
+			*floodlight = average / samples;
+		}
+	}
+}
+
+/*
+FloodLightForSample()
+calculates floodlight value for a given sample
+once again, kudos to the dirtmapping coder
+*/
+float FloodLightForSample( trace_t *trace )
+{
+	int		i;
+	float 	d;
+	float 	contribution;
+	int 	sub = 0;
+	float	gatherLight, outLight;
+	vec3_t	normal, worldUp, myUp, myRt, direction, displacement;
+	float 	dd;
+	int 	vecs = 0;
+ 
+	gatherLight=0;
+	/* dummy check */
+	//if( !dirty )
+	//	return 1.0f;
+	if( trace == NULL || trace->cluster < 0 )
+		return 0.0f;
+	
+
+	/* setup */
+	dd = floodlightDistance;
+	VectorCopy( trace->normal, normal );
+	
+	/* check if the normal is aligned to the world-up */
+	if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
+	{
+		if( normal[ 2 ] == 1.0f )		
+		{
+			VectorSet( myRt, 1.0f, 0.0f, 0.0f );
+			VectorSet( myUp, 0.0f, 1.0f, 0.0f );
+		}
+		else if( normal[ 2 ] == -1.0f )
+		{
+			VectorSet( myRt, -1.0f, 0.0f, 0.0f );
+			VectorSet( myUp,  0.0f, 1.0f, 0.0f );
+		}
+	}
+	else
+	{
+		VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
+		CrossProduct( normal, worldUp, myRt );
+		VectorNormalize( myRt, myRt );
+		CrossProduct( myRt, normal, myUp );
+		VectorNormalize( myUp, myUp );
+	}
+
+	/* iterate through ordered vectors */
+	for( i = 0; i < numFloodVectors; i++ )
+	{
+		if (floodlight_lowquality==qtrue)
+        {
+			if (rand()%10 != 0 ) continue;
+		}
+
+		vecs++;
+         
+		/* transform vector into tangent space */
+		direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
+		direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
+		direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
+
+		/* set endpoint */
+		VectorMA( trace->origin, dd, direction, trace->end );
+
+		//VectorMA( trace->origin, 1, direction, trace->origin );
+			
+		SetupTrace( trace );
+		/* trace */
+	  	TraceLine( trace );
+		contribution=1;
+
+		if (trace->compileFlags & C_SKY )
+		{
+			contribution=1.0f;
+		}
+		else if ( trace->opaque )
+		{
+			VectorSubtract( trace->hit, trace->origin, displacement );
+			d=VectorLength( displacement );
+
+			// d=trace->distance;            
+			//if (d>256) gatherDirt+=1;
+			contribution=d/dd;
+			if (contribution>1) contribution=1.0f; 
+             
+			//gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
+		}
+         
+		gatherLight+=contribution;
+	}
+   
+	/* early out */
+	if( gatherLight <= 0.0f )
+		return 0.0f;
+   	
+	sub=vecs;
+
+	if (sub<1) sub=1;
+	gatherLight/=(sub);
+
+	outLight=gatherLight;
+	if( outLight > 1.0f )
+		outLight = 1.0f;
+	
+	/* return to sender */
+	return outLight;
+}
+
Index: tools/quake3/q3map2/light.c
===================================================================
--- tools/quake3/q3map2/light.c	(revision 158)
+++ tools/quake3/q3map2/light.c	(working copy)
@@ -1378,6 +1378,56 @@
 			break;
 	}
 	
+	/////// Floodlighting for point //////////////////
+	//do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
+	if (floodlighty)
+	{
+		int q;
+		float addSize,f;
+		vec3_t col,dir;
+		col[0]=col[1]=col[2]=floodlightIntensity;
+		dir[0]=dir[1]=0;
+		dir[2]=1;
+      
+		trace.testOcclusion = qtrue;
+		trace.forceSunlight = qfalse;
+		trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+		trace.testAll = qtrue;     
+      
+		for (q=0;q<2;q++)
+		{
+			if (q==0) //upper hemisphere
+			{
+				trace.normal[0]=0;
+				trace.normal[1]=0;
+				trace.normal[2]=1;
+			}
+			else //lower hemisphere
+			{
+				trace.normal[0]=0;
+				trace.normal[1]=0;
+				trace.normal[2]=-1;
+			}
+
+			f = FloodLightForSample(&trace);
+
+			contributions[ numCon ].color[0]=col[0]*f;
+			contributions[ numCon ].color[1]=col[1]*f;
+			contributions[ numCon ].color[2]=col[2]*f;
+
+			contributions[ numCon ].dir[0]=dir[0];
+			contributions[ numCon ].dir[1]=dir[1];
+			contributions[ numCon ].dir[2]=dir[2];
+
+			contributions[ numCon ].style = 0;
+			numCon++;		
+			/* push average direction around */
+			addSize = VectorLength( col );
+			VectorMA( gp->dir, addSize, dir, gp->dir );
+		}
+	}
+	/////////////////////
+
 	/* normalize to get primary light direction */
 	VectorNormalize( gp->dir, gp->dir );
 	
@@ -1420,6 +1470,9 @@
 		
 		/* ambient light will be at 1/4 the value of directed light */
 		/* (ydnar: nuke this in favor of more dramatic lighting?) */
+		/* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
+//		d = 0.25f;
+		/* (Hobbes: always setting it to .25 is hardly any better) */
 		d = 0.25f * (1.0f - d);
 		VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
 	}
@@ -1661,6 +1714,12 @@
 		RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
 	}
 	
+	/* floodlight them up */
+	if( floodlighty )
+	{
+		Sys_Printf( "--- FloodlightRawLightmap ---\n" );
+		RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
+	}
 
 	/* ydnar: set up light envelopes */
 	SetupEnvelopes( qfalse, fast );
@@ -1836,6 +1895,14 @@
 			i++;
 		}
 		
+		else if( !strcmp( argv[ i ], "-exposure" ) )
+		{
+			f = atof( argv[ i + 1 ] );
+			lightmapExposure = f;
+			Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
+			i++;
+		}
+		
 		else if( !strcmp( argv[ i ], "-compensate" ) )
 		{
 			f = atof( argv[ i + 1 ] );
@@ -2191,6 +2258,21 @@
 			cpmaHack = qtrue;
 			Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
 		}
+		else if( !strcmp( argv[ i ], "-floodlight" ) )
+		{
+			floodlighty = qtrue;
+			Sys_Printf( "FloodLighting enabled\n" );
+		}
+		else if( !strcmp( argv[ i ], "-debugnormals" ) )
+		{
+			debugnormals = qtrue;
+			Sys_Printf( "DebugNormals enabled\n" );
+		}
+		else if( !strcmp( argv[ i ], "-lowquality" ) )
+		{
+			floodlight_lowquality = qtrue;
+			Sys_Printf( "Low Quality FloodLighting enabled\n" );
+		}
 		
 		/* r7: dirtmapping */
 		else if( !strcmp( argv[ i ], "-dirty" ) )
@@ -2279,6 +2361,7 @@
 	/* ydnar: set up optimization */
 	SetupBrushes();
 	SetupDirt();
+	SetupFloodLight();
 	SetupSurfaceLightmaps();
 	
 	/* initialize the surface facet tracing */
Index: tools/quake3/q3map2/game_etut.h
===================================================================
--- tools/quake3/q3map2/game_etut.h	(revision 158)
+++ tools/quake3/q3map2/game_etut.h	(working copy)
@@ -148,6 +148,7 @@
 	qfalse,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	2.2f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	47,					/* bsp file version */
Index: tools/quake3/q3map2/brush.c
===================================================================
--- tools/quake3/q3map2/brush.c	(revision 158)
+++ tools/quake3/q3map2/brush.c	(working copy)
@@ -78,7 +78,7 @@
 	
 	
 	/* count brushes */
-	for( brushes; brushes != NULL; brushes = brushes->next )
+	for( ; brushes != NULL; brushes = brushes->next )
 		c++;
 	return c;
 }
@@ -122,7 +122,7 @@
 	
 	
 	/* error check */
-	if( *((int*) b) == 0xFEFEFEFE )
+	if( *((unsigned int*) b) == 0xFEFEFEFE )
 	{
 		Sys_FPrintf( SYS_VRB, "WARNING: Attempt to free an already freed brush!\n" );
 		return;
@@ -135,7 +135,7 @@
 	
 	/* ydnar: overwrite it */
 	memset( b, 0xFE, (int) &(((brush_t*) 0)->sides[ b->numsides ]) );
-	*((int*) b) = 0xFEFEFEFE;
+	*((unsigned int*) b) = 0xFEFEFEFE;
 	
 	/* free it */
 	free( b );
@@ -156,7 +156,7 @@
 	
 	
 	/* walk brush list */
-	for( brushes; brushes != NULL; brushes = next )
+	for( ; brushes != NULL; brushes = next )
 	{
 		next = brushes->next;
 		FreeBrush( brushes );
Index: tools/quake3/q3map2/game_jk2.h
===================================================================
--- tools/quake3/q3map2/game_jk2.h	(revision 158)
+++ tools/quake3/q3map2/game_jk2.h	(working copy)
@@ -64,6 +64,7 @@
 	qfalse,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"RBSP",				/* bsp file prefix */
 	1,					/* bsp file version */
Index: tools/quake3/q3map2/lightmaps_ydnar.c
===================================================================
--- tools/quake3/q3map2/lightmaps_ydnar.c	(revision 158)
+++ tools/quake3/q3map2/lightmaps_ydnar.c	(working copy)
@@ -414,6 +414,12 @@
 		lm->superNormals = safe_malloc( size );
 	memset( lm->superNormals, 0, size );
 	
+ 	/* allocate floodlight map storage */
+	size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
+	if( lm->superFloodLight == NULL )
+		lm->superFloodLight = safe_malloc( size );
+	memset( lm->superFloodLight, 0, size );
+	
 	/* allocate cluster map storage */
 	size = lm->sw * lm->sh * sizeof( int );
 	if( lm->superClusters == NULL )
Index: tools/quake3/q3map2/game_ja.h
===================================================================
--- tools/quake3/q3map2/game_ja.h	(revision 158)
+++ tools/quake3/q3map2/game_ja.h	(working copy)
@@ -67,6 +67,7 @@
 	qfalse,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"RBSP",				/* bsp file prefix */
 	1,					/* bsp file version */
Index: tools/quake3/q3map2/game_tremulous.h
===================================================================
--- tools/quake3/q3map2/game_tremulous.h	(revision 158)
+++ tools/quake3/q3map2/game_tremulous.h	(working copy)
@@ -70,6 +70,7 @@
 	qfalse,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	46,					/* bsp file version */
Index: tools/quake3/q3map2/game_wolfet.h
===================================================================
--- tools/quake3/q3map2/game_wolfet.h	(revision 158)
+++ tools/quake3/q3map2/game_wolfet.h	(working copy)
@@ -66,6 +66,7 @@
 	qtrue,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	47,					/* bsp file version */
Index: tools/quake3/q3map2/model.c
===================================================================
--- tools/quake3/q3map2/model.c	(revision 158)
+++ tools/quake3/q3map2/model.c	(working copy)
@@ -266,7 +266,7 @@
 			continue;
 		
 		/* fix the surface's normals */
-		PicoFixSurfaceNormals( surface );
+		//PicoFixSurfaceNormals( surface );
 		
 		/* allocate a surface (ydnar: gs mods) */
 		ds = AllocDrawSurface( SURFACE_TRIANGLES );
@@ -521,7 +521,15 @@
 						else
 							free( buildBrush );
 					}
+					else
+					{
+						Sys_Printf( "WARNING: Model %s unable to generate brush - Case 1.\n", name );  
+					}
 				}
+				else
+				{
+					Sys_Printf( "WARNING: Model %s unable to generate brush - Case 2.\n", name );  
+				}  
 			}
 		}
 	}
Index: tools/quake3/q3map2/light_bounce.c
===================================================================
--- tools/quake3/q3map2/light_bounce.c	(revision 158)
+++ tools/quake3/q3map2/light_bounce.c	(working copy)
@@ -510,7 +510,7 @@
 			break;
 		
 		case MST_TRIANGLE_SOUP:
-			numTriangleDiffuseLights;
+			numTriangleDiffuseLights++;
 			break;
 		
 		case MST_PATCH:
Index: tools/quake3/q3map2/game_wolf.h
===================================================================
--- tools/quake3/q3map2/game_wolf.h	(revision 158)
+++ tools/quake3/q3map2/game_wolf.h	(working copy)
@@ -129,6 +129,7 @@
 	qtrue,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	47,					/* bsp file version */
Index: tools/quake3/q3map2/game_sof2.h
===================================================================
--- tools/quake3/q3map2/game_sof2.h	(revision 158)
+++ tools/quake3/q3map2/game_sof2.h	(working copy)
@@ -139,6 +139,7 @@
 	qfalse,					/* wolf lighting model? */
 	128,					/* lightmap width/height */
 	1.0f,					/* lightmap gamma */
+	1.0f,					/* lightmap exposure */
 	1.0f,					/* lightmap compensate */
 	"RBSP",					/* bsp file prefix */
 	1,						/* bsp file version */
Index: tools/quake3/q3map2/q3map2.h
===================================================================
--- tools/quake3/q3map2/q3map2.h	(revision 158)
+++ tools/quake3/q3map2/q3map2.h	(working copy)
@@ -35,8 +35,8 @@
 
 
 /* version */
-#define Q3MAP_VERSION	"2.5.17"
-#define Q3MAP_MOTD		"Last one turns the lights off"
+#define Q3MAP_VERSION	"2.5.17 base - FS_20g"
+#define Q3MAP_MOTD		"Sorry, it doesn't match my furniture."
 
 
 
@@ -267,6 +267,7 @@
 #define SUPER_NORMAL_SIZE		4
 #define SUPER_DELUXEL_SIZE		3
 #define BSP_DELUXEL_SIZE		3
+#define SUPER_FLOODLIGHT_SIZE	1
 
 #define VERTEX_LUXEL( s, v )	(vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
 #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
@@ -279,6 +280,7 @@
 #define SUPER_ORIGIN( x, y )	(lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
 #define SUPER_NORMAL( x, y )	(lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
 #define SUPER_DIRT( x, y )		(lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3)	/* stash dirtyness in normal[ 3 ] */
+#define SUPER_FLOODLIGHT( x, y )	(lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )	
 
 
 
@@ -543,6 +545,7 @@
 	qboolean			wolfLight;						/* when true, lights work like wolf q3map  */
 	int					lightmapSize;					/* bsp lightmap width/height */
 	float				lightmapGamma;					/* default lightmap gamma */
+	float				lightmapExposure;				/* default lightmap exposure */
 	float				lightmapCompensate;				/* default lightmap compensate value */
 	char				*bspIdent;						/* 4-letter bsp file prefix */
 	int					bspVersion;						/* bsp version to use */
@@ -1392,6 +1395,7 @@
 	
 	float					*superDeluxels;	/* average light direction */
 	float					*bspDeluxels;
+	float					*superFloodLight; 
 }
 rawLightmap_t;
 
@@ -1704,6 +1708,10 @@
 float						DirtForSample( trace_t *trace );
 void						DirtyRawLightmap( int num );
 
+void						SetupFloodLight();
+float						FloodLightForSample( trace_t *trace );
+void						FloodLightRawLightmap( int num );
+
 void						IlluminateRawLightmap( int num );
 void						IlluminateVertexes( int num );
 
@@ -2098,6 +2106,13 @@
 Q_EXTERN float				dirtScale Q_ASSIGN( 1.0f );
 Q_EXTERN float				dirtGain Q_ASSIGN( 1.0f );
 
+Q_EXTERN qboolean			debugnormals Q_ASSIGN( qfalse );
+Q_EXTERN qboolean			floodlighty Q_ASSIGN( qfalse );
+Q_EXTERN qboolean			floodlight_lowquality Q_ASSIGN( qfalse );
+Q_EXTERN vec3_t				floodlightRGB;
+Q_EXTERN float				floodlightIntensity Q_ASSIGN( 512 );
+Q_EXTERN float				floodlightDistance Q_ASSIGN( 1024 );
+
 Q_EXTERN qboolean			dump Q_ASSIGN( qfalse );
 Q_EXTERN qboolean			debug Q_ASSIGN( qfalse );
 Q_EXTERN qboolean			debugUnused Q_ASSIGN( qfalse );
@@ -2117,6 +2132,7 @@
 
 /* ydnar: lightmap gamma/compensation */
 Q_EXTERN float				lightmapGamma Q_ASSIGN( 1.0f );
+Q_EXTERN float				lightmapExposure Q_ASSIGN( 1.0f );
 Q_EXTERN float				lightmapCompensate Q_ASSIGN( 1.0f );
 
 /* ydnar: for runtime tweaking of falloff tolerance */
Index: tools/quake3/q3map2/path_init.c
===================================================================
--- tools/quake3/q3map2/path_init.c	(revision 158)
+++ tools/quake3/q3map2/path_init.c	(working copy)
@@ -383,7 +383,7 @@
 	/* remove processed arguments */
 	for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )
 	{
-		for( j; j < *argc && argv[ j ] == NULL; j++ );
+		for( ; j < *argc && argv[ j ] == NULL; j++ );
 		argv[ i ] = argv[ j ];
 		if( argv[ i ] != NULL )
 			k++;
Index: tools/quake3/q3map2/game_qfusion.h
===================================================================
--- tools/quake3/q3map2/game_qfusion.h	(revision 158)
+++ tools/quake3/q3map2/game_qfusion.h	(working copy)
@@ -115,6 +115,7 @@
 	qfalse,				/* wolf lighting model? */
 	512,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"FBSP",				/* bsp file prefix */
 	1,					/* bsp file version */
Index: tools/quake3/q3map2/game_tenebrae.h
===================================================================
--- tools/quake3/q3map2/game_tenebrae.h	(revision 158)
+++ tools/quake3/q3map2/game_tenebrae.h	(working copy)
@@ -112,6 +112,7 @@
 	qfalse,				/* wolf lighting model? */
 	512,				/* lightmap width/height */
 	2.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	46,					/* bsp file version */
Index: tools/quake3/q3map2/q3map2.vcproj
===================================================================
--- tools/quake3/q3map2/q3map2.vcproj	(revision 158)
+++ tools/quake3/q3map2/q3map2.vcproj	(working copy)
@@ -180,7 +180,7 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386"
 				AdditionalDependencies="glib-2.0.lib wsock32.lib libxml2.lib libpng.lib libmhash.lib"
-				OutputFile=".\Release/q3map2.exe"
+				OutputFile=".\Release/q3map2_fs_20g.exe"
 				LinkIncremental="1"
 				SuppressStartupBanner="true"
 				AdditionalLibraryDirectories="&quot;..\..\..\..\mhash-0.9\win32\libmhash\Release&quot;;&quot;..\..\..\..\libxml2-2.6\lib&quot;;&quot;..\..\..\..\gtk2-2.10\lib&quot;"
Index: tools/quake3/q3map2/game_quake3.h
===================================================================
--- tools/quake3/q3map2/game_quake3.h	(revision 158)
+++ tools/quake3/q3map2/game_quake3.h	(working copy)
@@ -112,6 +112,7 @@
 	qfalse,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	46,					/* bsp file version */
Index: tools/quake3/q3map2/game_ef.h
===================================================================
--- tools/quake3/q3map2/game_ef.h	(revision 158)
+++ tools/quake3/q3map2/game_ef.h	(working copy)
@@ -113,6 +113,7 @@
 	qfalse,				/* wolf lighting model? */
 	128,				/* lightmap width/height */
 	1.0f,				/* lightmap gamma */
+	1.0f,				/* lightmap exposure */
 	1.0f,				/* lightmap compensate */
 	"IBSP",				/* bsp file prefix */
 	46,					/* bsp file version */
Index: tools/quake3/q3map2/surface.c
===================================================================
--- tools/quake3/q3map2/surface.c	(revision 158)
+++ tools/quake3/q3map2/surface.c	(working copy)
@@ -304,7 +304,7 @@
 		out = &mapDrawSurfs[ i ];
 		
 		/* walk the surface list again until a proper surface is found */
-		for( j; j < numMapDrawSurfs; j++ )
+		for( ; j < numMapDrawSurfs; j++ )
 		{
 			/* get in surface */
 			in = &mapDrawSurfs[ j ];
@@ -484,7 +484,7 @@
 	
 	
 	/* walk the list of surfaces */
-	for( numSurfs; numSurfs > 0; numSurfs--, ds++ )
+	for( ; numSurfs > 0; numSurfs--, ds++ )
 	{
 		/* ignore bogus (or flare) surfaces */
 		if( ds->type == SURFACE_BAD || ds->numVerts <= 0 )
Index: tools/quake3/q3map2/shaders.c
===================================================================
--- tools/quake3/q3map2/shaders.c	(revision 158)
+++ tools/quake3/q3map2/shaders.c	(working copy)
@@ -793,8 +793,14 @@
 	}
 	
 	if( VectorLength( si->color ) <= 0.0f )
+	{
 		ColorNormalize( color, si->color );
-	VectorScale( color, (1.0f / count), si->averageColor );
+		VectorScale( color, (1.0f / count), si->averageColor );
+	}
+	else
+	{
+		VectorCopy( si->color, si->averageColor );
+	}
 }
 
 
@@ -1896,12 +1902,14 @@
 					si->styleMarker = 2;
 				
 				/* ydnar: default to searching for q3map_<surfaceparm> */
-				else
+#if 0
+ 				else
 				{
-					//%	Sys_FPrintf( SYS_VRB, "Attempting to match %s with a known surfaceparm\n", token );
+					Sys_FPrintf( SYS_VRB, "Attempting to match %s with a known surfaceparm\n", token );
 					if( ApplySurfaceParm( &token[ 6 ], &si->contentFlags, &si->surfaceFlags, &si->compileFlags ) == qfalse )
-						;//%	Sys_Printf( "WARNING: Unknown q3map_* directive \"%s\"\n", token );
+						Sys_Printf( "WARNING: Unknown q3map_* directive \"%s\"\n", token );
 				}
+#endif
 			}
 			
 			
Index: tools/quake3/q3map2/mesh.c
===================================================================
--- tools/quake3/q3map2/mesh.c	(revision 158)
+++ tools/quake3/q3map2/mesh.c	(working copy)
@@ -563,7 +563,7 @@
 	}
 	
 	/* keep chopping */
-	for( iterations; iterations > 0; iterations-- )
+	for( ; iterations > 0; iterations-- )
 	{
 		/* horizontal subdivisions */
 		for( j = 0; j + 2 < out.width; j += 4 )
Index: libs/picomodel/pm_ase.c
===================================================================
--- libs/picomodel/pm_ase.c	(revision 158)
+++ libs/picomodel/pm_ase.c	(working copy)
@@ -32,6 +32,7 @@
 
 ----------------------------------------------------------------------------- */
 
+void Sys_Printf (const char *format, ...);
 
 /* marker */
 #define PM_ASE_C
@@ -253,7 +254,6 @@
 struct aseVertex_s
 {
 	picoVec3_t xyz;
-	picoVec3_t normal;
 	picoIndex_t id;
 };
 
@@ -276,6 +276,8 @@
 	picoIndex_t smoothingGroup;
 	picoIndex_t materialId;
 	picoIndex_t subMaterialId;
+   picoVec3_t  facenormal;
+   picoVec3_t  vertexnormal[3];
 };
 typedef aseFace_t* aseFacesIter_t;
 
@@ -455,33 +457,157 @@
 
 #endif
 
+static int VectorCompareExtn( picoVec3_t n1, picoVec3_t n2, float epsilon )
+{
+	int		i;
+	
+	
+	/* test */
+	for( i= 0; i < 3; i++ )
+		if( fabs( n1[ i ] - n2[ i ]) > epsilon )
+			return -1;
+	return 1;
+}
+
+#define CrossProductTemp(a,b,c)		((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0])
+
 static void _ase_submit_triangles( picoModel_t* model , aseMaterial_t* materials , aseVertex_t* vertices, aseTexCoord_t* texcoords, aseColor_t* colors, aseFace_t* faces, int numFaces )
 {
-	aseFacesIter_t i = faces, end = faces + numFaces;
-	for(; i != end; ++i)
+   
+   picoVec3_t accum;
+   int index;
+   int counter;
+   aseFacesIter_t i = faces, end = faces + numFaces;
+   counter=0;
+
+   //rebuild normals
+   for(i=faces; i != end; ++i)
+   {
+    
+      //&(*i).facenormal
+	   //vec3_t v1, v2;
+	   //VectorSubtract(va, vb, v1);
+	   //VectorSubtract(vc, vb, v2);
+      //CrossProduct(v1, v2, out);
+      
+      picoVec3_t a,b,c;
+      picoVec3_t v1,v2,v3;
+      int j;
+      counter++;
+      for (j=0;j<3;j++)
+      {
+         a[j]    =  vertices[(*i).indices[0]].xyz[j];
+         b[j]    =  vertices[(*i).indices[1]].xyz[j];
+         c[j]    =  vertices[(*i).indices[2]].xyz[j];
+      }
+      for (j=0;j<3;j++)
+      {
+         v1[j]=a[j]-b[j];
+         v2[j]=c[j]-b[j];
+      }
+      
+      CrossProductTemp(v1,v2,v3);
+      _pico_normalize_vec(v3);
+      (*i).facenormal[0]=v3[0];
+      (*i).facenormal[1]=v3[1];
+      (*i).facenormal[2]=v3[2];
+      
+      
+   }
+   
+   
+   //if (counter>0) Sys_Printf( "Rebuilding %d Normals\n", counter * 3 );
+   for(i=faces; i != end; ++i)
 	{
-		/* look up the shader for the material/submaterial pair */
+      /* look up the shader for the material/submaterial pair */
 		aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId );
-		if( subMtl == NULL )
+
+      if( subMtl == NULL )
 		{
 			return;
 		}
 
 		{
 			picoVec3_t* xyz[3];
+         picoVec3_t *a[3];
 			picoVec3_t* normal[3];
 			picoVec2_t* st[3];
 			picoColor_t* color[3];
 			picoIndex_t smooth[3];
-			int j;
-			/* we pull the data from the vertex, color and texcoord arrays using the face index data */
-			for ( j = 0 ; j < 3 ; j ++ )
+
+			int j,z;
+
+         
+   
+         /* we pull the data from the vertex, color and texcoord arrays using the face index data */
+         for ( j = 0 ; j < 3 ; j ++ )
 			{
-				xyz[j]    = &vertices[(*i).indices[j]].xyz;
-				normal[j] = &vertices[(*i).indices[j]].normal;
+            aseFacesIter_t q = faces;
+            aseFacesIter_t qend = faces + numFaces;
+
+            xyz[j]    = &vertices[(*i).indices[j]].xyz;
+            
+            // Use Face normal
+            normal[j] = &(*i).facenormal;
+             
+     
+            //Oooor we can use the smoothing group
+
+            //Slow method, but testing
+            //Find All faces that use this vertex, average their facenormals.
+            // skip where smoothgroups both equal 0, or don't have any shared bits (x & y)
+            index=(*i).indices[j];
+    
+//            accum[0]=0;
+  //          accum[1]=0;
+    //        accum[2]=0;
+            accum[0]=(*i).facenormal[0];
+            accum[1]=(*i).facenormal[1];
+            accum[2]=(*i).facenormal[2];
+            counter=1;
+           
+            
+            z=0;
+            for(; q != qend; ++q)
+            {
+               z++;
+               if (q==i)
+                  continue;
+               // if  ( (*q).indices[0]==index || (*q).indices[1]==index || (*q).indices[2]==index) 
+                a[0]=  &vertices[(*q).indices[0] ].xyz; 
+                a[1]=  &vertices[(*q).indices[1] ].xyz; 
+                a[2]=  &vertices[(*q).indices[2] ].xyz; 
+               
+               if ( VectorCompareExtn(*a[0],*xyz[j],0.01f)>0 ||
+                    VectorCompareExtn(*a[1],*xyz[j],0.01f)>0 ||
+                    VectorCompareExtn(*a[2],*xyz[j],0.01f)>0
+                  )
+               {
+                  if ( (*i).smoothingGroup==0 && (*q).smoothingGroup ==0 )
+                     continue;
+
+                  if ( (*i).smoothingGroup & (*q).smoothingGroup  )
+                  {
+                     accum[0]+=(*q).facenormal[0];
+                     accum[1]+=(*q).facenormal[1];
+                     accum[2]+=(*q).facenormal[2];
+                     
+                     counter++;
+             
+                  }
+               }
+            } 
+            _pico_normalize_vec(accum); 
+
+            (*i).vertexnormal[j][0]=accum[0];
+            (*i).vertexnormal[j][1]=accum[1];
+            (*i).vertexnormal[j][2]=accum[2];
+            normal[j]=&(*i).vertexnormal[j]; 
+                        
+
 				st[j]     = &texcoords[(*i).indices[j + 3]].texcoord;
-	 	 	
-				if( colors != NULL && (*i).indices[j + 6] >= 0 )
+	 	 	      
+          	if( colors != NULL && (*i).indices[j + 6] >= 0 )
 				{
 					color[j] = &colors[(*i).indices[j + 6]].color;
 				}
@@ -490,30 +616,18 @@
 					color[j] = &white;
 				}
 
-				smooth[j] = (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
+				smooth[j] = 0;//  (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
 				
 			}
 
 			/* submit the triangle to the model */
 			PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader, smooth );
 		}
+
 	}
 }
 
-static void shadername_convert(char* shaderName)
-{
-  /* unix-style path separators */
-  char* s = shaderName;
-  for(; *s != '\0'; ++s)
-  {
-    if(*s == '\\')
-    {
-      *s = '/';
-    }
-  }
-}
 
-
 /* _ase_load:
  *  loads a 3dsmax ase model file.
 */
@@ -534,6 +648,9 @@
 	int numColorVertices = 0;
 	int numColorVertexFaces = 0;
 	int vertexId = 0;
+   int currentVertexFace=0;
+   int currentVertexIndex=0;
+   int counter=0;
 
 	aseMaterial_t* materials = NULL;
 
@@ -610,10 +727,11 @@
 		}
 		else if (!_pico_stricmp(p->token,"*mesh_numvertex"))
 		{
-			if (!_pico_parse_int( p, &numVertices) )
+  			if (!_pico_parse_int( p, &numVertices) )
 				_ase_error_return("Missing MESH_NUMVERTEX value");
 
 			vertices = _pico_calloc(numVertices, sizeof(aseVertex_t));
+         currentVertexIndex=0;   
 		}
 		else if (!_pico_stricmp(p->token,"*mesh_numfaces"))
 		{
@@ -621,6 +739,7 @@
 				_ase_error_return("Missing MESH_NUMFACES value");
 
 			faces = _pico_calloc(numFaces, sizeof(aseFace_t));
+
 		}
 		else if (!_pico_stricmp(p->token,"*mesh_numtvertex"))
 		{
@@ -685,7 +804,20 @@
 
 			vertices[index].id = vertexId++;
 		}
-		/* model mesh vertex normal */
+		else if (!_pico_stricmp(p->token,"*mesh_facenormal"))
+		{
+		   //Grab the faceindex for the next vertex normals.
+         if( numVertices == 0 )
+				_ase_error_return("Vertex parse error (facenormals)");
+
+         if (!_pico_parse_int( p,&currentVertexFace ))
+				_ase_error_return("Vertex parse error");
+
+ 			if (!_pico_parse_vec( p,faces[currentVertexFace].facenormal ))
+				_ase_error_return("Vertex parse error");
+
+      }
+      /* model mesh vertex normal */
 		else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))
 		{
 			int			index;
@@ -696,10 +828,25 @@
 			/* get vertex data (orig: index +y -x +z) */
 			if (!_pico_parse_int( p,&index ))
 				_ase_error_return("Vertex parse error");
-			if (!_pico_parse_vec( p,vertices[index].normal ))
+
+         //^^ Index is 'wrong' in .ase models.  they reference the same vert index with multiple normals..
+         // I've tried, this is a lost cause.  Use the SG's
+         // 
+			/*
+         
+         if (!_pico_parse_vec( p,vertices[counter].normal ))
 				_ase_error_return("Vertex parse error");
+         vertices[counter].faceid=index;
+         counter++;
+         */
 		}
 		/* model mesh face */
+		else if (!_pico_stricmp(p->token,"*mesh_normals"))
+      {
+      //   counter=0; //part of the above vertex normals fix
+      }
+         
+      /* model mesh face */
 		else if (!_pico_stricmp(p->token,"*mesh_face"))
 		{
 			picoIndex_t indexes[3];
@@ -736,8 +883,35 @@
 				}
 				if (!_pico_stricmp (p->token,"*MESH_SMOOTHING" ))
 				{
-					_pico_parse_int ( p , &faces[index].smoothingGroup );
-				}
+               int total=0;
+               char* point;
+               char* start;
+               _pico_parse(p,0);
+
+               point=p->token;
+               start=point;
+               faces[index].smoothingGroup=0;
+              
+               //Super dodgy comma delimited string parse
+               while (*point<'A') 
+               {
+                  if (*point<=32 || *point==',')
+                  {
+                     total=atoi(start);
+                     if (total!=0)
+                     {
+                        faces[index].smoothingGroup+=1<<total;
+                     }
+                     start=point+1;
+                  }
+                  
+                  point++;
+               }
+               
+               
+			      
+               
+            }
 				if (!_pico_stricmp (p->token,"*MESH_MTLID" ))
 				{
 					_pico_parse_int ( p , &faces[index].subMaterialId );
@@ -755,19 +929,19 @@
 			int			index;
 
 			if( numVertices == 0 )
-				_ase_error_return("Texture Vertex parse error");
+				_ase_error_return("Vertex parse error");
 
 			/* get uv vertex index */
-			if (!_pico_parse_int( p,&index ) || index >= numTextureVertices)
-				_ase_error_return("Texture vertex parse error");
+			if (!_pico_parse_int( p,&index ))
+				_ase_error_return("UV vertex parse error");
 
 			/* get uv vertex s */
 			if (!_pico_parse_float( p,&texcoords[index].texcoord[0] ))
-				_ase_error_return("Texture vertex parse error");
+				_ase_error_return("UV vertex parse error");
 
 			/* get uv vertex t */
 			if (!_pico_parse_float( p,&texcoords[index].texcoord[1] ))
-				_ase_error_return("Texture vertex parse error");
+				_ase_error_return("UV vertex parse error");
 			
 			/* ydnar: invert t */
 			texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
@@ -831,6 +1005,13 @@
 			
 			/* leave alpha alone since we don't get any data from the ASE format */
 			colors[index].color[3] = 255;
+
+         /* 27 hack, red as alpha */
+         colors[index].color[3]=colors[index].color[0];
+         colors[index].color[0]=255;
+         colors[index].color[1]=255;
+         colors[index].color[2]=255;
+
 		}
 		/* model color face */
 		else if (!_pico_stricmp(p->token,"*mesh_cface"))
@@ -900,7 +1081,6 @@
 				{
 					/* set material name */
 					_pico_first_token( materialName );
-          shadername_convert(materialName);
 					PicoSetShaderName( shader, materialName);
 
 					/* set shader's transparency */
@@ -1085,7 +1265,6 @@
 				}
 
 				/* set material name */
-        shadername_convert(materialName);
 				PicoSetShaderName( shader,materialName );
 
 				/* set shader's transparency */
@@ -1115,8 +1294,18 @@
           char* p = mapname;
 
           /* convert to shader-name format */
-          shadername_convert(mapname);
           {
+            /* unix-style path separators */
+            char* s = mapname;
+            for(; *s != '\0'; ++s)
+            {
+              if(*s == '\\')
+              {
+                *s = '/';
+              }
+            }
+          }
+          {
             /* remove extension */
             char* last_period = strrchr(p, '.');
             if(last_period != NULL)
@@ -1125,14 +1314,32 @@
             }
           }
 
-          /* find shader path */
+          /* find game root */
           for(; *p != '\0'; ++p)
           {
-            if(_pico_strnicmp(p, "models/", 7) == 0 || _pico_strnicmp(p, "textures/", 9) == 0)
+            if(_pico_strnicmp(p, "quake", 5) == 0 || _pico_strnicmp(p, "doom", 4) == 0)
             {
               break;
             }
           }
+          /* root-relative */
+          for(; *p != '\0'; ++p)
+          {
+            if(*p == '/')
+            {
+              ++p;
+              break;
+            }
+          }
+          /* game-relative */
+          for(; *p != '\0'; ++p)
+          {
+            if(*p == '/')
+            {
+              ++p;
+              break;
+            }
+          }
 
           if(*p != '\0')
           {
Index: libs/picomodel/picomodel.c
===================================================================
--- libs/picomodel/picomodel.c	(revision 158)
+++ libs/picomodel/picomodel.c	(working copy)
@@ -295,10 +295,7 @@
 		model = PicoModuleLoadModel(module, fileName, buffer, bufSize, frameNum);
 	}
 	
-  if(model != 0)
-  {
-	  _pico_free(buffer);
-  }
+	_pico_free(buffer);
 
 	/* return */
 	return model;
@@ -1573,6 +1570,7 @@
 {
 	int		i, j;
 	
+//   Sys_Printf(" %f %f %f\n", normal[0] , normal[1] , normal[2] );
 	
 	/* dummy check */
 	if( surface == NULL || surface->numVertexes <= 0 )
@@ -1861,13 +1859,10 @@
 typedef picoVec3_t* picoNormalIter_t;
 typedef picoIndex_t* picoIndexIter_t;
 
-#define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
-
 void _pico_triangles_generate_weighted_normals(picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals)
 {
 	for(; first != end; first += 3)
 	{
-#if (THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
 		picoVec3_t weightedNormal;
 		{
 			float* a = xyz[*(first + 0)];
@@ -1878,24 +1873,11 @@
 			_pico_subtract_vec( c, a, ca );
 			_pico_cross_vec( ca, ba, weightedNormal );
 		}
-#endif
 		{
 			int j = 0;
 			for(; j < 3; ++j)
 			{
 				float* normal = normals[*(first + j)];
-#if (!THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
-				picoVec3_t weightedNormal;
-				{
-					float* a = xyz[*(first + ((j + 0) % 3))];
-					float* b = xyz[*(first + ((j + 1) % 3))];
-					float* c = xyz[*(first + ((j + 2) % 3))];
-					picoVec3_t ba, ca;
-					_pico_subtract_vec( b, a, ba );
-					_pico_subtract_vec( c, a, ca );
-					_pico_cross_vec( ca, ba, weightedNormal );
-				}
-#endif
 				_pico_add_vec(weightedNormal, normal, normal);
 			}
 		}
@@ -1941,7 +1923,8 @@
 {
 	for(; first != last; ++first, ++generated)
 	{
-		if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated))
+      //27 - fix for badly generated normals thing.
+      //	if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated))
 		{
 			_pico_copy_vec(*generated, *first);
 		}
@@ -1954,10 +1937,11 @@
 
 	_pico_normals_zero(normals, normals + surface->numVertexes);
 
+   //Just build standard no sg normals for now
 	_pico_triangles_generate_weighted_normals(surface->index, surface->index + surface->numIndexes, surface->xyz, normals);
 	_pico_vertices_combine_shared_normals(surface->xyz, surface->smoothingGroup, normals, surface->numVertexes);
 
-	_pico_normals_normalize(normals, normals + surface->numVertexes);
+	_pico_normals_normalize(normals, normals + surface->numVertexes); 
 
 	_pico_normals_assign_generated_normals(surface->normal, surface->normal + surface->numVertexes, normals);
 
@@ -2261,7 +2245,7 @@
 		int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface );
 
 		/* get the index of the vertex that we're going to store at newVertIndex */
-		vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]);
+      vertDataIndex = -1;// PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]);
 
 		/* the vertex wasn't found, so create a new vertex in the pool from the data we have */
 		if ( vertDataIndex == -1 )
@@ -2290,3 +2274,5 @@
 		PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex );
 	}
 }
+
+
