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

#ifdef GD_D3D10

#include <Darkstar/Resource System/Textures/loadableTexture.hpp>
#include <Darkstar/Kernel/logh.hpp>
#include <Darkstar/Graphic System/Direct3D/graphicDriver.hpp>
#include <Darkstar/math.hpp>
#include <ddraw.h>

using namespace ker;
using namespace rs_private;
using namespace rs;

LoadableTexture::LoadableTexture() : BaseTexture()
{
	texture = NULL;
};

LoadableTexture::~LoadableTexture()
{
	if(texture)
	{
		if(FAILED(texture->Release()))
		{
			lwar << "Cannot release texture with width: " << width << " height: " << height << " pixel format: " << pixel_format;
			return;
		};
		texture = NULL;
	};
	if(srv)
	{
		if(FAILED(srv->Release()))
		{
			lwar << "Cannot release shader resource view";
			return;
		};
		srv = NULL;
	};
};

DWORD LoadableTexture::_getConvertedColor(const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha) const
{
	return DWORD(red + (green << 8) + (blue << 16) + (alpha << 24));
};

void LoadableTexture::_setCorrectConvertedFormat()
{
	pixel_format = DFMT_R8G8B8A8_UNORM;
};

rs::DSEFORMAT LoadableTexture::_tryToSetSpecificPlatfromPixelFormat(const bool is_signed, const unsigned int bpp)
{
	if(!is_signed && masks.amask == 0xff000000 && masks.bmask == 0x00ff0000 && masks.gmask == 0x0000ff00 && masks.rmask == 0x000000ff)
		return rs::DFMT_R8G8B8A8_UNORM;
	return rs::DFMT_UNKNOWN;
};

bool LoadableTexture::_makeProxyTexture(const std::string& filename)
{
	lwar << "Try to create proxy texture for file: " << filename;
	width = 2;
	height = 2;
	depth = 1;
	pixel_format = DFMT_B8G8R8A8_UNORM;
	mip_count = 1;
	unsigned char data[16];
	for(unsigned int i = 0; i < 16; i += 4)
	{
		data[i] = 255;
		data[i+1] = 0;
		data[i+2] = 255;
		data[i+3] = 0;
	};
	D3D10_TEXTURE2D_DESC texdesc;
	D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
	_fillD3DStructures<D3D10_TEXTURE2D_DESC, D3D10_TEX2D_SRV>(texdesc, srv_desc.Texture2D);
	texdesc.ArraySize = 1;
	texdesc.SampleDesc.Count = 1;
	texdesc.SampleDesc.Quality = 0;

	D3D10_SUBRESOURCE_DATA sub_data;
	sub_data.pSysMem = data;
	sub_data.SysMemPitch = 8;
	ID3D10Texture2D* tex;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateTexture2D(&texdesc, &sub_data, &tex)))
	{
		lerr << "Cannot create dummy texture";
		return false;
	};
	texture = tex;
	srv_desc.Format = (DXGI_FORMAT)pixel_format;
	srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateShaderResourceView(texture, &srv_desc, &srv)))
	{
		lwar << "Cannot create shader resource view for dummy texture";
		return false;
	};
	lwar << "Will be use proxy texture for file: " << filename;
	return true;
};

template <typename T, typename S>
void LoadableTexture::_fillD3DStructures(T& tex, S& srv)
{
	tex.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	tex.CPUAccessFlags = 0;
	tex.Format = (DXGI_FORMAT)pixel_format;
	tex.Height = height;
	tex.Width = width;
	tex.MipLevels = mip_count;
	tex.MiscFlags = 0;
	tex.Usage = D3D10_USAGE_DEFAULT;
	
	srv.MipLevels = mip_count;
	srv.MostDetailedMip = 0;
};

bool LoadableTexture::_createTexture2D(const shared_array<DSUBRES_DATA>& sub_data)
{
	D3D10_TEXTURE2D_DESC tex_desc;
	D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;

	_fillD3DStructures<D3D10_TEXTURE2D_DESC, D3D10_TEX2D_SRV>(tex_desc, srv_desc.Texture2D);
	tex_desc.ArraySize = 1;
	tex_desc.SampleDesc.Count = 1;
	tex_desc.SampleDesc.Quality = 0;

	ID3D10Texture2D* tex;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateTexture2D(&tex_desc, (D3D10_SUBRESOURCE_DATA*)sub_data.get(), &tex)))
	{
		lwar << "Cannot create texture";
		return false;
	};
	texture = tex;
	srv_desc.Format = (DXGI_FORMAT)pixel_format;
	srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateShaderResourceView(tex, &srv_desc, &srv)))
	{
		lwar << "Cannot create shader resource view";
		return false;
	};
	return true;
};

bool LoadableTexture::_createTextureCube(const shared_array<DSUBRES_DATA>& sub_data)
{
	D3D10_TEXTURE2D_DESC tex_desc;
	D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
	_fillD3DStructures<D3D10_TEXTURE2D_DESC, D3D10_TEXCUBE_SRV>(tex_desc, srv_desc.TextureCube);
	tex_desc.ArraySize = 6;
	tex_desc.MiscFlags = D3D10_RESOURCE_MISC_TEXTURECUBE;
	tex_desc.SampleDesc.Count = 1;
	tex_desc.SampleDesc.Quality = 0;

	ID3D10Texture2D* tex = NULL;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateTexture2D(&tex_desc, (D3D10_SUBRESOURCE_DATA*)sub_data.get(), &tex)))
	{
		lwar << "Cannot create texture";
		return false;
	};
	texture = tex;
	srv_desc.Format = (DXGI_FORMAT)pixel_format;
	srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURECUBE;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateShaderResourceView(tex, &srv_desc, &srv)))
	{
		lwar << "Cannot create shader resource view";
		return false;
	};
	return true;
};

bool LoadableTexture::_createTextureVolume(const shared_array<DSUBRES_DATA>& sub_data)
{
	D3D10_TEXTURE3D_DESC tex_desc;
	D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
	_fillD3DStructures<D3D10_TEXTURE3D_DESC, D3D10_TEX3D_SRV>(tex_desc, srv_desc.Texture3D);
	tex_desc.Depth = depth;

	ID3D10Texture3D* tex;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateTexture3D(&tex_desc, (D3D10_SUBRESOURCE_DATA*)sub_data.get(), &tex)))
	{
		lwar << "Cannot create volume texture";
		return false;
	};
	texture = tex;
	srv_desc.Format = (DXGI_FORMAT)pixel_format;
	srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE3D;
	if(FAILED(gs::GraphicDriver::ptr()->getDevice()->CreateShaderResourceView(tex, &srv_desc, &srv)))
	{
		lwar << "Cannot create shader resource view";
		return false;
	};
	return true;
};	

#endif