#include "Gos.pch"
#include "Graphics.h"
#include "d3dx8.h"

GosTexture*	(*GosTexture::CreateFromFile)( TCHAR *, bool, int ) = Texture::CreateFromFile;
GosTexture*	(*GosTexture::CreateFromMemory)( LPCVOID, UINT, bool, int, int ) = Texture::CreateFromMemory;
GosTexture*	(*GosTexture::CreateEmpty)( UINT, UINT, UINT, D3DFORMAT, D3DPOOL, const TCHAR *,bool ) = Texture::CreateEmpty;

GosTexture*	(*GosTexture::CreateVolume)( UINT, UINT, UINT, UINT, D3DFORMAT ) = Texture::CreateVolume;
GosTexture*	(*GosTexture::CreateCube)( UINT, UINT, D3DFORMAT ) = Texture::CreateCube;

GosTexture* Texture::CreateFromFile( TCHAR *pName, bool CreateMip , /* D3DFORMAT */ int Format  )
{
	LOG_API("Texture::CreateFromFile");
	IDirect3DTexture8 *pD3DTexture;

	HRESULT rc = D3DXCreateTextureFromFile( Graphics::D3DDevice(), pName, &pD3DTexture );

	if( FAILED(rc) )
		STOP(("Failed to create texture from file %s",pName));

	Texture *pTexture = new Texture(pD3DTexture,mipmap);

	pTexture->SetName( pName );

	if( !pTexture )
		STOP(("Error creating a texture object"));

	return pTexture;
}

GosTexture* Texture::CreateFromMemory( LPCVOID pSrcData, UINT SrcDataSize, bool CreateMip , /* D3DFORMAT */ int Format, int Pool  )
{
	LOG_API("Texture::CreateFromMemory");;
	IDirect3DTexture8 *pD3DTexture;

    HRESULT rc = D3DXCreateTextureFromFileInMemoryEx( Graphics::D3DDevice(), pSrcData, SrcDataSize, 0, 0, ( CreateMip ? 1 : 0 ),
                                                      0, D3DFORMAT( Format ), D3DPOOL( Pool ), D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &pD3DTexture );

    if( FAILED(rc) )
		STOP(("Failed to create texture from memory"));

	Texture *pTexture = new Texture(pD3DTexture,mipmap);

	if( !pTexture )
		STOP(("Error creating a texture object"));

	return pTexture;
}

GosTexture* Texture::CreateEmpty( UINT Width, UINT Height, UINT Levels, D3DFORMAT Format, D3DPOOL Pool, const TCHAR *pName, bool fUse3D )
{
	IDirect3DTexture8 *pD3DTexture;

    HRESULT rc = Graphics::D3DDevice()->CreateTexture( Width, Height, Levels, fUse3D ? D3DUSAGE_RENDERTARGET : 0, Format, Pool, &pD3DTexture );

	if( FAILED(rc) )
		STOP(("Failed to create texture from file %s",pName));

	Texture *pTexture = new Texture(pD3DTexture,mipmap);

	pTexture->SetName( pName );

	if( !pTexture )
		STOP(("Error creating a texture object"));

	return pTexture;
}


HRESULT Texture::Lock( D3DLOCKED_RECT *pLockedRect, UINT Level, RECT *pRect )
{
	HRESULT rc;
	LOG_API("Texture::Lock");
	rc = ((IDirect3DTexture8 *)m_pD3DBaseTexture)->LockRect( Level, pLockedRect, pRect, 0 );
	CHECK_RC;
}

HRESULT Texture::LevelDesc( D3DSURFACE_DESC *pDesc, UINT Level )
{
	HRESULT rc;
	LOG_API("Texture::LevelDesc");
	rc = ((IDirect3DTexture8 *)m_pD3DBaseTexture)->GetLevelDesc( Level, pDesc );
	CHECK_RC;
}

GosSurface* Texture::LevelSurface( UINT level )		// yields the GosSurface for a level of a mipmap
{
	LOG_API("Texture::LevelSurface");
	if( level >= m_nLevels )
		STOP(("Requested level %d from surface with %d levels",level,m_nLevels));

	if( !m_apLevel[level] )
	{
		IDirect3DSurface8 *pD3DSurface;
		((IDirect3DTexture8 *)m_pD3DBaseTexture)->GetSurfaceLevel( level, &pD3DSurface );
		m_apLevel[level] = new Surface( pD3DSurface );
	}
	return (GosSurface *)(m_apLevel[level]);
}

