//
// Asura_PlatformTextureManagement.cpp
//
// Created by Kevin Lea - 05/10/2001 16:39:14
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

/******************************************************************************/
/* Included Files                                                             */
/******************************************************************************/

#include "Core/Asura.h"

#include "Core/Asura_TextureManagement.h"

// Asura Platform-independent
#include "Core/Asura_PlatformBasics.h"
#include "Core/Asura_String.h"
#include "Debugging/Asura_Logfile.h"
#include "FileAccess/Asura_FileAccess.h"

// Asura PC
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Direct3D_UserOptions.h"

// Tools
#ifdef ASURA_TOOLS
	#include "Tools_System.h"
	#include "Load&Save/LevelExport/Tools_Level_Export.h"
	#include "Misc/Tools_MessageLog.h"
	#include "Misc/Tools_Timed_Messages.h"
	#include "Texturing/Tools_Texture_Management.h"
#endif

// Misc
#include <ddraw.h> // For DDS structures
#include <dxerr9.h>

/******************************************************************************/
/* Types                                                                      */
/******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// Asura_PC_DDS_Header
//
// The format of a DDS file mostly matches a DDSURFACEDESC2 struct, except that
// there's a pointer in that which will come out differently sized on 64-bit.
// Annoyingly, the DirectX headers don't define a fixed struct, so we have to
// do it ourselves. See the file reference in the DXSDK docs
//
////////////////////////////////////////////////////////////////////////////////

struct Asura_PC_DDS_Header
{
	u_int m_uMagic;
	u_int m_uSize;
	u_int m_uFlags;
	u_int m_uHeight;
	u_int m_uWidth;
	u_int m_uPitchOrLinearSize;
	u_int m_uDepth;
	u_int m_uMipMapCount;
	u_int m_auReserved[11];
	DDPIXELFORMAT m_xPixelFormat;
	DDSCAPS2 m_xCaps;
	u_int m_uReserved2;
};

/******************************************************************************/
/* Constants                                                                  */
/******************************************************************************/

const Asura_Char* const szLOCAL_GRAPHICS_FOLDER = "Graphics";
const Asura_Char* const szTEXTURE_LOGFILE = "Logfiles\\TextureLog.txt";

/******************************************************************************/
/* Global Variables                                                           */
/******************************************************************************/

Direct3D_BaseTexture* evilg_apxTextureStorage[ ASURA_MAX_NO_OF_TEXTURES ] = { NULL};
#if defined( ASURA_USE_TEXTURE_STREAMING )
Direct3D_BaseTexture* evilg_apxStreamingTextureStorage[ ASURA_MAX_NO_OF_TEXTURES ] = { NULL };
#endif

/******************************************************************************/
/* Functions                                                                  */
/******************************************************************************/

#if defined ASURA_TOOLS

static bool GenerateDDSAndGetFilename( const Asura_String& xTextureName, int iIndex, Asura_String& xFileToLoad )
{
	//if already a dds file , just use it
	if( xFileToLoad.EndsWith( ".dds" ) ) return true;

	//generate filename for dds file
	Asura_String xPath, xFilename;
	xTextureName.SplitFilename( &xPath, &xFilename, NULL );

	char szDDSName[ MAX_PATH ];
	Asura_PrintfToBfr( szDDSName, "%s%s\\DDS\\%s.dds", MAX_PATH, true, szLOCAL_GRAPHICS_FOLDER, xPath.GetString(), xFilename.GetString() );

	if( Tools_Level_Export::GenerateDDSFile( xFileToLoad.GetString(), szDDSName, iIndex ) )
	{
		xFileToLoad = szDDSName;
		return true;
	}
	else
	{
		return false;
	}
}

#endif // defined ASURA_TOOLS

static bool IsCubemap( const void* const pData, const u_int uFileSize )
{
	if( uFileSize < sizeof( Asura_PC_DDS_Header ) ) return false;

	const Asura_PC_DDS_Header* const pxDDSHeader = static_cast< const Asura_PC_DDS_Header* >( pData );

	return pxDDSHeader->m_uMagic == ' SDD'                                         // Magic number is 'DDS ', but stored big-endian in the file
		&& pxDDSHeader->m_uSize == sizeof( Asura_PC_DDS_Header ) - sizeof( DWORD ) // The magic number isn't included in the size
		&& (pxDDSHeader->m_uFlags & DDSD_CAPS)                                     // Check that the caps field is valid
		&& (pxDDSHeader->m_xCaps.dwCaps & DDSCAPS_COMPLEX)
		&& (pxDDSHeader->m_xCaps.dwCaps2 & DDSCAPS2_CUBEMAP);
}

/******************************************************************************/
/* Asura_Texture_Management Static Class Functions                            */
/******************************************************************************/

