#include "PhysicsRenderer.h"
#include "DeviceStateManager.h"
#include "BufferManager.h"

PhysicsRenderer::PhysicsRenderer(DeviceStateManager* const device) : m_pDevice(device), 
	m_pVSTransform(device->GetShaderManager()->CreateVS("..\\Shaders\\transformcolored.vsh")), 
	m_pPSColor(device->GetShaderManager()->CreatePS("..\\Shaders\\vertexcolor.psh")),
	m_VB(device->GetBufferManager()->CreateDynamicVB(2048))
{
	
}

PhysicsRenderer::~PhysicsRenderer(void)
{
	if(m_pVSTransform)
		m_pVSTransform->Release();

	if(m_pPSColor)
		m_pPSColor->Release();

	if(m_VB)
		m_VB->Release();
}

void PhysicsRenderer::Invalidate(void)
{
	//m_VB.Invalidate();
}

void PhysicsRenderer::Restore(void)
{
	//m_VB.Restore();
}

void PhysicsRenderer::RenderData(const NxDebugRenderable* data, const Camera& cam)
{
	if(!data || !m_pVSTransform || !m_pPSColor)
		return;

	m_pDevice->SetZFunc(CMP_LESSEQUAL);
	m_pDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE);

	m_pDevice->SetVertexShader(m_pVSTransform);
	m_pDevice->SetPixelShader(m_pPSColor);
	
	D3DXMATRIX matWVP;
	D3DXMatrixMultiply(&matWVP, (D3DXMATRIX*)&cam.GetViewMatrix(), (D3DXMATRIX*)&cam.GetProjMatrix());
	D3DXMatrixTranspose(&matWVP, &matWVP);
	m_pDevice->GetDevice()->SetVertexShaderConstantF(0, (float*)&matWVP, 4);

	m_pDevice->SetWorldMatrix(DXMatrix::IDENTITY());

	struct ColorVertex
	{
		DXVector3 pos;
		D3DXCOLOR	col;
	};

	unsigned int nPoints = data->getNbPoints();
	if(nPoints)
	{
		int maxRender = nPoints < MAXRENDERPATCH ? nPoints : MAXRENDERPATCH;

		ColorVertex* vb = (ColorVertex*)m_VB->LockVB(maxRender * sizeof(ColorVertex));

		const NxDebugPoint* points = data->getPoints();
		while(nPoints--)
		{
			vb->pos.x = points->p.x;
			vb->pos.y = points->p.y;
			vb->pos.z = points->p.z;
			vb->col = points->color;
			vb++;

			points++;

			if(!--maxRender && nPoints)
			{
				m_VB->UnlockVB();
				m_VB->SetVBStream(sizeof(ColorVertex), 0);

				m_pDevice->DrawPrimitive(PT_POINTLIST, 0, MAXRENDERPATCH);

				maxRender = nPoints < MAXRENDERPATCH ? nPoints : MAXRENDERPATCH;

				vb = (ColorVertex*)m_VB->LockVB(maxRender * sizeof(ColorVertex));
			}
		}

		m_VB->UnlockVB();
		m_VB->SetVBStream(sizeof(ColorVertex), 0);

		m_pDevice->DrawPrimitive(PT_POINTLIST, 0, data->getNbPoints() % MAXRENDERPATCH);
	}

	unsigned int nLines = data->getNbLines();
	if(nLines)
	{
		int maxRender = nLines < MAXRENDERPATCH ? nLines : MAXRENDERPATCH;

		ColorVertex* vb = (ColorVertex*)m_VB->LockVB(maxRender * sizeof(ColorVertex) * 2);

		const NxDebugLine* lines = data->getLines();
		while(nLines--)
		{
			vb->pos.x = lines->p0.x;
			vb->pos.y = lines->p0.y;
			vb->pos.z = lines->p0.z;
			vb->col = lines->color;
			vb++;

			vb->pos.x = lines->p1.x;
			vb->pos.y = lines->p1.y;
			vb->pos.z = lines->p1.z;
			vb->col = lines->color;
			vb++;

			lines++;

			if(!--maxRender && nLines)
			{
				m_VB->UnlockVB();
				m_VB->SetVBStream(sizeof(ColorVertex), 0);

				m_pDevice->DrawPrimitive(PT_LINELIST, 0, MAXRENDERPATCH);

				maxRender = nLines < MAXRENDERPATCH ? nLines : MAXRENDERPATCH;

				vb = (ColorVertex*)m_VB->LockVB(maxRender * sizeof(ColorVertex) * 2);
			}
		}

		m_VB->UnlockVB();
		m_VB->SetVBStream(sizeof(ColorVertex), 0);

		m_pDevice->DrawPrimitive(PT_LINELIST, 0, data->getNbLines() % MAXRENDERPATCH);
	}

	unsigned int nTris = data->getNbTriangles();
	if(nTris)
	{
		int maxRender = nTris < MAXRENDERPATCH ? nTris : MAXRENDERPATCH;

		ColorVertex* vb = (ColorVertex*)m_VB->LockVB(maxRender * sizeof(ColorVertex) * 3);

		const NxDebugTriangle* triangles = data->getTriangles();
		while(nTris--)
		{
			vb->pos.x = triangles->p0.x;
			vb->pos.y = triangles->p0.y;
			vb->pos.z = triangles->p0.z;
			vb->col = triangles->color;
			vb++;

			vb->pos.x = triangles->p1.x;
			vb->pos.y = triangles->p1.y;
			vb->pos.z = triangles->p1.z;
			vb->col = triangles->color;
			vb++;

			vb->pos.x = triangles->p2.x;
			vb->pos.y = triangles->p2.y;
			vb->pos.z = triangles->p2.z;
			vb->col = triangles->color;
			vb++;

			triangles++;

			if(!--maxRender && nTris)
			{
				m_VB->UnlockVB();
				m_VB->SetVBStream(sizeof(ColorVertex), 0);

				m_pDevice->DrawPrimitive(PT_TRIANGLELIST, 0, MAXRENDERPATCH);

				maxRender = nTris < MAXRENDERPATCH ? nTris : MAXRENDERPATCH;

				vb = (ColorVertex*)m_VB->LockVB(maxRender * sizeof(ColorVertex) * 3);
			}
		}

		m_VB->UnlockVB();
		m_VB->SetVBStream(sizeof(ColorVertex), 0);
		
		m_pDevice->DrawPrimitive(PT_TRIANGLELIST, 0, data->getNbTriangles() % MAXRENDERPATCH);
	}
