//
// Asura_Platform_TextureManagement.cpp
//
// Created by KOR - 10 October 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Core/Asura_TextureManagement.h"

// Asura headers
#include "Core/Asura_String.h"
#include "Debugging/Asura_Logfile.h"
#include "FileAccess/Asura_FileAccess.h"
#include "FileAccess/Asura_PlatformFileAccess.h"

// Platform headers
#include "Core/Asura_Wii_MEM2.h"
#include "Rendering/Asura_GX.h"
#include "Rendering/Asura_GX_TextureManagement.h"

// Library headers
#include <revolution/dvd.h>
#include <revolution/tpl.h>

/// Kim Randell - 05/02/2003 11:46:36 - Implementing GC specific texture loader
/// Removed code to look on network
void Asura_Texture_Management::Platform_LoadTexture(const Asura_String& xName, int index)
{
	if (IsTextureLoaded(index)) return;
	Loaded[index] = s_uCurResetGroup;

	// KOR - 14/08/2003 12:17:22 - Nicked from PS2 version
	static char szBuffer[256];
	const char* const szInputName = xName.GetString();

	// Prepend "graphics\" to the path.
	{
		int iNumChars = Asura_PrintfToBfr( szBuffer, "graphics%s%s", 255, true, ('\\' == *szInputName ? "" : "\\"), szInputName );
		Asura_Assert( iNumChars < 256, "Path to texture is too long." );
	}

	REPLACE_EXTENSION(szBuffer, "tpl", 256);
	REPLACE_SLASHES(szBuffer);

	DVDFileInfo xFileInfo;
	if (DVDOpen(szBuffer, &xFileInfo))
	{
		unsigned int uFileSize;
		uFileSize = DVDGetLength(&xFileInfo);
		DVDClose(&xFileInfo);
		Asura_Handle iFileHandle;
		if ((iFileHandle = Asura_FileAccess::Open(szBuffer)) != ASURA_INVALID_HANDLE)
		{
			Asura_OutputToDebugger(("Loading %s with RESET group %d\n", szBuffer, s_uCurResetGroup));
			Platform_LoadTextureFromResource(iFileHandle, uFileSize, index, 0);
			Asura_FileAccess::Close(iFileHandle);
			return;
		}
		else
		{
			Asura_OutputToDebugger(("Error: DVDOpen succeeded but Asura_FileAccess failed to open %s\n", szBuffer));
		}
	}
	return;
}

