//
//
// win_lighteffects.cpp
//
// Various lighting effects w/ pixel shaders
//
//

#ifdef VV_LIGHTING

#include "../server/exe_headers.h"

#include "../renderer/tr_local.h"
#include "glw_win_dx8.h"
#include "win_local.h"

#include "win_lighteffects.h"

#include <xgraphics.h>
#include <xgmath.h>

#include "shader_constants.h"


LightEffects::LightEffects()
{
    m_pCubeMap          = NULL;
	m_pBumpMap			= NULL;
//	m_pSpecularMap		= NULL;
	m_pFalloffMap		= NULL;
	m_dwVertexShaderLight = 0L;
	m_dwPixelShaderLight = 0L;
//	m_dwVertexShaderSpecular_Dynamic = 0L;
//	m_dwPixelShaderSpecular_Dynamic = 0L;
//	m_dwVertexShaderSpecular_Static = 0L;
//	m_dwPixelShaderSpecular_Static = 0L;
	m_dwVertexShaderEnvironment = 0L;
//	m_dwVertexShaderBump = 0L;
//	m_dwPixelShaderBump = 0L;
	m_bInLightPhase	    = false;
	m_bInitialized      = false;

	Initialize();
}


LightEffects::~LightEffects()
{
    if( m_pCubeMap )
		m_pCubeMap->Release();
	m_pCubeMap = NULL;

	if(m_pBumpMap)
		m_pBumpMap->Release();
	m_pBumpMap = NULL;

	if(m_pFalloffMap)
		m_pFalloffMap->Release();
	m_pFalloffMap = NULL;
    
	/*if(m_pSpecularMap)
		m_pSpecularMap->Release();
	m_pSpecularMap = NULL;*/

    if( glw_state->device )
	{
        glw_state->device->DeleteVertexShader( m_dwVertexShaderLight );
		glw_state->device->DeletePixelShader( m_dwPixelShaderLight );
		/*glw_state->device->DeleteVertexShader( m_dwVertexShaderSpecular_Dynamic );
		glw_state->device->DeletePixelShader( m_dwPixelShaderSpecular_Dynamic );
		glw_state->device->DeleteVertexShader( m_dwVertexShaderSpecular_Static );
		glw_state->device->DeletePixelShader( m_dwPixelShaderSpecular_Static );*/
		glw_state->device->DeleteVertexShader( m_dwVertexShaderEnvironment );
		glw_state->device->DeletePixelShader( m_dwPixelShaderBump );
		glw_state->device->DeleteVertexShader( m_dwVertexShaderBump );
	}
}


void LightEffects::StartLightPhase()
{
	m_bInLightPhase = true;
}


void LightEffects::EndLightPhase()
{
	m_bInLightPhase = false;
}