void Asura_Texture_Management::Platform_LoadTexture( const Asura_String& xName, int iTexID )
{
	if( IsTextureLoaded( iTexID ) || Loaded[ iTexID ] == ASURA_TEXTURE_ERROR_LOADING ) return;
	Loaded[ iTexID ] = s_uCurResetGroup;

	#if defined ASURA_TOOLS
		// Set tools data for width/height to 0 to indicate that it is unknown yet
		Tools_Texture_Management::StoreTextureSize( iTexID, 0, 0 );
	#endif

	enum
	{
		TEXTURELOAD_DDS,		// Checks for file with same name , but dds extension instead
		TEXTURELOAD_ASIS,		// Checks for file using the given filename
#if defined ASURA_TOOLS
		TEXTURELOAD_LOCALCACHE,	// Checks for pre-converted files. Only used if network is down.
#endif
		TEXTURELOAD_NUMATTEMPTS,
	};

	for( int iAttempt = 0; iAttempt < TEXTURELOAD_NUMATTEMPTS; ++iAttempt )
	{
		char szLocalFilename[260];
		const char* szFileToLoad = szLocalFilename;

		#if defined ASURA_TOOLS
			if( iAttempt == TEXTURELOAD_LOCALCACHE )
			{
				#if defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK
					const char* const szNetDir = Asura_FileAccess::PlatformGetNetworkPath();
					if( szNetDir && *szNetDir )
					{
						//If the netwok path is still available ,then we don't bother inspecting the local
						//cache of converted files. This is to prevent files that have been deleted from
						//being loaded , and confusing matters. RAR 29/11/2004
						continue;
					}
				#endif // defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK

				Asura_String xPath, xFilename;
				xName.SplitFilename( &xPath, &xFilename, NULL );

				Asura_PrintfToBfr( szLocalFilename, "%s%s\\DDS\\%s.dds", 260, true, szLOCAL_GRAPHICS_FOLDER, xPath.GetString(), xFilename.GetString() );
			}
			else
		#endif // defined ASURA_TOOLS

		{
			//Get the relative filename for the local copy of the texture
			Asura_PrintfToBfr( szLocalFilename, "%s%s", 260, true, szLOCAL_GRAPHICS_FOLDER, xName.GetString() );

			if( iAttempt == TEXTURELOAD_DDS )
			{
				//first time round we check for a dds file with the same name in the same directory
				char* const szDot = strrchr( szLocalFilename, '.' );
				if( szDot )
				{
					strcpy( szDot, ".dds" );
				}
			}
		}

		#if defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK
			//Determine if the network version should be used instead
			char szFilename[260];
			Asura_FileAccess::PlatformGetNetworkFilenameOrGetLocalCopy( szLocalFilename, szFilename, 260 );
			szFileToLoad = szFilename;
		#endif // defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK

		#if defined ASURA_PC_ALLOW_LOAD_FROM_SEARCHPATHS
			// DLH - 15 September 2006 15:44:29 - I would like this to be MAX_PATH but it is in an independent file
			const u_int uSearchFilenameSize = 260;
			char szSearchFilename[ uSearchFilenameSize + 1] = { 0};
			Asura_FileAccess::PlatformSearchPathsGetExistingFilename( szLocalFilename, szSearchFilename, uSearchFilenameSize);
			szFileToLoad = szSearchFilename;
		#endif // defined ASURA_PC_ALLOW_LOAD_FROM_SEARCHPATHS

		if( Asura_FileAccess::FileExists( szFileToLoad ) )
		{
			D3DFORMAT eSurfaceFormat;

			if( xName.Contains( "\\exp" ) )
			{
				eSurfaceFormat = D3DFMT_A8R8G8B8;
			}
			else
			{
				eSurfaceFormat = D3DFMT_DXT3;
			}

			/// Kevin Lea - 19/12/2002 11:58:59 - do we bother to compress textures?
			#if defined ASURA_TOOLS
				Asura_String xFilename = szFileToLoad;

				if( iAttempt == TEXTURELOAD_LOCALCACHE )
				{
					eSurfaceFormat = D3DFMT_UNKNOWN;
				}
				else if( Tools_System::ShouldNotCompressTexturesOnLoad() )
				{
					eSurfaceFormat = D3DFMT_A8R8G8B8;
				}
				else if( GenerateDDSAndGetFilename( xName, iTexID, xFilename ) )
				{
					//for dds files use whichever surface format they were saved as
					eSurfaceFormat = D3DFMT_UNKNOWN;
				}

				szFileToLoad = xFilename.GetString();

				D3DXIMAGE_INFO xImageInfo;
				D3DXIMAGE_INFO* const pxImageInfo = &xImageInfo;
			#else
				D3DXIMAGE_INFO* const pxImageInfo = NULL;
			#endif // !defined ASURA_TOOLS

			UINT uMipMaps = (iAttempt == TEXTURELOAD_ASIS) ? D3DX_DEFAULT : D3DX_FROM_FILE;
			const u_int uTextureFlags = Asura_Texture_Management::GetTextureFlags( iTexID );			
			if( (uTextureFlags & AsuraTextureFlag_NoMipMaps) == AsuraTextureFlag_NoMipMaps )
			{
				uMipMaps = 1;
			}

			const u_int uFileSize = Asura_FileAccess::GetFileSize( szFileToLoad );

			void* const pFileContents = Asura_Allocate( uFileSize );
			if( !pFileContents )
			{
				Asura_Assert( false, "Failed to allocate memory for texture read." );
				return;
			}

			const Asura_Handle iFileHandle = Asura_FileAccess::Open( szFileToLoad );
			if( iFileHandle == ASURA_INVALID_HANDLE )
			{
				Asura_Assertf( false, ("Failed to open texture file '%s'.", szFileToLoad) );
				Asura_Deallocate( pFileContents );
				return;
			}

			const bool bReadSuccessful = Asura_FileAccess::ReadData( iFileHandle, pFileContents, uFileSize );
			Asura_FileAccess::Close( iFileHandle );

			if( !bReadSuccessful )
			{
				Asura_Assertf( false, ("Unable to read data from file '%s'.", szFileToLoad) );
				Asura_Deallocate( pFileContents );
				return;
			}

			HRESULT xResult = D3D_OK;

			if( NULL != Asura_Direct3D::D3DDevice)
			{
				if( IsCubemap( pFileContents, uFileSize ) )
				{
					Direct3D_CubeTexture* pxTexture = NULL;

					xResult = D3DXCreateCubeTextureFromFileInMemoryEx
					(
						Asura_Direct3D::D3DDevice,	// Device
						pFileContents,				// Source data
						uFileSize,					// Source data size
						D3DX_DEFAULT,				// Cube width/height
						uMipMaps,					// Mip levels
						0,							// Usage
						D3DFMT_UNKNOWN,				// Format
						D3DPOOL_MANAGED,			// Pool
						D3DX_DEFAULT,				// Filter
						D3DX_DEFAULT,				// Mip filter
						0,							// Colour key
						pxImageInfo,				// Output info
						NULL,						// Palette
						&pxTexture					// Output pointer
					);

					if( SUCCEEDED( xResult ) )
					{
						evilg_apxTextureStorage[ iTexID ] = pxTexture;
					}
				}
				else
				{
					Direct3D_Texture* pxTexture = NULL;

					// SB (15/02/08) - Check UserOptions to see if we want to drop levels on load
					int iLevelsToDrop = 0;
					{
						// Prepare texture information and get scaling info
						const Asura_Direct3D_UserOptions::TexInfo xTexInfo( &xName, uTextureFlags );
						const Asura_Direct3D_UserOptions::TexScalingInfo xScalingInfo = Asura_Direct3D_UserOptions::GetTextureScalingInfo( xTexInfo );
			
						// Scale if necessary
						if ( xScalingInfo.m_bScale == true )
						{
							// Get number of levels in texture from the DDS header
							const Asura_PC_DDS_Header* const pxDDSHeader = static_cast< const Asura_PC_DDS_Header* >( pFileContents );
							const u_int uLevels = pxDDSHeader->m_uMipMapCount;

							// Work out number of levels to drop
							const u_int uMaxNumberOfLevels = xScalingInfo.m_uMaxLevel;
							iLevelsToDrop = uLevels - uMaxNumberOfLevels;
				
							if (iLevelsToDrop < 0) iLevelsToDrop = 0;
						}
					}

					xResult = D3DXCreateTextureFromFileInMemoryEx
					(
						Asura_Direct3D::D3DDevice,	// Device
						pFileContents,				// Source data
						uFileSize,					// Source data size
						D3DX_DEFAULT,				// Width
						D3DX_DEFAULT,				// Height
						uMipMaps,					// Mip levels
						0,							// Usage
						eSurfaceFormat,				// Format
						D3DPOOL_MANAGED,			// Pool
						D3DX_DEFAULT,				// Filter
						D3DX_SKIP_DDS_MIP_LEVELS( iLevelsToDrop, D3DX_FILTER_BOX ),	// Mip filter + drop levels if necessary
						0,							// Colour key
						pxImageInfo,				// Output info
						NULL,						// Palette
						&pxTexture					// Output pointer
					);

					if( SUCCEEDED( xResult ) )
					{
						evilg_apxTextureStorage[ iTexID ] = pxTexture;
					}
				}
			}
			else
			{
				xResult = D3DXGetImageInfoFromFileInMemory( pFileContents, uFileSize, pxImageInfo);
			}

			Asura_Deallocate( pFileContents );

			if( FAILED( xResult ) )
			{
				#if defined ASURA_USE_TEXTURE_LOG || defined ASURA_LOGFILES_ENABLED || !defined ASURA_NO_DEBUG_OUTPUT
					const char* const szErrorName = DXGetErrorString9( xResult );
					const char* const szErrorDescription = DXGetErrorDescription9( xResult );
				#endif

				#if defined ASURA_USE_TEXTURE_LOG
					AddToTextureLog( "Error loading '%s':\n\t%s\n\t%s\n\n", szFileToLoad, szErrorName, szErrorDescription );
				#else
					Asura_Logfile_Retail(( szTEXTURE_LOGFILE, "Error loading '%s':\n\t%s\n\t%s\n\n", szFileToLoad, szErrorName, szErrorDescription ));
				#endif
				Asura_OutputToDebugger_Retail(( "\nError loading '%s':\n\t%s\n\t%s\n\n", szFileToLoad, szErrorName, szErrorDescription ));
			}

			#if defined ASURA_TOOLS
				//store the width and height of the texture for tools use
				if( SUCCEEDED( xResult ) )
				{
					Tools_Texture_Management::StoreTextureSize( iTexID, xImageInfo.Width, xImageInfo.Height );
				}
			#endif // defined ASURA_TOOLS

			return;
		}
	}

	//tried both as DDS and given filename, so give up
	#if defined ASURA_USE_TEXTURE_LOG
		AddToTextureLog( "Error - Failed to find %s.\n", xName.GetString() );
	#else
		Asura_Logfile_Retail(( szTEXTURE_LOGFILE, "Failed to find %s ", xName.GetString() ));
	#endif
	Asura_OutputToDebugger(( "Failed to find texture %s.\n", xName.GetString() ));

	// ARC - 21 February 2006 14:47:49 - belt and braces stuff
	#if defined ASURA_TOOLS
		if( Tools_System::IsActive() && NULL != Asura_Direct3D::D3DDevice)
		{
			Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "Failed to find texture '%s'", xName.GetString() );
			if( Tools_MessageLog::ShouldShowForMissingTextures() )
			{
				Tools_MessageLog::ShowOverlay();
			}
		}
		else
	#endif // defined ASURA_TOOLS
	{
		Asura_Assertf( false, ("Failed to find texture '%s'", xName.GetString() ) );
	}

	Loaded[ iTexID ] = ASURA_TEXTURE_ERROR_LOADING;
}