void Asura_Texture_Management::Platform_LoadTextureFromResource(Asura_Handle fileHandle, int fileSize, int index, u_int uChunkFlags)
{
	if(!fileSize)
	{
		Asura_Assert(0, "Texture resource fileSize is zero.\n");
		return;
	}
	TPLPalettePtr& pTPL = Asura_GX_Texture_Management::s_apxTexturePaletteStorage[index];
	//pTPL = (TPLPalettePtr)Asura_AllocateAlign(OSRoundUp32B(fileSize), ASURA_ALIGN_32_BYTE);
	pTPL = static_cast<TPLPalettePtr>(ASURA_WII_MEM2_ALLOC_SILENTFAIL(OSRoundUp32B(fileSize)));
	if(!pTPL)
	{
		Asura_Assert(0, "Failed to allocate MEM2 for TPL");
		return;
	}
	Asura_FileAccess::ReadData(fileHandle, pTPL, fileSize);
	DCFlushRange(pTPL, fileSize);
	
	if(pTPL->versionNumber != 2142000 )
		OSHalt("invalid version number for texture palette");
	
	pTPL->descriptorArray = (TPLDescriptorPtr)(((u32)(pTPL->descriptorArray)) + ((u32)pTPL));
	
	for (unsigned int i = 0; i < pTPL->numDescriptors; i++ )
	{
		if(pTPL->descriptorArray[i].textureHeader)
		{
			pTPL->descriptorArray[i].textureHeader = (TPLHeaderPtr)(((u32)(pTPL->descriptorArray[i].textureHeader)) + ((u32)pTPL));	
			if(!(pTPL->descriptorArray[i].textureHeader->unpacked))
			{
				pTPL->descriptorArray[i].textureHeader->data = (Ptr)((u32)(pTPL->descriptorArray[i].textureHeader->data) + (u32)pTPL);
				pTPL->descriptorArray[i].textureHeader->unpacked = 1;
			}
		}
		if(pTPL->descriptorArray[i].CLUTHeader)
		{
			pTPL->descriptorArray[i].CLUTHeader = (TPLClutHeaderPtr)((u32)(pTPL->descriptorArray[i].CLUTHeader) + (u32)pTPL);		
			if(!(pTPL->descriptorArray[i].CLUTHeader->unpacked))
			{
				pTPL->descriptorArray[i].CLUTHeader->data = (Ptr)((u32)(pTPL->descriptorArray[i].CLUTHeader->data) + (u32)pTPL);
				pTPL->descriptorArray[i].CLUTHeader->unpacked = 1;
			}
		}		
	}
	GXTexObj*& pxTexObj = Asura_GX_Texture_Management::s_apxTextureStorage[index];
	pxTexObj =(GXTexObj* )Asura_Allocate(sizeof(GXTexObj));
	// KOR - TPL functions call GXInit* functions, which are prohibited inside GXBegin/End. Make sure we are not currently rendering.
	Asura_GX::LockMutex();
	TPLGetGXTexObjFromPalette(pTPL, pxTexObj, 0);
#ifdef DISABLE_FILTERING
	GXInitTexObjLOD(pxTexObj, GX_NEAR, GX_NEAR, 0, 0, 0, GX_TRUE, GX_TRUE, GX_ANISO_1);
#endif
	Asura_GX_AlphaMap* pxAlphaMap = &Asura_GX_Texture_Management::s_axAlphaStorage[index];
	pxAlphaMap->m_iIndex = -1;
	if(pTPL->numDescriptors > 1)
	{
		// Second texture is alpha channel
		pxAlphaMap->m_pxTextureObject = (GXTexObj*)Asura_Allocate(sizeof(GXTexObj));
		TPLGetGXTexObjFromPalette(pTPL, pxAlphaMap->m_pxTextureObject, 1);
	}
	else
	{
		pxAlphaMap->m_pxTextureObject = NULL;
	}
	Asura_GX::UnlockMutex();
}

void Asura_Texture_Management::Platform_DestroyTexture(int index)
{
	//unload the existing texture
	GXTexObj*& pxTexObj = Asura_GX_Texture_Management::s_apxTextureStorage[index];
	TPLPalettePtr& pxTPL = Asura_GX_Texture_Management::s_apxTexturePaletteStorage[index];
	Asura_GX_AlphaMap* pxAlphaMap = &Asura_GX_Texture_Management::s_axAlphaStorage[index];
	if( pxTexObj )
	{
		//Asura_DeallocateAlign(pxTPL);
		Asura_Wii_MEM2::Free(pxTPL);
		pxTPL = NULL;
		Asura_Deallocate(pxTexObj);
		pxTexObj = NULL;
		if(pxAlphaMap->m_pxTextureObject)
		{
			Asura_Deallocate(pxAlphaMap->m_pxTextureObject);
			pxAlphaMap->m_pxTextureObject = NULL;
		}
	}
	pxAlphaMap->m_iIndex = -1;
	Loaded[index] = ASURA_TEXTURE_NOT_LOADED;
}

void Asura_Texture_Management::Platform_Reset( void )
{
}


void Asura_Texture_Management::ReloadTexture(int index)
{
	Platform_DestroyTexture(index);

	//and try loading it again
	Asura_String xName = *GetTextureName( index );
    if(xName.IsNull())
    {
        return;
    }
	Platform_LoadTexture(xName,index);
}

void Asura_Texture_Management::Platform_Initialise(void)
{
	for(unsigned int index = 0; index < ASURA_MAX_NO_OF_TEXTURES; index++)
	{
		Asura_GX_Texture_Management::s_apxTextureStorage[index]= 0;
		Asura_GX_Texture_Management::s_axAlphaStorage[index].m_iIndex = -1;
		Asura_GX_Texture_Management::s_axAlphaStorage[index].m_pxTextureObject = 0;
		Asura_GX_Texture_Management::s_apxTexturePaletteStorage[index] = 0;
	}
}

void Asura_Texture_Management::Platform_Shutdown(void)
{
	for(int index = 0; index < ASURA_MAX_NO_OF_TEXTURES; index++)
	{
		Platform_DestroyTexture(index);
	}
}