bool LightEffects::Initialize()
{
	HRESULT hr;

	// Create a vertex shader
    DWORD dwVertexDecl[] =
    {
        D3DVSD_STREAM( 0 ),
        D3DVSD_REG( 0, D3DVSDT_FLOAT3 ),     // v0 = Position
		D3DVSD_REG( 1, D3DVSDT_FLOAT3 ),	 // v1 = Normal
        D3DVSD_REG( 2, D3DVSDT_FLOAT2 ),     // v2 = Base tex coords
        D3DVSD_REG( 3, D3DVSDT_FLOAT3 ),     // v3 = Tangent space tangent
        D3DVSD_END()
    };

    if(!( CreateVertexShader("D:\\base\\media\\dlight.xvu", dwVertexDecl, &m_dwVertexShaderLight)))
		return false;

	/*if(!( CreateVertexShader("D:\\base\\media\\specular_dynamic.xvu", dwVertexDecl, &m_dwVertexShaderSpecular_Dynamic)))
		return false;

	if(!( CreateVertexShader("D:\\base\\media\\specular_static.xvu", dwVertexDecl, &m_dwVertexShaderSpecular_Static)))
		return false;*/

	DWORD dwVertexDeclBump[] =
	{ 
		D3DVSD_STREAM( 0 ),
		D3DVSD_REG( 0, D3DVSDT_FLOAT3 ),     // v0 = Position
		D3DVSD_REG( 1, D3DVSDT_FLOAT3 ),	 // v1 = Normal
		D3DVSD_REG( 2, D3DVSDT_FLOAT2 ),     // v2 = Base tex coords 0
		D3DVSD_REG( 3, D3DVSDT_FLOAT2 ),     // v2 = Base tex coords 1
		D3DVSD_REG( 4, D3DVSDT_FLOAT3 ),     // v4 = Tangent space tangent
		D3DVSD_END()
	};

	if(!( CreateVertexShader("D:\\base\\media\\bump.xvu", dwVertexDeclBump, &m_dwVertexShaderBump)))
		return false;

	DWORD dwVertexDeclEnv[] =
    {
        D3DVSD_STREAM( 0 ),
        D3DVSD_REG( 0, D3DVSDT_FLOAT3 ),     // v0 = Position
		D3DVSD_REG( 1, D3DVSDT_FLOAT3 ),	 // v1 = Normal
		D3DVSD_REG( 2, D3DVSDT_D3DCOLOR ),   // v2 = Color
		D3DVSD_END()
    };

	if(!( CreateVertexShader("D:\\base\\media\\environment.xvu", dwVertexDeclEnv, &m_dwVertexShaderEnvironment)))
		return false;

	// Create the pixel shader
	if(!(CreatePixelShader("D:\\base\\media\\dlight.xpu", &m_dwPixelShaderLight)))
		return false;

	/*if(!(CreatePixelShader("D:\\base\\media\\specular_dynamic.xpu", &m_dwPixelShaderSpecular_Dynamic)))
		return false;

	if(!(CreatePixelShader("D:\\base\\media\\specular_static.xpu", &m_dwPixelShaderSpecular_Static)))
		return false;*/

	if(!(CreatePixelShader("D:\\base\\media\\bump.xpu", &m_dwPixelShaderBump)))
		return false;

	hr = D3DXCreateTextureFromFileEx(glw_state->device, 
		"D:\\base\\media\\defaultbump.dds",
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		0,
		0,
		D3DFMT_A8R8G8B8,
		0,
		D3DX_FILTER_LINEAR,
		D3DX_FILTER_LINEAR,
		0,
		NULL,
		NULL,
		&m_pBumpMap);
	if (FAILED(hr))
	{
		return false;
	}

	/*hr = D3DXCreateTextureFromFileEx(glw_state->device, 
		"D:\\base\\media\\diffspec.dds",
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		0,
		0,
		D3DFMT_A8R8G8B8,
		0,
		D3DX_FILTER_LINEAR,
		D3DX_FILTER_LINEAR,
		0,
		NULL, 
		NULL, 
		&m_pSpecularMap);
	if (FAILED(hr))
	{
		return false;
	}*/

	// Create the volume falloff texture
	UINT width = 32, 
		 height = 32, 
		 depth = 32, 
		 levels = 1;
	D3DFORMAT format = D3DFMT_A8;
	if (FAILED (hr = glw_state->device->CreateVolumeTexture(width, height, depth,
		1, 0, format, D3DPOOL_DEFAULT, &m_pFalloffMap) ) )
	{
		return false;
	}

	// Fill the volume texture
    D3DVOLUME_DESC  desc;
    D3DLOCKED_BOX   lock;
    m_pFalloffMap->GetLevelDesc( 0, &desc );
    m_pFalloffMap->LockBox( 0, &lock, 0, 0L );
    BYTE* pBits = (BYTE*)lock.pBits;

    for( UINT w=0; w<width; w++ )
    {
        for( UINT v=0; v<height; v++ )
        {
            for( UINT u=0; u<depth; u++ )
            {
				FLOAT x = (2.0f*u)/(width-1) - 1.0f; // Ranges from -1 to +1
				FLOAT y = (2.0f*v)/(height-1) - 1.0f; // Ranges from -1 to +1
				FLOAT z = (2.0f*w)/(depth-1) - 1.0f;

				FLOAT distance = (float)(x*x + y*y + z*z);
				if (distance == 0) 
				{
					*pBits++ = (BYTE)255;
				}
				else
				{
                    FLOAT falloff = min(1.0f, max(0.0f, ((1.0f/2.0f)/distance - 1.0f/2.0f)/1.0f ) );
					*pBits++ = (BYTE)(255*falloff);
				}
            }
        }
    }

	DWORD dwPixelSize   = XGBytesPerPixelFromFormat( desc.Format );
    DWORD dwTextureSize = desc.Width * desc.Height * desc.Depth * dwPixelSize;

    BYTE* pSrcBits = new BYTE[ dwTextureSize ];
    memcpy( pSrcBits, lock.pBits, dwTextureSize );
    
    XGSwizzleBox( pSrcBits, 0, 0, NULL, lock.pBits, 
                  desc.Width, desc.Height, desc.Depth, 
                  NULL, dwPixelSize );

    delete [] pSrcBits;

	m_pFalloffMap->UnlockBox( 0 );

	// Create the normalization cube map
    if(!CreateNormalizationCubeMap( 32, &m_pCubeMap ))
        return false;

	m_bInitialized = true;

    return true;
}