void Asura_Texture_Management::Platform_LoadTextureFromResource( Asura_Handle iFileHandle, int iFileSize, int iTexID, u_int uChunkFlags )
{
	void* const pBuffer = Asura_Allocate( iFileSize );
	if( !pBuffer )
	{
		Asura_Assert( false, "Failed to allocate memory for texture." );
		return;
	}

	if( !Asura_FileAccess::ReadData( iFileHandle, pBuffer, iFileSize ) )
	{
		Asura_Assert( false, "Failed to read texture data from resource." );
		Asura_Deallocate( pBuffer );
		return;
	}

	UINT uMipMaps = D3DX_FROM_FILE;
	const int iTextureFlags = Asura_Texture_Management::GetTextureFlags( iTexID );
	if( (AsuraTextureFlag_NoMipMaps & iTextureFlags) == AsuraTextureFlag_NoMipMaps)
	{
		uMipMaps = 1;
	}

	#if !defined(ASURA_TOOLS) && !defined(_DEBUG)
		D3DXIMAGE_INFO* const pxImageInfo = NULL;
	#else
		D3DXIMAGE_INFO xImageInfo;
		D3DXIMAGE_INFO* const pxImageInfo = &xImageInfo;
	#endif

	HRESULT xResult;

	if( IsCubemap( pBuffer, iFileSize ) )
	{
		Direct3D_CubeTexture* pxTexture = NULL;

		xResult = D3DXCreateCubeTextureFromFileInMemoryEx
		(
			Asura_Direct3D::D3DDevice,	// Device
			pBuffer,					// Source data
			iFileSize,					// Source data size
			D3DX_DEFAULT,				// Cube width/height
			uMipMaps,					// Mip levels
			0,							// Usage
			D3DFMT_UNKNOWN,				// Format
			D3DPOOL_MANAGED,			// Pool
			D3DX_DEFAULT,				// Filter
			D3DX_DEFAULT,				// Mip filter
			0,							// Colour key
			pxImageInfo,				// Output info
			NULL,						// Palette
			&pxTexture					// Output pointer
		);

		if( SUCCEEDED( xResult ) )
		{
			evilg_apxTextureStorage[ iTexID ] = pxTexture;
		}
	}
	else
	{
		Direct3D_Texture* pxTexture = NULL;

		// SB (15/02/08) - Check UserOptions to see if we want to drop levels on load
		int iLevelsToDrop = 0;
		{
			// Prepare texture information and get scaling info
			const Asura_Direct3D_UserOptions::TexInfo xTexInfo( Asura_Texture_Management::GetTextureName( iTexID ), iTextureFlags );
			const Asura_Direct3D_UserOptions::TexScalingInfo xScalingInfo = Asura_Direct3D_UserOptions::GetTextureScalingInfo( xTexInfo );

			// Scale if necessary
			if ( xScalingInfo.m_bScale == true )
			{
				// Get number of levels in texture from the DDS header
				const Asura_PC_DDS_Header* const pxDDSHeader = static_cast< const Asura_PC_DDS_Header* >( pBuffer );
				const u_int uLevels = pxDDSHeader->m_uMipMapCount;

				// Work out number of levels to drop
				const u_int uMaxNumberOfLevels = xScalingInfo.m_uMaxLevel;
				iLevelsToDrop = uLevels - uMaxNumberOfLevels;
	
				if (iLevelsToDrop < 0) iLevelsToDrop = 0;
			}
		}

		xResult = D3DXCreateTextureFromFileInMemoryEx
		(
			Asura_Direct3D::D3DDevice,	// Device
			pBuffer,					// Source data
			iFileSize,					// Data size
			D3DX_DEFAULT,				// Width
			D3DX_DEFAULT,				// Height
			uMipMaps,					// Mip leves
			0,							// Usage
			D3DFMT_UNKNOWN,				// Format
			D3DPOOL_MANAGED,			// Pool
			D3DX_DEFAULT,				// Filter
			D3DX_SKIP_DDS_MIP_LEVELS( iLevelsToDrop, D3DX_FILTER_BOX ),	// Mip filter + drop levels if necessary
			0,							// Colour key
			pxImageInfo,				// Output info
			NULL,						// Palette
			&pxTexture					// Output object
		);

		if( SUCCEEDED( xResult ) )
		{
			evilg_apxTextureStorage[ iTexID ] = pxTexture;
		}
	}

	#if defined ASURA_TOOLS
		if( FAILED( xResult ) )
		{
			Tools_Texture_Management::StoreTextureSize( iTexID, 0, 0 );
		}
		else
		{
	 		Tools_Texture_Management::StoreTextureSize( iTexID, xImageInfo.Width, xImageInfo.Height );
		}
	#endif // defined ASURA_TOOLS

	Asura_Deallocate( pBuffer );
}