GosTexture* Texture::CreateVolume( UINT Width, UINT Height, UINT Depth, UINT Levels, D3DFORMAT Format )
{
	LOG_API("Texture::CreateVolume");
	IDirect3DVolumeTexture8 *pD3DTexture;
	HRESULT rc = Graphics::D3DDevice()->CreateVolumeTexture( Width, Height, Depth, Levels, 0, Format, D3DPOOL_DEFAULT, &pD3DTexture );

	if( FAILED(rc) )
		STOP(("Failed to create volume"));

	Texture *pTexture = new Texture(pD3DTexture,volume);

	if( !pTexture )
		STOP(("Error creating a texture object"));

	return pTexture;
}

HRESULT Texture::Lock( D3DLOCKED_BOX *pLockedBox, UINT Level, D3DBOX *pBox )
{
	HRESULT rc;
	LOG_API("Texture::Lock");
	rc = ((IDirect3DVolumeTexture8 *)m_pD3DBaseTexture)->LockBox( Level, pLockedBox, pBox, 0 );
	CHECK_RC;
}

GosTexture* Texture::CreateCube( UINT EdgeLength, UINT Levels, D3DFORMAT Format )
{
	LOG_API("Texture::CreateCube");
	IDirect3DCubeTexture8 *pD3DTexture;
	HRESULT rc = Graphics::D3DDevice()->CreateCubeTexture( EdgeLength, Levels, 0, Format, D3DPOOL_DEFAULT, &pD3DTexture );

	if( FAILED(rc) )
		STOP(("Failed to create cube"));

	Texture *pTexture = new Texture(pD3DTexture,cube);

	if( !pTexture )
		STOP(("Error creating a texture object"));

	return pTexture;
}

HRESULT Texture::Lock( D3DLOCKED_RECT *pLockedRect, D3DCUBEMAP_FACES Face, UINT Level, RECT *pRect )
{
	HRESULT rc;
	LOG_API("Texture::Lock");
	rc = ((IDirect3DCubeTexture8 *)m_pD3DBaseTexture)->LockRect( Face, Level, pLockedRect, pRect, 0 );
	CHECK_RC;
}

HRESULT Texture::Unlock( UINT Level, D3DCUBEMAP_FACES Face )
{
	HRESULT rc;
	LOG_API("Texture::Unlock");

	switch( m_Type )
	{
	case mipmap:
		rc = ((IDirect3DTexture8 *)m_pD3DBaseTexture)->UnlockRect(Level);
		break;
	case cube:
		rc = ((IDirect3DCubeTexture8 *)m_pD3DBaseTexture)->UnlockRect( Face, Level );
		break;
	case volume:
		rc = ((IDirect3DVolumeTexture8 *)m_pD3DBaseTexture)->UnlockBox(Level);
		break;
	}
	CHECK_RC;
}

HRESULT Texture::Update( GosTexture* pSourceTexture )
{
	HRESULT rc;
	LOG_API("Texture::Update");
	rc = Graphics::D3DDevice()->UpdateTexture( ((Texture *)pSourceTexture)->D3DTexture(), m_pD3DBaseTexture );
	CHECK_RC;
}

Texture::Texture( IDirect3DBaseTexture8 *pD3DTexture, TextureType Type )
{
	m_Type = Type;
	m_pD3DBaseTexture = pD3DTexture;
	m_nLevels = m_pD3DBaseTexture->GetLevelCount();
	m_pName = NULL;
	for( DWORD i = 0; i < m_nLevels; i++ )
		m_apLevel[i] = NULL;
}

Texture::~Texture()
{
	for( DWORD level=0; level < m_nLevels; level++ )
		if( m_apLevel[level] )
			delete m_apLevel[level];

	if( m_pName )
	{
		free( m_pName );
		m_pName = NULL;
	}

	m_pD3DBaseTexture->Release();
}

void Texture::SetName( const TCHAR *pName )
{
	if( m_pName )
		free( m_pName );
	if( pName )
	{
		m_pName = (TCHAR *)malloc( ( 1 + _tcslen(pName) ) << 2 );
		_tcscpy( m_pName, pName );
	}
}

GosTexture::~GosTexture()
{
	;
}

bool Texture::HasAlpha()
{
	_asm int 3;
	return true;
}

