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

#ifdef GD_D3D10

#include <Darkstar/Resource System/Model/index_buffer_d3d10.hpp>
#include <Darkstar/Kernel/logh.hpp>
#include <Darkstar/Graphic System/Direct3D/graphicDriver.hpp>

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

IndexBuffer::IndexBuffer()
{
	buffer = NULL;
	buf_size = 0;
	ind_count = 0;
};

IndexBuffer::IndexBuffer(const unsigned int ind_count, const IBTYPE& type, const DEUSAGE& usage /* = DEU_DYNAMIC */)
{
	buffer = NULL;
	create(ind_count, type, usage);
};

IndexBuffer::~IndexBuffer()
{
	if(buffer)
	{
		if(FAILED(buffer->Release()))
		{
			lwar << "Cannot release index buffer";
			return;
		};
		buffer = NULL;
	};
};

bool IndexBuffer::create(const unsigned int ind_count, const IBTYPE& type, const DEUSAGE& usage /* = DEU_DYNAMIC */)
{
	if(buffer)
	{
		lwar << "Index buffer have already created";
		return false;
	};
	DEUSAGE new_usage = usage;
	if(usage == DEU_DEFAULT)
	{
		lwar << "Cannot create index buffer with cpu access write and default usage. Usage will be set to dynamic";
		new_usage = DEU_DYNAMIC;
	};
	buf_size = type == DSEIB_16 ? ind_count << 1 : ind_count << 2;
	D3D10_BUFFER_DESC buf_desc;
	buf_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
	buf_desc.ByteWidth = buf_size;
	buf_desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
	buf_desc.MiscFlags = 0;
	buf_desc.Usage = (D3D10_USAGE)new_usage;
	if(FAILED(GraphicDriver::ptr()->getDevice()->CreateBuffer(&buf_desc, NULL, &buffer)))
	{
		lwar << "Cannot create index buffer with ind_count = " << ind_count << " and type = " << type;
		return false;
	};
	this->ind_count = ind_count;
	buf_type = type;
	return true;
};

bool IndexBuffer::createWithData(const unsigned int ind_count, const IBTYPE& type, void* data, const DEUSAGE& usage /* = DEU_DEFAULT */)
{
	if(buffer)
	{
		lwar << "Index buffer have already created";
		return false;
	};
	buf_size = type == DSEIB_16 ? ind_count << 1 : ind_count << 2;
	D3D10_BUFFER_DESC buf_desc;
	buf_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
	buf_desc.ByteWidth = buf_size;
	buf_desc.CPUAccessFlags = 0;
	buf_desc.MiscFlags = 0;
	buf_desc.Usage = (D3D10_USAGE)usage;
	D3D10_SUBRESOURCE_DATA sub_rs_data;
	sub_rs_data.pSysMem = data;
	if(FAILED(GraphicDriver::ptr()->getDevice()->CreateBuffer(&buf_desc, &sub_rs_data, &buffer)))
	{
		lwar << "Cannot create index buffer with ind_count = " << ind_count << " and type = " << type;
		return false;
	};
	this->ind_count = ind_count;
	buf_type = type;
	return true;
};

bool IndexBuffer::upload(const unsigned int size, void* data, const unsigned int offset)
{
	if(!buffer)
	{
		lwar << "Cannot upload uninitialized buffer";
		return false;
	};
	unsigned int up_size = size;
	if(size == 0)
		up_size = buf_size;
	void* ptr;
	if(!(ptr = map(DEMT_WRITE_DISCARD)))
	{
		lwar << "Cannot map index buffer";
		return false;
	};
	memcpy((char*)ptr + offset, (char*)data, up_size);
	unmap();
	return true;
};

void* IndexBuffer::map(const DEMAPTYPE& map_type)
{
	void* ptr;
	if(FAILED(buffer->Map((D3D10_MAP)map_type, 0, &ptr)))
	{
		lwar << "Cannot map index buffer";
		return NULL;
	};
	return ptr;
};

void IndexBuffer::unmap()
{
	buffer->Unmap();
};

const unsigned int IndexBuffer::getIndicesNumber() const
{
	return ind_count;
};

void IndexBuffer::set()
{
	GraphicDriver::ptr()->getDevice()->IASetIndexBuffer(buffer, (DXGI_FORMAT)buf_type, 0);
};

#endif