bool LightEffects::RenderDynamicLights()
{
	dlight_t *dl;
	shaderStage_t *dStage;
	vec3_t	origin;
	byte	clipBits[SHADER_MAX_VERTEXES];
	glIndex_t	hitIndexes[SHADER_MAX_INDEXES];
	int		numIndexes;
	float	radius;
	int		fogging;
	vec3_t	dist;
	vec3_t	e1;
	vec3_t	e2;
	vec3_t	normal;
	float	fac;

	if(!backEnd.refdef.num_dlights)
		return true;

	glw_state->device->SetRenderState( D3DRS_LIGHTING,         FALSE );   
    
	glw_state->device->SetTextureStageState( 1, D3DTSS_ADDRESSU,  D3DTADDRESS_WRAP );
	glw_state->device->SetTextureStageState( 1, D3DTSS_ADDRESSV,  D3DTADDRESS_WRAP );
    glw_state->device->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
    glw_state->device->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
	glw_state->device->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_LINEAR );

	glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
	glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
	glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSW,  D3DTADDRESS_CLAMP );
    glw_state->device->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
    glw_state->device->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );

	glw_state->device->SetTextureStageState( 3, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
	glw_state->device->SetTextureStageState( 3, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
	glw_state->device->SetTextureStageState( 3, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
    glw_state->device->SetTextureStageState( 3, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
	glw_state->device->SetTextureStageState( 3, D3DTSS_MIPFILTER, D3DTEXF_POINT );

	glw_state->device->SetTextureStageState( 2, D3DTSS_ALPHAKILL, D3DTALPHAKILL_ENABLE);
	
	glw_state->device->SetTexture(1, m_pBumpMap); 
	glw_state->device->SetTexture(2, m_pFalloffMap);
	glw_state->device->SetTexture(3, m_pCubeMap);
	
	glw_state->device->SetPixelShader(m_dwPixelShaderLight);
	glw_state->device->SetVertexShader(m_dwVertexShaderLight);

	for(int l = 0; l < backEnd.refdef.num_dlights; l++)
	{  
		if(!(tess.dlightBits & (1 << l)))  
			continue;

		dl = &backEnd.refdef.dlights[l];
		if(!dl)
			continue;

		VectorCopy( dl->transformed, origin );
		radius = dl->radius;

		int		clipall = 63;
		for (int i = 0 ; i < tess.numVertexes ; i++) 
		{
			int		clip;
			VectorSubtract( origin, tess.xyz[i], dist );

			clip = 0;
			if (  dist[0] < -radius ) 
			{
				clip |= 1;
			}
			else if ( dist[0] > radius ) 
			{
				clip |= 2;
			}
			if (  dist[1] < -radius ) 
			{
				clip |= 4;
			}
			else if ( dist[1] > radius ) 
			{
				clip |= 8;
			}
			if (  dist[2] < -radius ) 
			{
				clip |= 16;
			}
			else if ( dist[2] > radius ) 
			{
				clip |= 32;
			}

			clipBits[i] = clip;
			clipall &= clip;
		}
		if ( clipall ) 
		{
			continue;	// this surface doesn't have any of this light
		}
		
		// build a list of triangles that need light
		numIndexes = 0;
		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) 
		{
			int		a, b, c;

			a = tess.indexes[i];
			b = tess.indexes[i+1];
			c = tess.indexes[i+2];
			if ( clipBits[a] & clipBits[b] & clipBits[c] ) 
			{
				continue;	// not lighted
			}

			VectorSubtract( tess.xyz[a], tess.xyz[b], e1);
			VectorSubtract( tess.xyz[c], tess.xyz[b], e2);
			CrossProduct(e1,e2,normal);

			VectorNormalize(normal);
			fac=DotProduct(normal,origin)-DotProduct(normal, tess.xyz[a]);
			if (fac >= radius)  // out of range
			{
				continue;
			}
			
			// save the indexes
			hitIndexes[numIndexes] = tess.indexes[i];
			hitIndexes[numIndexes + 1] = tess.indexes[i + 1];
			hitIndexes[numIndexes + 2] = tess.indexes[i + 2];

			numIndexes += 3;

			if (numIndexes>=SHADER_MAX_VERTEXES-3)
			{
				break; // we are out of space, so we are done :)
			}
		}

		if ( !numIndexes ) {
			continue;
		}

		//don't have fog enabled when we redraw with alpha test, or it will double over
		//and screw the tri up -rww
		if (r_drawfog->value == 2 && 
			tr.world &&
			(tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs))
		{
			fogging = qglIsEnabled(GL_FOG);

			if (fogging)
			{
				qglDisable(GL_FOG);
			}
		}
		else
		{
			fogging = 0;
		}

		dStage = NULL;
		if (tess.shader)
		{
			int j = 0;
			while (j < tess.shader->numUnfoggedPasses)
			{
				const int blendBits = (GLS_SRCBLEND_BITS+GLS_DSTBLEND_BITS);
				if (((tess.shader->stages[j].bundle[0].image && !tess.shader->stages[j].bundle[0].isLightmap && !tess.shader->stages[j].bundle[0].numTexMods && tess.shader->stages[j].bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[j].bundle[0].tcGen != TCGEN_FOG) ||
					(tess.shader->stages[j].bundle[1].image && !tess.shader->stages[j].bundle[1].isLightmap && !tess.shader->stages[j].bundle[1].numTexMods && tess.shader->stages[j].bundle[1].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[j].bundle[1].tcGen != TCGEN_FOG)) &&
					(tess.shader->stages[j].stateBits & blendBits) == 0 )
				{ //only use non-lightmap opaque stages
					dStage = &tess.shader->stages[j];
					break;
				}
				j++;
			}
		}

		if (dStage)
		{
			GL_SelectTexture( 0 );
			GL_State(0);
			if (dStage->bundle[0].image && !dStage->bundle[0].isLightmap && !dStage->bundle[0].numTexMods && dStage->bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && dStage->bundle[0].tcGen != TCGEN_FOG)
			{
				GL_Bind( dStage->bundle[0].image );
			}
			else
			{
				GL_Bind( dStage->bundle[1].image );
			}

			GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);// | GLS_DEPTHFUNC_EQUAL);
		}
		else
		{
			GL_Bind( tr.whiteImage );
			GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE);// | GLS_DEPTHFUNC_EQUAL );
		}

		glwstate_t::texturexlat_t::iterator inf = glw_state->textureXlat.find(glw_state->currentTexture[0]);

		glw_state->device->SetTexture(0, inf->second.mipmap);

		D3DXVECTOR4 vecLightRange(1.0f / dl->radius, 0.0f, 0.0f, 0.0f);
		glw_state->device->SetVertexShaderConstant(CV_ONE_OVER_LIGHT_RANGE, (void*)&vecLightRange.x, 1);

		glw_state->device->SetPixelShaderConstant(CP_DIFFUSE_COLOR, &dl->color[0], 1);

		ProcessVertices( (D3DXVECTOR3*)&dl->transformed );

		renderObject_Light( numIndexes, hitIndexes );

		if (fogging)
		{
			qglEnable(GL_FOG);
		}
	}

	glw_state->device->SetPixelShader( 0 );

	// This is kinda a hack to get the quake renderer to discard
	// these textures after they are used here, instead of applying
	// them to more geometry
	glState.currenttextures[0] = -2;
	glState.currenttextures[1] = -2;
	glw_state->currentTexture[0] = -2;
	glw_state->currentTexture[1] = -2;

	glw_state->device->SetTextureStageState( 2, D3DTSS_ALPHAKILL, D3DTALPHAKILL_DISABLE);
	
	return true;
}


