// LightRender.cpp: implementation of the CLightRender class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "mapeditor.h"
#include "LightRender.h"

#include "DXUtil.h"

#include "MainFrm.h"
#include "MapEditorDoc.h"
#include "MapEditorView.h"
#include <direct.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


#define D3DFVF_NOSPRITE (D3DFVF_XYZ|D3DFVF_DIFFUSE)
extern LPDIRECT3DDEVICE8	g_pD3dDev;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CLightRender::CLightRender()
{
	m_pVBSpotLightOut = NULL;
	m_pPointLight = NULL;
}

CLightRender::~CLightRender()
{

}

HRESULT CLightRender::InitDeviceObjects()
{
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	CMapEditorView* pView = (CMapEditorView*)pFrame->GetActiveView();

	_chdir( pView->m_strCurrentDir );
	m_pPointLight = new CSkinnedMesh;
	m_pPointLight->InitDeviceObjects();
	if( FAILED(m_pPointLight->LoadMeshHierarchy("Light") ) )
	{
		int k = 0;
	}

	return S_OK;
}

HRESULT CLightRender::RestoreDeviceObjects()
{
	if( FAILED( g_pD3dDev->CreateVertexBuffer( 10 * sizeof(NOSPRITE),
		0, D3DFVF_NOSPRITE, D3DPOOL_MANAGED, &m_pVBSpotLightOut ) ) )
	{
		return E_FAIL;
	}
	NOSPRITE* v;
	DWORD dwColor;
	dwColor = 0x330000FF;
	m_pVBSpotLightOut->Lock( 0, 0, (BYTE**)&v, 0 );
	int i = 0;
	for ( i = 0;i < 10;i++ )
	{
		v[i].color = dwColor;
	}
	m_pVBSpotLightOut->Unlock();
	if( FAILED( g_pD3dDev->CreateVertexBuffer( 10 * sizeof(NOSPRITE),
		0, D3DFVF_NOSPRITE, D3DPOOL_MANAGED, &m_pVBSpotLightIn ) ) )
	{
		return E_FAIL;
	}
	dwColor = 0x3300FFFF;
	m_pVBSpotLightIn->Lock( 0, 0, (BYTE**)&v, 0 );
	for ( i = 0;i < 10;i++ )
	{
		v[i].color = dwColor;
	}
	m_pVBSpotLightIn->Unlock();

	m_pPointLight->RestoreDeviceObjects();
	return S_OK;
}

HRESULT CLightRender::InvalidateDeviceObjects()
{
	SAFE_RELEASE( m_pVBSpotLightOut );
	SAFE_RELEASE( m_pVBSpotLightIn );
	m_pPointLight->InvalidateDeviceObjects();
	return S_OK;
}

HRESULT CLightRender::DeleteDeviceObjects()
{
	m_pPointLight->DeleteDeviceObjects();
	SAFE_DELETE( m_pPointLight );
	return S_OK;
}

