#pragma once

#include "DXVector3.h"

enum ATTRIBUTEMAPPING
{
	AM_UNKNOWN = 0,
	AM_TRIANGLE,
	AM_TRIANGLEINDEXED,
	AM_VERTEX,
	AM_TRIANGLEVERTEXINDEXED,
	AM_SINGLE
};

//usage for custom vertex attributes
#define D3DDECLUSAGE_CUSTOM ((D3DDECLUSAGE)0x7f)

struct MeshAttribute
{
	ATTRIBUTEMAPPING Mapping;

	//info needed to build vertex declartion
	D3DDECLUSAGE DeclUsage;
	D3DDECLTYPE DeclType; //also used to define interpolation
	D3DDECLMETHOD DeclMethod;

	MeshAttribute(const ATTRIBUTEMAPPING mapping, const D3DDECLUSAGE usage, const D3DDECLTYPE type, D3DDECLMETHOD method) 
	{ 
		Mapping = mapping; 
		DeclUsage = usage;
		DeclType = type;
		DeclMethod = method;
	}
};

class DXFUNCTIONS_API MeshContainer
{
	unsigned	m_VertexCount;
	DXVector3*	m_pVertices; //[VertexCount]
	unsigned	m_TriangleCount;
	unsigned*	m_pTriangles; //[TriangleCount * 3]

	//real size of the buffers, this maybe bigger than vertices/triangles exist, so that there is space when new ones are created
	unsigned	m_VertexBufferSize;
	unsigned	m_TriangleBufferSize;

	MeshAttribute** m_pAttributes;
	unsigned m_AttributeCount;

public:
	MeshContainer(unsigned VertexCount, DXVector3* pVertices, unsigned TriangleCount, unsigned* pTriangles);
	~MeshContainer(void);

	void AddAttribute(MeshAttribute* const pAttrib);

	unsigned GetTriangleCount(void) const { return m_TriangleCount; }
	unsigned GetVertexCount(void) const { return m_VertexCount; }

	unsigned* GetTriangles(void) const { return m_pTriangles; }
	DXVector3* GetVertices(void) const { return m_pVertices; }

	void ReallocBuffers(unsigned VertexCount, unsigned TriangleCount);
};

template <class T> struct PerTriangleAttribute : public MeshAttribute
{
	T* pAttribute; //[TriangleCount]

	PerTriangleAttribute(MeshContainer* const cont, const D3DDECLUSAGE usage, const D3DDECLUSAGE type, D3DDECLMETHOD method) : MeshAttribute(AM_TRIANGLE, usage, type, method) 
	{ 
		pAttribute = new T[cont->GetTriangleCount()]; 
	}

	~PerTriangleAttribute(void)
	{
		delete pAttribute;
	}

	T Get(const int index) { return pAttribue[index]; }
	void Set(const int index, const T& t) { pAttribute[index] = t; }
};

template <class T> struct PerTriangleIndexAttribute
{
	unsigned AttributeCount;
	T* pAttribute; //[AttributeCount]
	unsigned* pTriangleIndex; //[TriangleCount]

	PerTriangleIndexAttribute(MeshContainer* const cont, const D3DDECLUSAGE usage, const D3DDECLUSAGE type, D3DDECLMETHOD method) : MeshAttribute(AM_TRIANGLEINDEXED, usage, type, method) 
	{ 
		this->AttributeCount = AttributeCount;
		pAttribute = new T[AttributeCount]; 
		pTriangleIndex = new unsigned[cont->GetTriangleCount()];
	}

	~PerTriangleIndexAttribute(void)
	{
		delete pAttribute;
		delete pTriangleIndex;
	}
};

template <class T> struct PerVertexAttribute
{
	T* pAttribute; //[VertexCount]

	PerVertexAttribute(MeshContainer* const cont, const D3DDECLUSAGE usage, const D3DDECLUSAGE type, D3DDECLMETHOD method) : MeshAttribute(AM_VERTEX, usage, type, method) 
	{ 
		pAttribute = new T[cont->GetVertexCount()]; 
	}

	~PerVertexAttribute(void)
	{
		delete pAttribute;
	}
};

template <class T> struct PerTriangleVertexIndexedAttribute
{
	unsigned AttributeCount;
	T* pAttribute; //[AttributeCount]
	unsigned* pAttributeIndex; //[3 * TriangleCount]

	PerTriangleVertexIndexedAttribute(MeshContainer* const cont, const unsigned AttributeCount, const D3DDECLUSAGE usage, const D3DDECLUSAGE type, D3DDECLMETHOD method) : MeshAttribute(AM_TRIANGLEVERTEXINDEXED, usage, type, method) 
	{ 
		this->AttributeCount = AttributeCount;
		pAttribute = new T[AttributeCount]; 
		pAttributeIndex = new unsigned[cont->GetTriangleCount() * 3];
	}

	~PerTriangleVertexIndexedAttribute(void)
	{
		delete pAttribute;
		delete pAttributeIndex;
	}
};
template <class T> struct SingleAttribute
{
	T Attribute;

	SingleAttribute(const D3DDECLUSAGE usage, const D3DDECLUSAGE type, D3DDECLMETHOD method) : MeshAttribute(AM_SINGLE, usage, type, method) 
	{ 
	}
};

/*class RenderingMesh
{
	VertexBuffer* m_pVB;
	IndexBuffer*  m_pIB;
	VertexDeclaration*	VDecl;
	RenderJobDrawCall*   pDrawCalls;

};*/