//void LightEffects::RenderSpecular()
//{
//	glw_state->device->SetRenderState( D3DRS_LIGHTING,         FALSE );   
//	glw_state->device->SetRenderState( D3DRS_FOGENABLE,		   FALSE );
//
//	glwstate_t::texturexlat_t::iterator i = glw_state->textureXlat.find(glw_state->currentTexture[0]);
//
//	glw_state->device->SetTexture( 0, i->second.mipmap );   
//	glw_state->device->SetTexture( 2, m_pSpecularMap );
//
//	glw_state->device->SetVertexShaderConstant(CV_CAMERA_DIRECTION, D3DXVECTOR4(tr.viewParms.ori.axis[0][0],
//		tr.viewParms.ori.axis[0][1],
//		tr.viewParms.ori.axis[0][2],
//		1.0f), 1 );
//
//	RenderSpecular_Static();
//
//	if(tess.dlightBits)
//		RenderSpecular_Dynamic();
//
//	glw_state->device->SetPixelShader(0);
//
//	// This is kinda a hack to get the quake renderer to discard
//	// these textures after they are used here, instead of applying
//	// them to more geometry
//	glState.currenttextures[0] = -2;
//	glState.currenttextures[1] = -2;
//	glw_state->currentTexture[0] = -2;
//	glw_state->currentTexture[1] = -2;
//}
//
//
//bool LightEffects::RenderSpecular_Dynamic()
//{
//	VVdlight_t *dl;
//
//	glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSU,  D3DTADDRESS_WRAP );
//	glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSV,  D3DTADDRESS_WRAP );
//    glw_state->device->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
//    glw_state->device->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
//    glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
//    glw_state->device->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
//    glw_state->device->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
//	glw_state->device->SetTextureStageState( 2, D3DTSS_MIPFILTER, D3DTEXF_POINT );
//	glw_state->device->SetTextureStageState( 3, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
//	glw_state->device->SetTextureStageState( 3, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
//	glw_state->device->SetTextureStageState( 3, D3DTSS_ADDRESSW,  D3DTADDRESS_CLAMP );
//	glw_state->device->SetTextureStageState( 3, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 3, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
//
//	glw_state->device->SetTexture( 3, m_pFalloffMap );
//
//	glw_state->device->SetPixelShader(m_dwPixelShaderSpecular_Dynamic);
//	glw_state->device->SetVertexShader(m_dwVertexShaderSpecular_Dynamic);
//
//	for(int i = 0; i < VVLightMan.num_dlights; i++)
//	{  
//		if(!(tess.dlightBits & (1 << i)))  
//			continue;
//
//		dl = &VVLightMan.dlights[i];
//
//		D3DXVECTOR4 vecLightRange(1.0f / dl->radius, 0.0f, 0.0f, 0.0f);
//		glw_state->device->SetVertexShaderConstant(CV_ONE_OVER_LIGHT_RANGE, (void*)&vecLightRange.x, 1);
//
//		ProcessVertices( (D3DXVECTOR3*)&dl->direction, (D3DXVECTOR3*)&dl->transformed );
//
//		renderObject_Light(tess.numIndexes, tess.indexes);
//	}
//
//	glw_state->device->SetTexture( 3, NULL );
//
//	return true;
//}
//
//
//bool LightEffects::RenderSpecular_Static()
//{
//	glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSU,  D3DTADDRESS_WRAP );
//	glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSV,  D3DTADDRESS_WRAP );
//	glw_state->device->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
//	glw_state->device->SetTextureStageState( 2, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
//	glw_state->device->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
//	glw_state->device->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
//	glw_state->device->SetTextureStageState( 2, D3DTSS_MIPFILTER, D3DTEXF_NONE );
//
//	glw_state->device->SetPixelShader(m_dwPixelShaderSpecular_Static);
//	glw_state->device->SetVertexShader(m_dwVertexShaderSpecular_Static);
//
//	ProcessVertices( NULL, NULL );
//
//	D3DXVECTOR4 vLight;
//	if (backEnd.currentEntity && (backEnd.currentEntity->e.hModel||backEnd.currentEntity->e.ghoul2) )
//	{
//		vLight.x = backEnd.currentEntity->lightDir[0];
//		vLight.y = backEnd.currentEntity->lightDir[1];
//		vLight.z = backEnd.currentEntity->lightDir[2];
//	}
//	else
//	{
//		// These values were taken from the RB_CalcSpecularAlpha default case
//		vLight.x = -960.0f;
//		vLight.y = 1920.0f;
//		vLight.z = 96.0f;
//	}
//	
//	vLight.w = 1.0f;
//
//	glw_state->device->SetVertexShaderConstant(CV_LIGHT_DIRECTION, vLight, 1);
//
//	renderObject_Light(tess.numIndexes, tess.indexes);
//
//	return true;
//}

