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

#ifdef GD_D3D10

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

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

VertexStream::VertexStream()
{
	stream_size = 0;
	stream_element_size = 0;
	elems_count = 0;
	stream = NULL;
};

VertexStream::VertexStream(const unsigned int stream_elem_size, const unsigned int elems_count, const DEUSAGE& usage)
{
	stream = NULL;
	create(stream_elem_size, elems_count, usage);
};

VertexStream::~VertexStream()
{
	if(stream)
	{
		if(FAILED(stream->Release()))
			lwar << "Cannot release vertex stream";
		stream = NULL;
	};
};

bool VertexStream::create(const unsigned int stream_elem_size, const unsigned int elems_count, const DEUSAGE& usage /* = DEU_DYNAMIC */)
{
	if(stream)
	{
		lwar << "Vertex stream have already created";
		return false;
	};
	DEUSAGE new_usage = usage;
	if(usage == D3D10_USAGE_DEFAULT)
	{
		lwar << "Cannot create buffer with cpu access write and usage default. Usage will be set to dynamic";
		new_usage = DEU_DYNAMIC;
	};
	stream_size = stream_elem_size*elems_count;
	D3D10_BUFFER_DESC buf_desc;
	buf_desc.Usage = (D3D10_USAGE)new_usage;
	buf_desc.ByteWidth = stream_size;
	buf_desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
	buf_desc.MiscFlags = 0;
	buf_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	if(FAILED(GraphicDriver::ptr()->getDevice()->CreateBuffer(&buf_desc, NULL, &stream)))
	{
		lwar << "Cannot create vertex buffer";
		return false;
	};
	stream_element_size = stream_elem_size;
	this->elems_count = elems_count;
	return true;
};

bool VertexStream::createWithData(const unsigned int stream_elem_size, const unsigned int elems_count, 
								  void* data, const DEUSAGE& usage)
{
	if(stream)
	{
		lwar << "Vertex stream have already created";
		return false;
	};
	stream_size = stream_elem_size*elems_count;
	D3D10_BUFFER_DESC buf_desc;
	buf_desc.Usage = (D3D10_USAGE)usage;
	buf_desc.ByteWidth = stream_size;
	buf_desc.CPUAccessFlags = 0;
	buf_desc.MiscFlags = 0;
	buf_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	D3D10_SUBRESOURCE_DATA sub_rs_data;
	sub_rs_data.pSysMem = data;
	if(FAILED(GraphicDriver::ptr()->getDevice()->CreateBuffer(&buf_desc, &sub_rs_data, &stream)))
	{
		lwar << "Cannot create vertex buffer with data";
		return false;
	};
	stream_element_size = stream_elem_size;
	this->elems_count = elems_count;
	return true;
};

bool VertexStream::upload(const unsigned int size, void* data, const unsigned int offset)
{
	if(!stream)
	{
		lwar << "Cannot upload uninitialized vertex stream";
		return false;
	};
	void* ptr;
	unsigned int up_size = size;
	if(size == 0)
		up_size = elems_count*stream_element_size;
	if(!(ptr = map(DEMT_WRITE_DISCARD)))
	{
		lwar << "Cannot lock vertex stream";
		return false;
	};
	memcpy((char*)ptr + offset, (char*)data, up_size);
	unmap();
	return true;
};

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

void VertexStream::unmap()
{
	stream->Unmap();
}

ID3D10Buffer* VertexStream::getStream() const
{
	return stream;
};

unsigned int VertexStream::getElementSize() const
{
	return stream_element_size;
};

unsigned int VertexStream::getElementsCount() const
{
	return elems_count;
};

#endif