void Asura_Texture_Management::Platform_DestroyTexture( int iTexID )
{
	if( evilg_apxTextureStorage[ iTexID ] )
	{
		evilg_apxTextureStorage[ iTexID ]->Release();
		evilg_apxTextureStorage[ iTexID ] = NULL;
	}
}

bool Asura_Texture_Management::Platform_IsTextureCubemap( const int iTexID )
{
	if( 0 <= iTexID && iTexID < ASURA_MAX_NO_OF_TEXTURES )
	{
		if( evilg_apxTextureStorage[ iTexID ] )
		{
			return evilg_apxTextureStorage[ iTexID ]->GetType() == D3DRTYPE_CUBETEXTURE;
		}

#if defined ASURA_TOOLS
		else
		{
			// If D3D hasn't been initialised (perhaps through the -consolemode command-line arg),
			// we've got one more chance - see if we can check the file itself

			const Asura_String* const pxTextureName = GetTextureName( iTexID );
			if( pxTextureName )
			{
				Asura_String xTexturePath = "Graphics";
				xTexturePath += *pxTextureName;

				char szNetworkPath[ MAX_PATH ];
				Asura_FileAccess::PlatformGetNetworkFilename( xTexturePath.GetString(),
					szNetworkPath, MAX_PATH );

				D3DXIMAGE_INFO xImageInfo;
				if( SUCCEEDED( D3DXGetImageInfoFromFile( szNetworkPath, &xImageInfo ) ) )
				{
					return xImageInfo.ResourceType == D3DRTYPE_CUBETEXTURE;
				}
			}
		}
#endif // defined ASURA_TOOLS
	}

	// Can't tell. Nothing we can do except assume not a cubemap
	return false;
}