bool LightEffects::RenderEnvironment()
{
	glw_state->device->SetRenderState( D3DRS_LIGHTING, false );
	glw_state->device->SetRenderState( D3DRS_FOGENABLE, false );

	glw_state->device->SetVertexShaderConstant(CV_CAMERA_DIRECTION, D3DXVECTOR4(backEnd.ori.viewOrigin[0],
																				backEnd.ori.viewOrigin[1],
																				backEnd.ori.viewOrigin[2],
																				1.0f), 1 );

	ProcessVertices(NULL);

	glw_state->device->SetVertexShader(m_dwVertexShaderEnvironment);

	renderObject_Env();

	return true;
}


// Renders bump maps without the benefit of dynamic lights
void LightEffects::RenderBump()
{
	glw_state->device->SetRenderState( D3DRS_LIGHTING, false );
	glw_state->device->SetRenderState( D3DRS_FOGENABLE, false );

	glwstate_t::texturexlat_t::iterator i = glw_state->textureXlat.find(glw_state->currentTexture[0]);
	glw_state->device->SetTexture( 0, i->second.mipmap );

	i = glw_state->textureXlat.find(glw_state->currentTexture[1]);
	glw_state->device->SetTexture( 1, i->second.mipmap );

	glw_state->device->SetTextureStageState(0, D3DTSS_MAXANISOTROPY, i->second.anisotropy);
	glw_state->device->SetTextureStageState(0, D3DTSS_MINFILTER, i->second.minFilter);
	glw_state->device->SetTextureStageState(0, D3DTSS_MIPFILTER, i->second.mipFilter);
	glw_state->device->SetTextureStageState(0, D3DTSS_MAGFILTER, i->second.magFilter);
	glw_state->device->SetTextureStageState(0, D3DTSS_ADDRESSU, i->second.wrapU);
	glw_state->device->SetTextureStageState(0, D3DTSS_ADDRESSV, i->second.wrapV);

	glw_state->device->SetTextureStageState(1, D3DTSS_MAXANISOTROPY, i->second.anisotropy);
	glw_state->device->SetTextureStageState(1, D3DTSS_MINFILTER, i->second.minFilter);
	glw_state->device->SetTextureStageState(1, D3DTSS_MIPFILTER, i->second.mipFilter);
	glw_state->device->SetTextureStageState(1, D3DTSS_MAGFILTER, i->second.magFilter);
	glw_state->device->SetTextureStageState(1, D3DTSS_ADDRESSU, i->second.wrapU);
	glw_state->device->SetTextureStageState(1, D3DTSS_ADDRESSV, i->second.wrapV);

	glw_state->device->SetRenderState(D3DRS_SPECULARENABLE, true);

	glw_state->device->SetPixelShader(m_dwPixelShaderBump);
	glw_state->device->SetVertexShader(m_dwVertexShaderBump);

	ProcessVertices(NULL);

	D3DXVECTOR4 vAmbient, vDiffuse, vLightDir;

	if (backEnd.currentEntity && (backEnd.currentEntity->e.hModel||backEnd.currentEntity->e.ghoul2) )
	{
		if(tess.shader->stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE_ENTITY)
		{
			vAmbient.x = (backEnd.currentEntity->ambientLight[0] / 255.f) * (backEnd.currentEntity->e.shaderRGBA[0] / 255.0);
			vAmbient.y = (backEnd.currentEntity->ambientLight[1] / 255.f) * (backEnd.currentEntity->e.shaderRGBA[1] / 255.0);
			vAmbient.z = (backEnd.currentEntity->ambientLight[2] / 255.f) * (backEnd.currentEntity->e.shaderRGBA[2] / 255.0);
		}
		else
		{
			vAmbient.x = backEnd.currentEntity->ambientLight[0] / 255.f;
			vAmbient.y = backEnd.currentEntity->ambientLight[1] / 255.f;
			vAmbient.z = backEnd.currentEntity->ambientLight[2] / 255.f;
		}

		vDiffuse.x = backEnd.currentEntity->directedLight[0] / 255.f;
		vDiffuse.y = backEnd.currentEntity->directedLight[1] / 255.f;
		vDiffuse.z = backEnd.currentEntity->directedLight[2] / 255.f; 

		vLightDir.x = DotProduct( backEnd.currentEntity->lightDir, backEnd.currentEntity->e.axis[0] );
		vLightDir.y = DotProduct( backEnd.currentEntity->lightDir, backEnd.currentEntity->e.axis[1] );
		vLightDir.z = DotProduct( backEnd.currentEntity->lightDir, backEnd.currentEntity->e.axis[2] );
	} 
	else
	{
		vec3_t sundir;
		sundir[0] = r_sundir_x->value;
		sundir[1] = r_sundir_y->value;
		sundir[2] = r_sundir_z->value;

		VectorNormalize(sundir);

		vLightDir.x = sundir[0];//tr.sunDirection[0];
		vLightDir.y = sundir[1];//tr.sunDirection[1];
		vLightDir.z = sundir[2];//tr.sunDirection[2];
		vLightDir.w = 1.0f;

		vAmbient.x = tr.sunAmbient[0] / 1.5f;
		vAmbient.y = tr.sunAmbient[1] / 1.5f;
		vAmbient.z = tr.sunAmbient[2] / 1.5f;

		vDiffuse.x = 1.0f;
		vDiffuse.y = 1.0f;
		vDiffuse.z = 1.0f;	
	}

	glw_state->device->SetPixelShaderConstant(CP_AMBIENT_COLOR, vAmbient, 1);
	glw_state->device->SetPixelShaderConstant(CP_DIFFUSE_COLOR, vDiffuse, 1);
	
	glw_state->device->SetVertexShaderConstant(CV_LIGHT_DIRECTION, vLightDir, 1);

	glw_state->device->SetVertexShaderConstant(CV_CAMERA_DIRECTION, D3DXVECTOR4(tr.viewParms.ori.axis[0][0],
		tr.viewParms.ori.axis[0][1],
		tr.viewParms.ori.axis[0][2],
		1.0f), 1 );

	renderObject_Bump();

	glw_state->device->SetPixelShader( 0 );

	glw_state->device->SetRenderState(D3DRS_SPECULARENABLE, false);
}


