#include "RenderList.h"

RenderList::RenderList(void)
{
	m_AmbientLight = DXColor(0, 0, 0, 0);
	m_TexFilter = 2; //Linear
	m_TexAniso = 1;
	m_CullMode = 3; //CCW

	m_pSortedIB = NULL;
}

void RenderList::Sort(void)
{ 
	m_Clock.StartCapture(299);

	m_List.Sort(CmpJobLesser, CmpJobGreater); 

	m_Clock.EndCapture(299);
	LONGLONG rt = m_Clock.GetCaptureTime(299);

	m_Stats.SortingTime += rt / (double)m_Clock.GetTicksPerSec();
}

void RenderList::Render(DeviceStateManager* const device)
{
	m_Clock.StartCapture(199);
	
	bool needtodopasses = true;
	int currpass = 0;

	while (needtodopasses)
	{
		needtodopasses = false;

		int n = m_List.GetElementCount();

		RenderJob** pljob = m_List.GetStack();

		ShaderEffect* currEffect = NULL;
		D3DXHANDLE currTechnique = NULL;

		while (n--)
		{
			const RenderJob* const job = *pljob++;

			if (!job)
				continue;

			if (job->Effect != currEffect)
			{
				if (currEffect && currTechnique)
				{
					currEffect->End();
					currEffect->EndPass();
				}

				currEffect = job->Effect;
				currTechnique = NULL;

				//init global constants by semantic
				InitShaderParameterBySemantic(currEffect);

				m_Stats.EffectSwitches++;
			}

			if (!currEffect || !currEffect->IsCompiled())
				continue;

			int passes = 0;
			if (job->Technique != currTechnique)
			{
				if (currEffect && currTechnique)
				{
					currEffect->End();
					currEffect->EndPass();
				}			

				currTechnique = job->Technique;

				if (!currTechnique)
					continue;

				//currEffect->SetTechnique(currTechnique);
				currEffect->GetShader()->SetTechnique(currTechnique);
				m_Stats.TechniqueSwitches++;
				
				passes = currEffect->Begin();

				if (passes > currpass + 1)
					needtodopasses = true;

				currEffect->BeginPass(currpass);
			}

			//TODO do passes

			if (job->DrawCall)
			{
				job->Init();

				/*if(job->DrawCall->IB)
				{
					D3DVERTEXBUFFER_DESC vdesc;
					job->DrawCall->VB->GetDesc(&vdesc);

					D3DINDEXBUFFER_DESC idesc;
					job->DrawCall->IB->GetDesc(&idesc);
					int i = 0;
				}*/

				//if (false)
				if (job->pBSPTree)
				{
					//int h = 0;
					//if (!m_pSortedIB)
					//	m_pSortedIB = device->GetBufferManager()->CreateDynamicIB(sizeof(unsigned) * job->pBSPTree->GetRoot()->TriangleCount * 3, true);

					//job->pBSPTree->BuildIndexBuffer((void*)m_pSortedIB->LockIB(sizeof(unsigned) * job->pBSPTree->GetRoot()->TriangleCount * 3), true, m_Camera.GetPosition(), job->matWorldToMesh);
					//m_pSortedIB->UnlockIB();

					//job->DrawCall->ExecuteSorted(device, (LPDIRECT3DINDEXBUFFER9)m_pSortedIB->GetBuffer(), m_pSortedIB->GetIndexOffset() >> 2);
					job->DrawCall->Execute(device);
				}
				else
				{
					job->DrawCall->Execute(device);
				}
			}
		}

		if (currEffect && currTechnique)
		{
			currEffect->End();
			currEffect->EndPass();
		}

		currpass++;
	}

	m_Clock.EndCapture(199);
	LONGLONG rt = m_Clock.GetCaptureTime(199);

	m_Stats.RenderTime += rt / (double)m_Clock.GetTicksPerSec();

	//wlog("Effects:%d Techniques:%d Time:%d", m_EffectSwitches, m_TechniqueSwitches, m_RenderTime);
}

void RenderList::InitShaderParameterBySemantic(ShaderEffect* fx)
{
	if(!fx || !fx->IsCompiled())
		return;

	D3DXHANDLE h;

	h = fx->GetShader()->GetParameterBySemantic(NULL, "VIEWPROJ");
	if (h)
		fx->SetMatrix(h, m_Camera.GetViewProjMatrix());

	h = fx->GetShader()->GetParameterBySemantic(NULL, "INVVIEWPROJ");
	if(h)
		fx->SetMatrix(h, DXMatrix::InvertMatrix(m_Camera.GetViewProjMatrix()));

	h = fx->GetShader()->GetParameterBySemantic(NULL, "VIEW");
	if(h)
		fx->SetMatrix(h, m_Camera.GetViewMatrix());

	h = fx->GetShader()->GetParameterBySemantic(NULL, "INVVIEW");
	if(h)
		fx->SetMatrix(h, DXMatrix::InvertMatrix(m_Camera.GetViewMatrix()));

	h = fx->GetShader()->GetParameterBySemantic(NULL, "PROJ");
	if(h)
		fx->SetMatrix(h, m_Camera.GetProjMatrix());

	h = fx->GetShader()->GetParameterBySemantic(NULL, "INVPROJ");
	if(h)
		fx->SetMatrix(h, DXMatrix::InvertMatrix(m_Camera.GetProjMatrix()));

	h = fx->GetShader()->GetParameterBySemantic(NULL, "AMBIENT");
	if(h)
		fx->SetVector(h, static_cast<DXVector4>(m_AmbientLight));

	h = fx->GetShader()->GetParameterBySemantic(NULL, "CAMPOS");
	if(h)
		fx->SetFloatArray(h, (float*)&m_Camera.GetPosition(), 3);

	h = fx->GetShader()->GetParameterBySemantic(NULL, "TEXFILTER");
	if(h)
		fx->SetInt(h, m_TexFilter);

	h = fx->GetShader()->GetParameterBySemantic(NULL, "TEXANISO");
	if(h)
		fx->SetInt(h, m_TexAniso);

	h = fx->GetShader()->GetParameterBySemantic(NULL, "CULLMODE");
	if(h)
		fx->SetInt(h, m_CullMode);

	OnInitShader(fx);
}