void CLightRender::Render()
{
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	CMapEditorView* pView = (CMapEditorView*)pFrame->GetActiveView();

	list<D3DLIGHT8*>::iterator itLight = pView->m_listLightInfo.begin();
	while ( itLight != pView->m_listLightInfo.end() )
	{
		if ( (*itLight)->Type == D3DLIGHT_POINT )
		{
			D3DXMATRIX matTemp;
			D3DXMatrixIdentity( &matTemp );
			g_pD3dDev->SetTransform( D3DTS_WORLD, &matTemp );
			
			D3DXVECTOR3 vPos = (*itLight)->Position;
			D3DXMATRIX mat;

			D3DXVECTOR3 vVel = D3DXVECTOR3(0,0,1);
			D3DXVECTOR3 vUp = D3DXVECTOR3(0,1,0);
			D3DXMatrixLookAtLH( &mat, &vPos, &(vPos + vVel), &vUp );
			D3DXMatrixInverse( &mat, NULL, &mat );

			g_pD3dDev->SetRenderState( D3DRS_ZENABLE,   TRUE );
			g_pD3dDev->SetRenderState( D3DRS_LIGHTING, TRUE );
			g_pD3dDev->SetRenderState( D3DRS_ALPHABLENDENABLE,  TRUE );
			g_pD3dDev->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
			g_pD3dDev->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
			g_pD3dDev->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
	
			D3DXMATRIX matScale;
			D3DXMatrixScaling( &matScale, (*itLight)->Range, (*itLight)->Range, (*itLight)->Range );
			mat = matScale * mat;
			m_pPointLight->Tick(0.0f);
			m_pPointLight->SetWorldMatrix(mat);
			m_pPointLight->AnotherTexture(1);
			m_pPointLight->Render();
		}
		else if ( (*itLight)->Type == D3DLIGHT_SPOT )
		{
			D3DXVECTOR3 vPos = (*itLight)->Position;
			D3DXVECTOR3 vVel = (*itLight)->Direction;
			D3DXVec3Normalize( &vVel, &vVel );
			D3DXVECTOR3 vPos2 = vPos + vVel;
			
			float fAngle = (*itLight)->Theta;


			D3DXVECTOR3 vRand = D3DXVECTOR3( 5, -1, 5 );
			D3DXVec3Normalize( &vRand, &vRand );
			D3DXVECTOR3 vCross;
			D3DXVec3Cross( &vCross, &vRand, &vVel );
			D3DXMATRIX mat;
			D3DXMatrixRotationAxis( &mat, &vCross, fAngle/2.0f );
			D3DXVECTOR3 vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vVel, &mat );
			
			NOSPRITE* v;
			D3DXMatrixRotationAxis( &mat, &vVel, -D3DX_PI / 4.0f );

			m_pVBSpotLightIn->Lock( 0, 0, (BYTE**)&v, 0 );
			v[0].p = vPos;
			v[1].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[2].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[3].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[4].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[5].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[6].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[7].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[8].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[9].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			m_pVBSpotLightIn->Unlock();

			
			fAngle = (*itLight)->Phi;
			D3DXMatrixRotationAxis( &mat, &vCross, fAngle/2.0f );
			D3DXVec3TransformCoord( &vTargetVel, &vVel, &mat );
			D3DXMatrixRotationAxis( &mat, &vVel, -D3DX_PI / 4.0f );

			m_pVBSpotLightOut->Lock( 0, 0, (BYTE**)&v, 0 );
			v[0].p = vPos - vTargetVel;
			v[1].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[2].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[3].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[4].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[5].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[6].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[7].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[8].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			v[9].p = vPos + 10000.0f * vTargetVel;
			D3DXVec3TransformCoord( &vTargetVel, &vTargetVel, &mat );
			m_pVBSpotLightOut->Unlock();

			g_pD3dDev->SetTexture( 0, NULL );
			g_pD3dDev->SetRenderState( D3DRS_ZENABLE,   TRUE );
			g_pD3dDev->SetRenderState( D3DRS_LIGHTING, FALSE );
			g_pD3dDev->SetRenderState( D3DRS_ALPHABLENDENABLE,  TRUE );
			g_pD3dDev->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
			g_pD3dDev->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );

			D3DXMATRIX matTemp;
			D3DXMatrixIdentity( &matTemp );
			g_pD3dDev->SetVertexShader( D3DFVF_NOSPRITE );
			g_pD3dDev->SetTransform( D3DTS_WORLD, &matTemp );
			g_pD3dDev->SetStreamSource( 0, m_pVBSpotLightIn, sizeof(NOSPRITE) );
			g_pD3dDev->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 8 );
			g_pD3dDev->SetStreamSource( 0, m_pVBSpotLightOut, sizeof(NOSPRITE) );
			g_pD3dDev->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 8 );

		}

		itLight++;
	}
}
/*
    D3DLIGHTTYPE    Type;          
    D3DCOLORVALUE   Diffuse;       
    D3DCOLORVALUE   Specular;      
    D3DCOLORVALUE   Ambient;       
    D3DVECTOR       Position;      
    D3DVECTOR       Direction;     
    float           Range;         
    float           Falloff;       
    float           Attenuation0;  
    float           Attenuation1;  
    float           Attenuation2;  
    float           Theta;         
    float           Phi;           
*/