//bool LightEffects::RenderStaticLights()
//{
//	VVslight_t *sl;
//
//	for(int i = 0; i < tess.numSlights; i++)
//	{  
//		sl = &VVLightMan.slights[tess.slightBits[i]];
//
//		D3DXVECTOR4 vecLightRange(1.0f / (sl->radius * 2.0f), sl->radius, 1.0f, 1.0f);
//		glw_state->device->SetVertexShaderConstant(CV_ONE_OVER_LIGHT_RANGE, (void*)&vecLightRange.x, 1);
//
//		glw_state->device->SetVertexShaderConstant(CV_LIGHT_COLOR, &sl->color[0], 1);
//
//		ProcessVertices( NULL, (D3DXVECTOR3*)&sl->origin );
//
//		renderObject_Light();
//
//		tess.currentPass++;
//	}
//
//    return true;
//}


void LightEffects::ProcessVertices( D3DXVECTOR3* pPtLightPos )
{

	// Just in case, this doesn't always get set
	glw_state->device->SetTransform( D3DTS_PROJECTION, glw_state->matrixStack[glw_state->MatrixMode_Projection]->GetTop() );

	// Compute the matrix set
    XGMATRIX matComposite, matProjectionViewport, matWorld;
	// Get the projection viewport matrix the fixed pipeline uses.
	// The viewport matrix includes the viewport x,y scale and the 
	// appropriate z scale.
	glw_state->device->GetProjectionViewportMatrix( &matProjectionViewport );

	D3DVIEWPORT8 view;
	glw_state->device->GetViewport(&view);

	// Gotta do this to fix an XDK bug
	// GetProjectionViewportMatrix does not seem to reflect the viewport values
	// when the viewport is offset
	matProjectionViewport._31 += view.X;
	matProjectionViewport._32 += view.Y;

	XGMatrixMultiply( &matComposite, (XGMATRIX*)glw_state->matrixStack[glwstate_t::MatrixMode_Model]->GetTop(), &matProjectionViewport );

	// Transpose and set the composite matrix.
	XGMatrixTranspose( &matComposite, &matComposite );
	glw_state->device->SetVertexShaderConstant( CV_WORLDVIEWPROJ_0, &matComposite, 4 );

	if (pPtLightPos)
		glw_state->device->SetVertexShaderConstant( CV_LIGHT_POSITION, pPtLightPos,  1 );

	// Set viewport offsets.
	float fViewportOffsets[4] = { 0.53125f, 0.53125f, 0.0f, 0.0f };
	glw_state->device->SetVertexShaderConstant( CV_VIEWPORT_OFFSETS, &fViewportOffsets, 1 );

	// Set common constants
	glw_state->device->SetVertexShaderConstant(CV_ONE, D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f), 1);
	glw_state->device->SetVertexShaderConstant(CV_HALF, D3DXVECTOR4(0.5f, 0.5f, 0.5f, 0.5f), 1);
}


