#include "brush.h"
#include "baseentity.h"
#include "physics.h"
#include "rendering.h"
#include "tier0/platform.h"
#include "tier1/utlbuffer.h"
#include "tier1/utlvector.h"
#include "math3d.h"

void CBrushEntity::Precache()
{

}

void CBrushEntity::Spawn()
{
	/* physics don't support unindexed meshes, so generate indicies */
	CUtlBuffer<uint32_t> indicies(m_mesh.GetSize()*3);
	for (uint32_t i = 0;i<indicies.GetSize();i++)
	{
		indicies[i]=i;
	}
	/* copy over the triangles to a separate buffer, which will be used by physics */
	CUtlBuffer<Point<float>> triangles(m_mesh.GetSize()*3);
	uint32_t i = 0;
	for (auto tri: m_mesh)
	{
		V_memcpy(&triangles[i],tri.location,36);
		i+=3;
	}
	/* use them */
	px_collider_params params = {};
	params.friction = 0.0;
	m_collider = px_trimesh((Point<float>*)triangles.GetMemory(), triangles.GetSize(), (uint32_t(*)[3])indicies.GetMemory(), indicies.GetSize()/3 ,params);
	px_fixedbody(px, m_collider);
};

void CBrushEntity::Destroy()
{

}
void CBrushEntity::Think( float fDelta )
{

};

void CBrushEntity::ReadParameter( const char *szName, const char *szValue )
{
	CBaseEntity::ReadParameter(szName, szValue);
};


void C_BrushEntity::Precache()
{
	CBrushEntity* pBrushEntity = dynamic_cast<CBrushEntity*>(pEntity);
	if (!pBrushEntity)
		Plat_FatalErrorFunc("pEntity is not a CBrushEntity");
}

void C_BrushEntity::Spawn()
{
	struct Vertex_t
	{
		float position[3];
		float uv[2];
	};

	CBrushEntity* pBrushEntity = (CBrushEntity*)pEntity;
	uint32_t numVertices = 15*pBrushEntity->m_mesh.GetSize();
	
	vertexBuffer = IRenderer::CreateVertexBuffer(numVertices*4);

	Vertex_t *pTriangles = (Vertex_t*)vertexBuffer->Map();
	uint32_t i = 0;
	for (auto &triangle: pBrushEntity->m_mesh)
	{
		pTriangles[i].position[0] = triangle.location[0];
		pTriangles[i].position[1] = triangle.location[1];
		pTriangles[i].position[2] = triangle.location[2];
		pTriangles[i].uv[0] = triangle.uv[0];
		pTriangles[i].uv[1] = triangle.uv[1];
		pTriangles[i+1].position[0] = triangle.location[3];
		pTriangles[i+1].position[1] = triangle.location[4];
		pTriangles[i+1].position[2] = triangle.location[5];
		pTriangles[i+1].uv[0] = triangle.uv[2];
		pTriangles[i+1].uv[1] = triangle.uv[3];
		pTriangles[i+2].position[0] = triangle.location[6];
		pTriangles[i+2].position[1] = triangle.location[7];
		pTriangles[i+2].position[2] = triangle.location[8];
		pTriangles[i+2].uv[0] = triangle.uv[4];
		pTriangles[i+2].uv[1] = triangle.uv[5];
		i+=3;
	}
	vertexBuffer->Unmap();
};

void C_BrushEntity::Destroy()
{

}
void C_BrushEntity::Think( float fDelta )
{
	mat4 matrix;
	glm_mat4_zero(matrix);
	for (int i = 0; i < 9; i++) {
			matrix[i/3][i%3] = pEntity->m_matrix[i/3][i%3];
	}
	matrix[3][3] = 1;
	matrix[3][0] = pEntity->m_position[0];
	matrix[3][1] = pEntity->m_position[1];
	matrix[3][2] = pEntity->m_position[2];
};
	
IGraphicsPipeline *g_BrushPipeline;

class CBrushRendering: public IRenderingPipelineStep
{
public:
	virtual void Init() override;
	virtual void Frame( float fDelta ) override;
	virtual void Deinit() override;
private:
};
DECLARE_MESH_RENDERING_STAGE(CBrushRendering, brush_rasterizer);

CUtlVector<IVertexBuffer*> g_BrushVertices;

void CBrushRendering::Init()
{
	V_printf("cool\n");
	IRenderer::CreateGraphicsPipeline(
			{
			{"shaders/brush_vert.spv", SHADER_TYPE_VERTEX},
			{"shaders/brush_frag.spv", SHADER_TYPE_FRAGMENT},
			},
			{}, 64, 
			{EImageFormat::IMAGE_FORMAT_R8G8B8A8}
			);
};

void CBrushRendering::Frame( float fDelta )
{
	V_printf("cooll\n");
	IRenderer::ResetState();
	IRenderer::SetDepthMode(DEPTH_MODE_LESS_EQUAL);
	IRenderer::BindPipeline(g_BrushPipeline);
	for (auto &vertices: g_BrushVertices)
	{
		IRenderer::Draw(vertices, 0);
	}
};

void CBrushRendering::Deinit()
{

};
