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

#ifdef GD_D3D9

#include <Darkstar/Graphic System/Direct3D/graphicDriver.hpp>
#include <Darkstar/Graphic System/Render Target/render_target_d3d9.hpp>
#include <Darkstar/Kernel/logh.hpp>

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

RenderTarget::RenderTarget()
{
	layers_number = 0;
	darkstar_texture.reset();
	texture_data_without_aa = NULL;
	width = height = 0;
};

RenderTarget::~RenderTarget()
{
	if(texture_data.size() > 0)
	{
		for(unsigned int i = 0; i < static_cast<unsigned int>(texture_data.size()); ++i)
		{
			if(texture_data[i])
			{
				if(FAILED(texture_data[i]->Release()))
				{
					lwar << "Cannot release texture";
					return;
				};
				if(texture_data[i] == texture_data_without_aa)
					texture_data_without_aa = NULL;
				texture_data[i] = NULL;
			};
		};
	};
	if(texture_data_without_aa)
	{
		if(FAILED(texture_data_without_aa->Release()))
		{
			lwar << "Cannot release texture";
			return;
		};
		texture_data_without_aa = NULL;
	};
};

shared_ptr<BaseTexture> RenderTarget::getTexture() const
{
	return darkstar_texture;
};

bool RenderTarget::create2D(const unsigned int width, const unsigned int height, const DRTFORMAT& format, 
							const DRTAATYPE& aa_type, bool need_texture)
{
	IDirect3DDevice9* device = GraphicDriver::ptr()->getDevice();

	texture_data.resize(1);

	if(isDepthStencilFormat(format))
	{
		if(!need_texture)
		{
			if(FAILED(device->CreateDepthStencilSurface(width, height, getSpecRTFormat(format), aa_type.count == 1 ? D3DMULTISAMPLE_NONE : (D3DMULTISAMPLE_TYPE)aa_type.count, aa_type.quality, false, &texture_data[0], NULL)))
			{
				lwar << "Cannot create depth stencil view with width = " << width << " height = " << height << " aa_type.count = " << aa_type.count << " aa_type.quality = " << aa_type.quality;
				return false;
			};
		}
		else
		{
			// NEED TO CREATE DEPTH STENCIL VIEW WITH TEXTURE
		};
	}
	else
	{
		if(need_texture)
		{
			darkstar_texture.reset(new RTTexture());
			LPDIRECT3DTEXTURE9 tex;
			if(FAILED(device->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, getSpecRTFormat(format), 
				D3DPOOL_DEFAULT, &tex, NULL)))
			{
				lwar << "Cannot create render target with width = " << width << " height = " << height << " aa_type.count = " << aa_type.count << " aa_type.quality = " << aa_type.quality;
				return false;
			};
			if(aa_type.count == 1)
			{
				darkstar_texture->setTexture(tex);
				tex->GetSurfaceLevel(0, &texture_data[0]);
				texture_data_without_aa = texture_data[0];
			}
			else
			{
				if(FAILED(device->CreateRenderTarget(width, height, getSpecRTFormat(format), aa_type.count == 1 ? D3DMULTISAMPLE_NONE : (D3DMULTISAMPLE_TYPE)aa_type.count, aa_type.quality, 
					false, &texture_data[0], NULL)))
				{
					lwar << "Cannot create render target with width = " << width << " height = " << height << " aa_type.count = " << aa_type.count << " aa_type.quality = " << aa_type.quality;
					return false;
				};
				tex->GetSurfaceLevel(0, &texture_data_without_aa);
			};
			darkstar_texture->setTexture(tex);
		}
		else
		{
			if(FAILED(device->CreateRenderTarget(width, height, getSpecRTFormat(format), aa_type.count == 1 ? D3DMULTISAMPLE_NONE : (D3DMULTISAMPLE_TYPE)aa_type.count, aa_type.quality, 
				false, &texture_data[0], NULL)))
			{
				lwar << "Cannot create render target with width = " << width << " height = " << height << " aa_type.count = " << aa_type.count << " aa_type.quality = " << aa_type.quality;
				return false;
			};
		};
	};
	this->aa_type = aa_type;
	this->format = format;
	this->width = width;
	this->height = height;
	this->need_texture = need_texture;
	layers_number = 1;
	return true;
};

bool RenderTarget::create2D(IDirect3DSurface9* rt_text)
{
	D3DSURFACE_DESC desc;
	if(FAILED(rt_text->GetDesc(&desc)))
	{
		lwar << "Cannot get surface description. Cannot create render target";
		return false;
	};
	layers_number = 1;
	texture_data.resize(layers_number);

	width = desc.Width;
	height = desc.Height;
	format = getDarkRTFormat(desc.Format);
	aa_type.count = desc.MultiSampleType == D3DMULTISAMPLE_NONE ? 1 : (unsigned int)desc.MultiSampleType;
	aa_type.quality = desc.MultiSampleQuality;
	need_texture = false;
	texture_data[0] = rt_text;
	return true;
};

bool RenderTarget::createCube(const unsigned int width, const unsigned int height, const DRTFORMAT& format)
{
	IDirect3DDevice9* device = GraphicDriver::ptr()->getDevice();

	if(width != height)
	{
		lwar << "Cannot create cube texture with width = " << width << " and height = " << height;
		return false;
	};

	if(isDepthStencilFormat(format))
	{
		lwar << "Cannot create cubemap with depth-stencil format";
		return false;
	};
	
	layers_number = 6;
	texture_data.resize(layers_number);

	UINT usage = D3DUSAGE_RENDERTARGET;

	IDirect3DCubeTexture9* cube_texture;
	if(FAILED(device->CreateCubeTexture(width, 1, usage, getSpecRTFormat(format), D3DPOOL_DEFAULT, &cube_texture, NULL)))
	{
		lwar << "Cannot create cube texture with width = " << width << " and height = " << height;
		return false;
	};

	for(unsigned int i = 0; i < layers_number; ++i)
		cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &texture_data[i]);

	darkstar_texture.reset(new RTTexture());
	darkstar_texture->setTexture(cube_texture);

	this->aa_type = WITHOUT_AA;
	this->format = format;
	this->width = width;
	this->height = height;
	this->need_texture = true;

	return true;
};

unsigned int RenderTarget::getWidth() const
{
	return width;
};

unsigned int RenderTarget::getHeight() const
{
	return height;
};

const DRTAATYPE& RenderTarget::getAAType() const
{
	return aa_type;
};

const DRTFORMAT& RenderTarget::getFormat() const
{
	return format;
};

bool RenderTarget::getIsNeedTexture() const
{
	return need_texture;
};

IDirect3DSurface9* RenderTarget::getDataTexture(const unsigned int layer_num) const
{
	return texture_data[layer_num];
};

IDirect3DSurface9* RenderTarget::getDataWithoutAATexture() const
{
	return texture_data_without_aa;
};

unsigned int RenderTarget::getLayersNumber() const
{
	return layers_number;
};

#endif