/*
	unsigned int NbPoints = data->getNbPoints();
	if(NbPoints)
	{
		float* pVertList = new float[NbPoints*3];
    	float* pColorList = new float[NbPoints*4];
    	int vertIndex = 0;
    	int colorIndex = 0;
		const NxDebugPoint* Points = data.getPoints();
		while(NbPoints--)
		{
        	pVertList[vertIndex++] = Points->p.x;
        	pVertList[vertIndex++] = Points->p.y;
        	pVertList[vertIndex++] = Points->p.z;
        	pColorList[colorIndex++] = (float)((Points->color>>16)&0xff)/255.0f;
        	pColorList[colorIndex++] = (float)((Points->color>>8)&0xff)/255.0f;
        	pColorList[colorIndex++] = (float)(Points->color&0xff)/255.0f;
        	pColorList[colorIndex++] = 1.0f;
	      	Points++;
		}
		
		renderBuffer(pVertList, pColorList, GL_POINTS, data.getNbPoints());
    	
    	delete[] pVertList;
    	delete[] pColorList;
	}

	unsigned int NbLines = data.getNbLines();
	if(NbLines)
	{
		float* pVertList = new float[NbLines*3*2];
    	float* pColorList = new float[NbLines*4*2];
    	int vertIndex = 0;
    	int colorIndex = 0;
		const NxDebugLine* Lines = data.getLines();
		while(NbLines--)
		{
        	pVertList[vertIndex++] = Lines->p0.x;
        	pVertList[vertIndex++] = Lines->p0.y;
        	pVertList[vertIndex++] = Lines->p0.z;
        	pColorList[colorIndex++] = (float)((Lines->color>>16)&0xff)/255.0f;
        	pColorList[colorIndex++] = (float)((Lines->color>>8)&0xff)/255.0f;
        	pColorList[colorIndex++] = (float)(Lines->color&0xff)/255.0f;
        	pColorList[colorIndex++] = 1.0f;

        	pVertList[vertIndex++] = Lines->p1.x;
        	pVertList[vertIndex++] = Lines->p1.y;
        	pVertList[vertIndex++] = Lines->p1.z;
        	pColorList[colorIndex++] = (float)((Lines->color>>16)&0xff)/255.0f;
        	pColorList[colorIndex++] = (float)((Lines->color>>8)&0xff)/255.0f;
        	pColorList[colorIndex++] = (float)(Lines->color&0xff)/255.0f;
        	pColorList[colorIndex++] = 1.0f;

	      	Lines++;
		}
		
		renderBuffer(pVertList, pColorList, GL_LINES, data.getNbLines()*2);
    	
    	delete[] pVertList;
    	delete[] pColorList;
	}

	unsigned int NbTris = data.getNbTriangles();
	if(NbTris)
	{
		float* pVertList = new float[NbTris*3*3];
    	float* pColorList = new float[NbTris*4*3];
    	int vertIndex = 0;
    	int colorIndex = 0;
		const NxDebugTriangle* Triangles = data.getTriangles();
		while(NbTris--)
		{
        	pVertList[vertIndex++] = Triangles->p0.x;
        	pVertList[vertIndex++] = Triangles->p0.y;
        	pVertList[vertIndex++] = Triangles->p0.z;

        	pVertList[vertIndex++] = Triangles->p1.x;
        	pVertList[vertIndex++] = Triangles->p1.y;
        	pVertList[vertIndex++] = Triangles->p1.z;

        	pVertList[vertIndex++] = Triangles->p2.x;
        	pVertList[vertIndex++] = Triangles->p2.y;
        	pVertList[vertIndex++] = Triangles->p2.z;

			for(int i=0;i<3;i++)
			{
        		pColorList[colorIndex++] = (float)((Triangles->color>>16)&0xff)/255.0f;
        		pColorList[colorIndex++] = (float)((Triangles->color>>8)&0xff)/255.0f;
        		pColorList[colorIndex++] = (float)(Triangles->color&0xff)/255.0f;
        		pColorList[colorIndex++] = 1.0f;
			}

	      	Triangles++;
		}
		
		renderBuffer(pVertList, pColorList, GL_TRIANGLES, data.getNbTriangles()*3);
  	
    	delete[] pVertList;
    	delete[] pColorList;
	}

	glPopAttrib();*/
}
