//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2007-2008)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: input_layout_d3d9.cpp
//      Краткое описание: input layout under the DirectX 9 platform
//

#ifdef GD_D3D9

#include <Darkstar/Resource System/Model/input_layout_d3d9.hpp>
#include <Darkstar/Graphic System/direct3D.hpp>
#include <Darkstar/Kernel/logh.hpp>

using namespace rs;
using namespace gs;
using ker::Log;

InputLayout::InputLayout()
{
	decl = NULL;
}

InputLayout::~InputLayout()
{
	if(decl)
	{
		if(FAILED(decl->Release()))
		{
			lwar << "Cannot release vertex declaration";
			return;
		};
		decl = NULL;
	}
}

D3DDECLTYPE _getCorrectType(const DSEFORMAT& format)
{
	switch(format)
	{
	case DFMT_R32_FLOAT:
		{
			return D3DDECLTYPE_FLOAT1;
		};break;
	case DFMT_R32G32_FLOAT:
		{
			return D3DDECLTYPE_FLOAT2;
		};break;
	case DFMT_R32G32B32_FLOAT:
		{
			return D3DDECLTYPE_FLOAT3;
		};break;
	case DFMT_R32G32B32A32_FLOAT:
		{
			return D3DDECLTYPE_FLOAT4;
		};break;
	default:
		{
			return D3DDECLTYPE_UNUSED;
		};break;
	};
};

bool _getUsage(const std::string& usage, D3DDECLUSAGE& dusage)
{
	if(usage == "POSITION")
	{
		dusage = D3DDECLUSAGE_POSITION;
		return true;
	};
	if(usage == "NORMAL")
	{
		dusage = D3DDECLUSAGE_NORMAL;
		return true;
	};
	if(usage == "TEXCOORD")
	{
		dusage = D3DDECLUSAGE_TEXCOORD;
		return true;
	};
	if(usage == "TANGENT")
	{
		dusage = D3DDECLUSAGE_TANGENT;
		return true;
	};
	if(usage == "BINORMAL")
	{
		dusage = D3DDECLUSAGE_BINORMAL;
		return true;
	};
	return false;
};

std::vector<D3DVERTEXELEMENT9> InputLayout::_getD3DElements()
{
	std::vector<D3DVERTEXELEMENT9> elems;
	for(unsigned int i = 0; i < (unsigned int)elements.size(); ++i)
	{
		D3DVERTEXELEMENT9 new_elem;
		new_elem.Method = D3DDECLMETHOD_DEFAULT;
		new_elem.Stream = elements[i].stream;
		new_elem.Offset = elements[i].offset;
		D3DDECLUSAGE dusage;
		if(!_getUsage(elements[i].usage, dusage))
		{
			lwar << "Not correct usage field " << elements[i].usage;
			continue;
		};
		new_elem.Usage = dusage;
		new_elem.UsageIndex = elements[i].usage_index;
		new_elem.Type = _getCorrectType(elements[i].format);
		elems.push_back(new_elem);
	};
	D3DVERTEXELEMENT9 last_elem = D3DDECL_END();
	elems.push_back(last_elem);
	return elems;
};

bool InputLayout::create(const void* compiled_shader_code, const unsigned int code_size)
{
	if(decl)
	{
		lwar << "Vertex declaration have already created";
		return false;
	};
	if(elements.empty())
	{
		lwar << "Cannot create vertex declaration. Vector of elements is empty";
		return false;
	};
	std::vector<D3DVERTEXELEMENT9> d3d_elements = _getD3DElements();
	unsigned int num_elements = static_cast<unsigned int>(d3d_elements.size());
	if(FAILED(GraphicDriver::ptr()->getDevice()->CreateVertexDeclaration(&d3d_elements[0], &decl)))
	{
		lwar << "Cannot create input layout";
		return false;
	};
	elements.clear();
	return true;
};

void InputLayout::set()
{
	GraphicDriver::ptr()->getDevice()->SetVertexDeclaration(decl);
};

#endif