// returns surfID
static SurfaceHandle_t R_LightVecDisplacementChain( LightVecState_t& state, bool bUseLightStyles, Vector& c )
{
	// test the ray against displacements
	SurfaceHandle_t surfID = SURFACE_HANDLE_INVALID;

	for ( int i = 0; i < state.m_LightTestDisps.Count(); i++ )
	{
	
		float dist;
		Vector2D luv, tuv;
		IDispInfo *pDispInfo = state.m_LightTestDisps[i];
		if (pDispInfo->TestRay( state.m_Ray, 0.0f, state.m_HitFrac, dist, &luv, &tuv ))
		{
			// It hit it, and at a point closer than the previously computed
			// nearest intersection point
			state.m_HitFrac = dist;
			surfID = pDispInfo->GetParent();
			ComputeLightmapColor( surfID, (int)luv.x, (int)luv.y, bUseLightStyles, c );

			if (state.m_pLightmapS && state.m_pLightmapT)
			{
				ComputeLightmapCoordsAtIntersection( SurfaceLighting(surfID), (int)luv.x, (int)luv.y, state.m_pLightmapS, state.m_pLightmapT );
			}

			if (state.m_pTextureS && state.m_pTextureT)
			{
				*state.m_pTextureS = tuv.x;
				*state.m_pTextureT = tuv.y;
			}
		}
	}

	return surfID;
}
// returns surfID
static int R_LightVecDisplacementChain( LightVecState_t& state, bool bUseLightStyles, Vector& c )
{
	// test the ray against displacements
	int surfID = -1;

	IDispInfo *pDispInfo = state.m_LightTestChain.GetHead();
	for( ; pDispInfo; pDispInfo = pDispInfo->GetNextInRayCastChain() )
	{
		float dist;
		Vector2D luv, tuv;
		if (pDispInfo->TestRay( state.m_Ray, 0.0f, state.m_HitFrac, dist, &luv, &tuv ))
		{
			// It hit it, and at a point closer than the previously computed
			// nearest intersection point
			state.m_HitFrac = dist;
			surfID = pDispInfo->GetParent();

			ComputeLightmapColor( surfID, (int)luv.x, (int)luv.y, bUseLightStyles, c );

			if (state.m_pLightmapS && state.m_pLightmapT)
			{
				ComputeLightmapCoordsAtIntersection( SurfaceLighting(surfID), (int)luv.x, (int)luv.y, state.m_pLightmapS, state.m_pLightmapT );
			}

			if (state.m_pTextureS && state.m_pTextureT)
			{
				*state.m_pTextureS = tuv.x;
				*state.m_pTextureT = tuv.y;
			}
		}
	}

	return surfID;
}
//-----------------------------------------------------------------------------
// Tests a particular surface
//-----------------------------------------------------------------------------
static bool FASTCALL FindIntersectionAtSurface( int surfID, float f, 
	Vector& c, LightVecState_t& state )
{
	// no lightmaps on this surface? punt...
	// FIXME: should be water surface?
	if (MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT)
		return false;	

	// Compute the actual point
	Vector pt;
	VectorMA( state.m_Ray.m_Start, f, state.m_Ray.m_Delta, pt );

	mtexinfo_t* pTex = MSurf_TexInfo( surfID );
	
	// See where in lightmap space our intersection point is 
	float s, t;
	s = DotProduct (pt, pTex->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) + 
		pTex->lightmapVecsLuxelsPerWorldUnits[0][3];
	t = DotProduct (pt, pTex->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) + 
		pTex->lightmapVecsLuxelsPerWorldUnits[1][3];

	// Not in the bounds of our lightmap? punt...
	msurfacelighting_t *pLighting = SurfaceLighting( surfID );
	if( s < pLighting->m_pLightmapMins[0] || 
		t < pLighting->m_pLightmapMins[1] )
		return false;	
	
	// assuming a square lightmap (FIXME: which ain't always the case),
	// lets see if it lies in that rectangle. If not, punt...
	float ds = s - pLighting->m_pLightmapMins[0];
	float dt = t - pLighting->m_pLightmapMins[1];
	if( ds > pLighting->m_pLightmapExtents[0] || dt > pLighting->m_pLightmapExtents[1] )
		return false;	

	// Store off the hit distance...
	state.m_HitFrac = f;

	// You heard the man!
	ComputeTextureCoordsAtIntersection( pTex, pt, state.m_pTextureS, state.m_pTextureT );

#ifdef USE_CONVARS
	if( 1 )
#else
	if (r_avglight.GetInt())
#endif
	{
		// This is the faster path; it looks slightly different though
		ComputeLightmapColorFromAverage( pLighting, state.m_bUseLightStyles, c );
	}
	else
	{
		// Compute lightmap coords
		ComputeLightmapCoordsAtIntersection( pLighting, ds, dt, state.m_pLightmapS, state.m_pLightmapT );
		
		// Check out the value of the lightmap at the intersection point
		ComputeLightmapColor( surfID, (int)ds, (int)dt, state.m_bUseLightStyles, c );
	}

	return true;
}
//-----------------------------------------------------------------------------
// Tests a particular surface
//-----------------------------------------------------------------------------
static bool FASTCALL FindIntersectionAtSurface( SurfaceHandle_t surfID, float f, 
	Vector& c, LightVecState_t& state )
{
	// no lightmaps on this surface? punt...
	// FIXME: should be water surface?
	if (MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT)
		return false;	

	// Compute the actual point
	Vector pt;
	VectorMA( state.m_Ray.m_Start, f, state.m_Ray.m_Delta, pt );

	mtexinfo_t* pTex = MSurf_TexInfo( surfID );
	
	// See where in lightmap space our intersection point is 
	float s, t;
	s = DotProduct (pt, pTex->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) + 
		pTex->lightmapVecsLuxelsPerWorldUnits[0][3];
	t = DotProduct (pt, pTex->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) + 
		pTex->lightmapVecsLuxelsPerWorldUnits[1][3];

	// Not in the bounds of our lightmap? punt...
	msurfacelighting_t *pLighting = SurfaceLighting( surfID );
	if( s < pLighting->m_LightmapMins[0] || 
		t < pLighting->m_LightmapMins[1] )
		return false;	
	
	// assuming a square lightmap (FIXME: which ain't always the case),
	// lets see if it lies in that rectangle. If not, punt...
	float ds = s - pLighting->m_LightmapMins[0];
	float dt = t - pLighting->m_LightmapMins[1];
	if ( !pLighting->m_LightmapExtents[0] && !pLighting->m_LightmapExtents[1] )
	{
		worldbrushdata_t *pBrushData = host_state.worldbrush;

		// 
		float	lightMaxs[2];
		lightMaxs[ 0 ] = pLighting->m_LightmapMins[0];
		lightMaxs[ 1 ] = pLighting->m_LightmapMins[1];
		int i;
		for (i=0 ; i<MSurf_VertCount( surfID ); i++)
		{
			int e = pBrushData->vertindices[MSurf_FirstVertIndex( surfID )+i];
			mvertex_t *v = &pBrushData->vertexes[e];
			
			int j;
			for ( j=0 ; j<2 ; j++)
			{
				float sextent, textent;
				sextent = DotProduct (v->position, pTex->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) + 
					pTex->lightmapVecsLuxelsPerWorldUnits[0][3] - pLighting->m_LightmapMins[0];
				textent = DotProduct (v->position, pTex->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) + 
					pTex->lightmapVecsLuxelsPerWorldUnits[1][3] - pLighting->m_LightmapMins[1];

				if ( sextent > lightMaxs[ 0 ] )
				{
					lightMaxs[ 0 ] = sextent;
				}
				if ( textent > lightMaxs[ 1 ] )
				{
					lightMaxs[ 1 ] = textent;
				}
			}
		}
		if( ds > lightMaxs[0] || dt > lightMaxs[1] )
			return false;	
	}
	else
	{
		if( ds > pLighting->m_LightmapExtents[0] || dt > pLighting->m_LightmapExtents[1] )
			return false;	
	}

	// Store off the hit distance...
	state.m_HitFrac = f;

	// You heard the man!
	ComputeTextureCoordsAtIntersection( pTex, pt, state.m_pTextureS, state.m_pTextureT );

#ifdef USE_CONVARS
	if ( r_avglight.GetInt() )
#else
	if ( 1 )
#endif
	{
		// This is the faster path; it looks slightly different though
		ComputeLightmapColorFromAverage( pLighting, state.m_bUseLightStyles, c );
	}
	else
	{
		// Compute lightmap coords
		ComputeLightmapCoordsAtIntersection( pLighting, ds, dt, state.m_pLightmapS, state.m_pLightmapT );
		
		// Check out the value of the lightmap at the intersection point
		ComputeLightmapColor( surfID, (int)ds, (int)dt, state.m_bUseLightStyles, c );
	}

	return true;
}