void Asura_Texture_Management::ReloadTexture( int iTexID )
{
	//unload the existing texture
	if( evilg_apxTextureStorage[ iTexID ] )
	{
		evilg_apxTextureStorage[ iTexID ]->Release();
		evilg_apxTextureStorage[ iTexID ] = NULL;
	}

	Loaded[ iTexID ] = ASURA_TEXTURE_NOT_LOADED;

	//and try loading it again
	const Asura_String xName = *GetTextureName( iTexID );
    if( xName.IsNull() ) return;

	Platform_LoadTexture( xName, iTexID );
}
#if defined (ASURA_USE_TEXTURE_STREAMING)
#include "Core/Asura_Texture_Streaming.h"

static Asura_Handle g_iStreamingFileHandle = ASURA_INVALID_HANDLE;

void Asura_Texture_Streaming_System::Platform_Initialise()
{
}

void Asura_Texture_Streaming_System::Platform_Shutdown()
{
}

bool Asura_Texture_Streaming_System::Platform_StartStreaming( void )
{
	Asura_Assert( g_iStreamingFileHandle == ASURA_INVALID_HANDLE, "Code bug: is streaming file still open?" );

	g_iStreamingFileHandle = Asura_FileAccess::Open( Asura_Texture_Streaming_System::GetTextureStreamingFilename(), false, true );

	// return true if open successful.
	return ( g_iStreamingFileHandle != ASURA_INVALID_HANDLE );
}

