#include "dxstdafx.h"
#include "RTEffectsCommon.h"
#include "TransformMatrixesManager.h"

#pragma warning(push)			// Pushing a warning disabler...
#pragma warning(disable:4995)	// to disable deprecated warning...
#include <iostream>				// ..for those old C++ libs
#include <fstream>				//
using namespace std;			//
#pragma warning(pop)			// Restoring the previous warning states

#pragma once


//------------------------------------------------------------------------------------------------
// Constructor
// Load the effect and setup the basics handles (world matrix,etc)
//------------------------------------------------------------------------------------------------
RTEffectsCommon::RTEffectsCommon(LPCWSTR filePath)
{
	// Retrieve a pointer to the transform matrix manager
	m_pTransMatMgr = TransformMatrixesManager::GetInstance();

	// Nullify the common handles
	m_pEffect = NULL;
	m_hMatWorld =
	m_hMatWorldView =
	m_hMatProj =
	m_hMatPreviousWVP = NULL;

	// Compile the effect using the filePath parameter
	if( SUCCEEDED(CompileEffect(filePath)) ) // FAILURE
	{
		// Creating the basic handles
		SetupCommonHandles();		
	}
}


//--------------------------------------------------------------------------------------
// Destructor
//--------------------------------------------------------------------------------------
RTEffectsCommon::~RTEffectsCommon()
{
	// Release the effect
	SAFE_RELEASE(m_pEffect);
}


//--------------------------------------------------------------------------------------
// Compile an effect file and store the binary code in m_pEffect
// Return a log file with error compilation messages if some problems are detected
//--------------------------------------------------------------------------------------
HRESULT RTEffectsCommon::CompileEffect(LPCWSTR filePath)
{
	// Flushing the current effect
	SAFE_RELEASE(m_pEffect);

	// Load the effect
	ID3DXBuffer *pBuffer = NULL; //to store the compilation error messages
	if(FAILED(D3DXCreateEffectFromFile(DXUTGetD3DDevice(), filePath, NULL, NULL, D3DXFX_NOT_CLONEABLE|D3DXSHADER_PREFER_FLOW_CONTROL, NULL, &m_pEffect, &pBuffer)))
	{
		// Dumping message if there are some
		if(pBuffer != NULL)
		{
			ofstream fileStream("shader_dump.txt");
			fileStream << "Failed compiling shader\n";
			char * compileString = (char*)(pBuffer->GetBufferPointer());
			for(unsigned int i=0; i<pBuffer->GetBufferSize(); ++i)
				fileStream << compileString[i] ;

			fileStream.close();
			pBuffer->Release();
		}
		return E_FAIL;
	}

	return S_OK;
}


//--------------------------------------------------------------------------------------
// Prepare the common handles
//--------------------------------------------------------------------------------------
void RTEffectsCommon::SetupCommonHandles()
{
	// If the effect has been successfully compiled
	if(m_pEffect)
	{
		// Retrieve the handles from the shader variables names...
		m_hMatWorld = m_pEffect->GetParameterByName(NULL, "g_mWorld");
		m_hMatWorldView = m_pEffect->GetParameterByName(NULL, "g_mWorldView");
		m_hMatProj = m_pEffect->GetParameterByName(NULL, "g_mProj");

		m_hMatPreviousWVP = m_pEffect->GetParameterByName(NULL, "g_mPreviousWVP");
		
		m_hEyeWorldPos = m_pEffect->GetParameterByName(NULL, "g_vEyeWorldPos");

		m_hLightPos = m_pEffect->GetParameterByName(NULL, "g_vLightPos");
		m_hLightVect = m_pEffect->GetParameterByName(NULL, "g_vLightVect");

		m_hDiffuseTexture = m_pEffect->GetParameterByName(NULL, "g_DiffuseTex");
	}
}


//--------------------------------------------------------------------------------------
// Send World and WorldViewProj matrixes to the effect
// Compute the inverseWorldMatrix and send it to the effect
//--------------------------------------------------------------------------------------
void RTEffectsCommon::SetupEffectMatrixes()
{
	// Update the world, proj and WVP matrixes in the effect
	m_pEffect->SetMatrix(m_hMatWorld, &(m_pTransMatMgr->m_matWorld));
	m_pEffect->SetMatrix(m_hMatProj, &(m_pTransMatMgr->m_matProj));
	
	// Compute WorldView
	D3DXMATRIX temp =  (m_pTransMatMgr->m_matWorld) * (m_pTransMatMgr->m_matView);
	m_pEffect->SetMatrix(m_hMatWorldView, &temp);

	// Setup the two WVP matrixes
	m_pEffect->SetMatrix(m_hMatPreviousWVP, &(m_pTransMatMgr->m_matPreviousFrameWVP));
}


//--------------------------------------------------------------------------------------
// Setup light and eye effect data
//--------------------------------------------------------------------------------------
void RTEffectsCommon::SetupEffectLightAndObs(CDXUTDirectionWidget * pLightWidget, const D3DXVECTOR3 *pEyeWorldPos)
{
	// Compute light position and send it to the effect
	D3DXVECTOR3 vLigthPos = pLightWidget->GetLightDirection() * (pLightWidget->GetRadius());	
	m_pEffect->SetFloatArray(m_hLightPos, (CONST FLOAT*)(vLigthPos), 3);
	m_pEffect->SetFloatArray(m_hLightVect, (CONST FLOAT*)(pLightWidget->GetLightDirection()), 3);

	// Send the eye world position to the effect
	m_pEffect->SetFloatArray(m_hEyeWorldPos, (CONST FLOAT*)(*pEyeWorldPos), 3);
}


//--------------------------------------------------------------------------------------
// OnResetDevice
//--------------------------------------------------------------------------------------
HRESULT RTEffectsCommon::OnResetDevice()
{
	if(!m_pEffect) return D3DERR_INVALIDCALL;
	return (m_pEffect->OnResetDevice());
}


//--------------------------------------------------------------------------------------
// OnLostDevice
//--------------------------------------------------------------------------------------
HRESULT RTEffectsCommon::OnLostDevice()
{
	if(!m_pEffect) return D3DERR_INVALIDCALL;
	return (m_pEffect->OnLostDevice());
}