inline D3DCOLOR VectorToRGBA( const D3DXVECTOR3* v, FLOAT fHeight = 1.0f )
{
    D3DCOLOR r = (D3DCOLOR)( ( v->x + 1.0f ) * 127.5f );
    D3DCOLOR g = (D3DCOLOR)( ( v->y + 1.0f ) * 127.5f );
    D3DCOLOR b = (D3DCOLOR)( ( v->z + 1.0f ) * 127.5f );
    D3DCOLOR a = (D3DCOLOR)( 255.0f * fHeight );
    return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) );
}


bool LightEffects::CreateNormalizationCubeMap( DWORD dwSize, LPDIRECT3DCUBETEXTURE8* ppCubeMap )
{
    HRESULT hr;

    // Create the cube map
    if( FAILED( hr = glw_state->device->CreateCubeTexture( dwSize, 1, 0, D3DFMT_X8R8G8B8, 
                                                    D3DPOOL_DEFAULT, ppCubeMap ) ) )
        return false;
    
    // Allocate temp space for swizzling the cubemap surfaces
    DWORD* pSourceBits = new DWORD[ dwSize * dwSize ];

    // Fill all six sides of the cubemap
    for( DWORD i=0; i<6; i++ )
    {
        // Lock the i'th cubemap surface
        LPDIRECT3DSURFACE8 pCubeMapFace;
        (*ppCubeMap)->GetCubeMapSurface( (D3DCUBEMAP_FACES)i, 0, &pCubeMapFace );

        // Write the RGBA-encoded normals to the surface pixels
        DWORD*      pPixel = pSourceBits;
        D3DXVECTOR3 n;
        FLOAT       w, h;

        for( DWORD y = 0; y < dwSize; y++ )
        {
            h  = (FLOAT)y / (FLOAT)(dwSize-1);  // 0 to 1
            h  = ( h * 2.0f ) - 1.0f;           // -1 to 1
            
            for( DWORD x = 0; x < dwSize; x++ )
            {
                w = (FLOAT)x / (FLOAT)(dwSize-1);   // 0 to 1
                w = ( w * 2.0f ) - 1.0f;            // -1 to 1

                // Calc the normal for this texel
                switch( i )
                {
                    case D3DCUBEMAP_FACE_POSITIVE_X:    // +x
                        n.x = +1.0;
                        n.y = -h;
                        n.z = -w;
                        break;
                        
                    case D3DCUBEMAP_FACE_NEGATIVE_X:    // -x
                        n.x = -1.0;
                        n.y = -h;
                        n.z = +w;
                        break;
                        
                    case D3DCUBEMAP_FACE_POSITIVE_Y:    // y
                        n.x = +w;
                        n.y = +1.0;
                        n.z = +h;
                        break;
                        
                    case D3DCUBEMAP_FACE_NEGATIVE_Y:    // -y
                        n.x = +w;
                        n.y = -1.0;
                        n.z = -h;
                        break;
                        
                    case D3DCUBEMAP_FACE_POSITIVE_Z:    // +z
                        n.x = +w;
                        n.y = -h;
                        n.z = +1.0;
                        break;
                        
                    case D3DCUBEMAP_FACE_NEGATIVE_Z:    // -z
                        n.x = -w;
                        n.y = -h;
                        n.z = -1.0;
                        break;
                }

                // Store the normal as an RGBA color
                D3DXVec3Normalize( &n, &n );
                *pPixel++ = VectorToRGBA( &n );
            }
        }
        
        // Swizzle the result into the cubemap face surface
        D3DLOCKED_RECT lock;
        pCubeMapFace->LockRect( &lock, 0, 0L );
        XGSwizzleRect( pSourceBits, 0, NULL, lock.pBits, dwSize, dwSize,
                       NULL, sizeof(DWORD) );
        pCubeMapFace->UnlockRect();

        // Release the cubemap face
        pCubeMapFace->Release();
    }

    // Free temp space
    if( pSourceBits )
		delete [] pSourceBits;
	pSourceBits = NULL;

    return true;
}


#endif // VV_LIGHTING