void Asura_Texture_Streaming_System::Platform_EndStreaming( void )
{
	if ( g_iStreamingFileHandle != ASURA_INVALID_HANDLE )
	{
		Asura_FileAccess::Close( g_iStreamingFileHandle );
	}

	g_iStreamingFileHandle = ASURA_INVALID_HANDLE;
}

void Asura_Texture_Streaming_System::Platform_StreamTexture( Asura_Streaming_Texture& xTexture )
{
	const u_int uTextureID = xTexture.GetTextureIndex();

#if !defined(ASURA_TOOLS)

	if( g_iStreamingFileHandle == ASURA_INVALID_HANDLE )
	{
		return;
	}
	
	int iFileSize = xTexture.GetFileSize();

	// worry here about memory fragmentation? we can easily get the largest file size
	void* const pBuffer = Asura_Allocate( iFileSize );

	if( !pBuffer )
	{
		Asura_Assert( false, "Failed to allocate memory for texture." );
		return;
	}

	bool bSuccess;

	bSuccess = Asura_FileAccess::SeekFile( g_iStreamingFileHandle, xTexture.GetPositionInFile() );

	if ( bSuccess )
	{
		bSuccess = Asura_FileAccess::ReadData( g_iStreamingFileHandle, pBuffer, iFileSize );
	}

	
	if (!bSuccess)
	{
		Asura_Assert( false, "Failed to read texture data from resource." );
		Asura_Deallocate( pBuffer );
		return;
	}

	UINT uMipMaps = D3DX_FROM_FILE;
	const int iTextureFlags = Asura_Texture_Management::GetTextureFlags( uTextureID );
	if( (AsuraTextureFlag_NoMipMaps & iTextureFlags) == AsuraTextureFlag_NoMipMaps)
	{
		uMipMaps = 1;
	}

	D3DXIMAGE_INFO* const pxImageInfo = NULL;


	HRESULT xResult;

	if( IsCubemap( pBuffer, iFileSize ) )
	{
		Direct3D_CubeTexture* pxTexture = NULL;

		xResult = D3DXCreateCubeTextureFromFileInMemoryEx
		(
			Asura_Direct3D::D3DDevice,	// Device
			pBuffer,					// Source data
			iFileSize,					// Source data size
			D3DX_DEFAULT,				// Cube width/height
			uMipMaps,					// Mip levels
			0,							// Usage
			D3DFMT_UNKNOWN,				// Format
			D3DPOOL_MANAGED,			// Pool
			D3DX_DEFAULT,				// Filter
			D3DX_DEFAULT,				// Mip filter
			0,							// Colour key
			pxImageInfo,				// Output info
			NULL,						// Palette
			&pxTexture					// Output pointer
		);

		if( SUCCEEDED( xResult ) )
		{
			evilg_apxStreamingTextureStorage[ uTextureID ] = pxTexture;
		}
	}
	else
	{
		Direct3D_Texture* pxTexture = NULL;

		xResult = D3DXCreateTextureFromFileInMemoryEx
		(
			Asura_Direct3D::D3DDevice,	// Device
			pBuffer,					// Source data
			iFileSize,					// Data size
			D3DX_DEFAULT,				// Width
			D3DX_DEFAULT,				// Height
			uMipMaps,					// Mip leves
			0,							// Usage
			D3DFMT_UNKNOWN,				// Format
			D3DPOOL_MANAGED,			// Pool
			D3DX_DEFAULT,				// Filter
			D3DX_DEFAULT,				// Mip filter
			0,							// Colour key
			pxImageInfo,				// Output info
			NULL,						// Palette
			&pxTexture					// Output object
		);

		if( SUCCEEDED( xResult ) )
		{
			evilg_apxStreamingTextureStorage[ uTextureID ] = pxTexture;
		}
	}

	Asura_Deallocate( pBuffer );

	xTexture.SetStatus( Asura_Streaming_Texture::AST_LOADED );
 
#else // ASURA_TOOLS version

	const Asura_String* pxFilename = Asura_Texture_Management::GetTextureName( uTextureID );

	
	enum
	{
		TEXTURELOAD_DDS,		// Checks for file with same name , but dds extension instead
		TEXTURELOAD_ASIS,		// Checks for file using the given filename
#if defined ASURA_TOOLS
		TEXTURELOAD_LOCALCACHE,	// Checks for pre-converted files. Only used if network is down.
#endif
		TEXTURELOAD_NUMATTEMPTS,
	};

	for( int iAttempt = 0; iAttempt < TEXTURELOAD_NUMATTEMPTS; ++iAttempt )
	{
		char szLocalFilename[260];
		const char* szFileToLoad = szLocalFilename;

		#if defined ASURA_TOOLS
		if( iAttempt == TEXTURELOAD_LOCALCACHE )
		{
			#if defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK
				const char* const szNetDir = Asura_FileAccess::PlatformGetNetworkPath();
				if( szNetDir && *szNetDir )
				{
					//If the netwok path is still available ,then we don't bother inspecting the local
					//cache of converted files. This is to prevent files that have been deleted from
					//being loaded , and confusing matters. RAR 29/11/2004
					continue;
				}
			#endif // defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK

			Asura_String xPath, xFilename;
			pxFilename->SplitFilename( &xPath, &xFilename, NULL );

			Asura_PrintfToBfr( szLocalFilename, "%s%s\\DDS\\%s.dds", 260, true, szLOCAL_GRAPHICS_FOLDER, xPath.GetString(), xFilename.GetString() );
		}
		else
		#endif // defined ASURA_TOOLS

		{
			//Get the relative filename for the local copy of the texture
			Asura_PrintfToBfr( szLocalFilename, "%s%s", 260, true, szLOCAL_GRAPHICS_FOLDER, pxFilename->GetString() );

			if( iAttempt == TEXTURELOAD_DDS )
			{
				//first time round we check for a dds file with the same name in the same directory
				char* const szDot = strrchr( szLocalFilename, '.' );
				if( szDot )
				{
					strcpy( szDot, ".dds" );
				}
			}
		}

		#if defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK
			//Determine if the network version should be used instead
			char szFilename[260];
			Asura_FileAccess::PlatformGetNetworkFilenameOrGetLocalCopy( szLocalFilename, szFilename, 260 );
			szFileToLoad = szFilename;
		#endif // defined ASURA_PC_ALLOW_LOAD_FROM_NETWORK

		#if defined ASURA_PC_ALLOW_LOAD_FROM_SEARCHPATHS
			// DLH - 15 September 2006 15:44:29 - I would like this to be MAX_PATH but it is in an independent file
			const u_int uSearchFilenameSize = 260;
			char szSearchFilename[ uSearchFilenameSize + 1] = { 0};
			Asura_FileAccess::PlatformSearchPathsGetExistingFilename( szLocalFilename, szSearchFilename, uSearchFilenameSize);
			szFileToLoad = szSearchFilename;
		#endif // defined ASURA_PC_ALLOW_LOAD_FROM_SEARCHPATHS

		if( Asura_FileAccess::FileExists( szFileToLoad ) )
		{
			D3DFORMAT eSurfaceFormat;

			if( pxFilename->Contains( "\\exp" ) )
			{
				eSurfaceFormat = D3DFMT_A8R8G8B8;
			}
			else
			{
				eSurfaceFormat = D3DFMT_DXT3;
			}

			/// Kevin Lea - 19/12/2002 11:58:59 - do we bother to compress textures?
			#if defined ASURA_TOOLS
				Asura_String xFilename = szFileToLoad;

				if( iAttempt == TEXTURELOAD_LOCALCACHE )
				{
					eSurfaceFormat = D3DFMT_UNKNOWN;
				}
				else if( Tools_System::ShouldNotCompressTexturesOnLoad() )
				{
					eSurfaceFormat = D3DFMT_A8R8G8B8;
				}
				else if( GenerateDDSAndGetFilename( *pxFilename, uTextureID, xFilename ) )
				{
					//for dds files use whichever surface format they were saved as
					eSurfaceFormat = D3DFMT_UNKNOWN;
				}

				szFileToLoad = xFilename.GetString();

				D3DXIMAGE_INFO xImageInfo;
				D3DXIMAGE_INFO* const pxImageInfo = &xImageInfo;
			#else
				D3DXIMAGE_INFO* const pxImageInfo = NULL;
			#endif // !defined ASURA_TOOLS

			UINT uMipMaps = (iAttempt == TEXTURELOAD_ASIS) ? D3DX_DEFAULT : D3DX_FROM_FILE;
			const u_int uTextureFlags = Asura_Texture_Management::GetTextureFlags( uTextureID );			
			if( (uTextureFlags & AsuraTextureFlag_NoMipMaps) == AsuraTextureFlag_NoMipMaps )
			{
				uMipMaps = 1;
			}

			const u_int uFileSize = Asura_FileAccess::GetFileSize( szFileToLoad );

			void* const pFileContents = Asura_Allocate( uFileSize );
			if( !pFileContents )
			{
				Asura_Assert( false, "Failed to allocate memory for texture read." );
				return;
			}

			const Asura_Handle iFileHandle = Asura_FileAccess::Open( szFileToLoad );
			if( iFileHandle == ASURA_INVALID_HANDLE )
			{
				Asura_Assertf( false, ("Failed to open texture file '%s'.", szFileToLoad) );
				Asura_Deallocate( pFileContents );
				return;
			}

			const bool bReadSuccessful = Asura_FileAccess::ReadData( iFileHandle, pFileContents, uFileSize );
			Asura_FileAccess::Close( iFileHandle );

			if( !bReadSuccessful )
			{
				Asura_Assertf( false, ("Unable to read data from file '%s'.", szFileToLoad) );
				Asura_Deallocate( pFileContents );
				return;
			}

			HRESULT xResult = D3D_OK;

			if( NULL != Asura_Direct3D::D3DDevice)
			{
				if( IsCubemap( pFileContents, uFileSize ) )
				{
					Direct3D_CubeTexture* pxTexture = NULL;

					xResult = D3DXCreateCubeTextureFromFileInMemoryEx
					(
						Asura_Direct3D::D3DDevice,	// Device
						pFileContents,				// Source data
						uFileSize,					// Source data size
						D3DX_DEFAULT,				// Cube width/height
						uMipMaps,					// Mip levels
						0,							// Usage
						D3DFMT_UNKNOWN,				// Format
						D3DPOOL_MANAGED,			// Pool
						D3DX_DEFAULT,				// Filter
						D3DX_DEFAULT,				// Mip filter
						0,							// Colour key
						pxImageInfo,				// Output info
						NULL,						// Palette
						&pxTexture					// Output pointer
					);

					if( SUCCEEDED( xResult ) )
					{
						evilg_apxStreamingTextureStorage[ uTextureID ] = pxTexture;
					}
				}
				else
				{
					Direct3D_Texture* pxTexture = NULL;
					
					xResult = D3DXCreateTextureFromFileInMemoryEx
					(
						Asura_Direct3D::D3DDevice,	// Device
						pFileContents,				// Source data
						uFileSize,					// Source data size
						D3DX_DEFAULT,				// Width
						D3DX_DEFAULT,				// Height
						uMipMaps,					// Mip levels
						0,							// Usage
						eSurfaceFormat,				// Format
						D3DPOOL_MANAGED,			// Pool
						D3DX_DEFAULT,				// Filter
						D3DX_DEFAULT,				// Mip filter
						0,							// Colour key
						pxImageInfo,				// Output info
						NULL,						// Palette
						&pxTexture					// Output pointer
					);

					if( SUCCEEDED( xResult ) )
					{
						evilg_apxStreamingTextureStorage[ uTextureID ] = pxTexture;
					}
				}
			}
			else
			{
				xResult = D3DXGetImageInfoFromFileInMemory( pFileContents, uFileSize, pxImageInfo);
			}

			Asura_Deallocate( pFileContents );

			#if defined ASURA_TOOLS
				//store the width and height of the texture for tools use
				if( SUCCEEDED( xResult ) )
				{
					Tools_Texture_Management::StoreTextureSize( uTextureID, xImageInfo.Width, xImageInfo.Height );
				}
			#endif // defined ASURA_TOOLS
		
		//	Asura_Texture_Management::Loaded[ uTextureID ] = xTexture.GetResetGroup();

				xTexture.SetStatus( Asura_Streaming_Texture::AST_LOADED );

			return;
		}
	}

#endif

}

void Asura_Texture_Streaming_System::Platform_UnloadTexture( u_int uTextureID )
{
	if( evilg_apxStreamingTextureStorage[ uTextureID ] )
	{
		evilg_apxStreamingTextureStorage[ uTextureID ]->Release();
		evilg_apxStreamingTextureStorage[ uTextureID ] = NULL;
	}
}
#endif
void Asura_Texture_Management::Platform_Initialise()
{

}

void Asura_Texture_Management::Platform_Reset()
{
}

void Asura_Texture_Management::Platform_Shutdown()
{
}