//////////////////////////////////////////////////////////////////////////////
//
// Asura_Chunk_ResourceFile_Xbox360_Skin.cpp
//
// Copyright (c) 2009 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

#include "ChunkSystem/Asura_Chunk_ResourceFile_Xbox360_Skin.h"

// Asura Platform-independent
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Debugging/Asura_Assert.h"

// Asura Xbox 360
#include "Rendering/Asura_Xbox360_SkinRenderer.h"

/******************************************************************************/
/* Asura_Chunk_ResourceFile_Xbox360_Skin Class Functions                      */
/******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// Asura_Chunk_ResourceFile_Xbox360_Skin::Process()
//
// Processes a chunk containing a 360 skin resource
//
////////////////////////////////////////////////////////////////////////////////

bool Asura_Chunk_ResourceFile_Xbox360_Skin::Process( const char *const szFilename,
	Asura_Chunk_Stream& xStream )
{
	if( Version != iCURRENT_VERSION )
	{
		Asura_Assertf( false,
			("Invalid skin chunk version (%d) for '%s'. Re-export level or get new code.",
			Version, szFilename) );

		return false;
	}

	const Asura_Hash_ID uHash = Asura_GetHashID( szFilename );
	bool bAlreadyExisted = false;

	Asura_Xbox360_Skin* const pxSkin =
		Asura_Xbox360_SkinRenderer::CreateSkin( uHash, bAlreadyExisted );

	#if !defined ASURA_DONT_ASSERT_ON_DUPLICATE_RESOURCE_DATA
		Asura_Assertf( !bAlreadyExisted, ("Skin '%s' being loaded more than once.", szFilename) );
	#endif

	if( bAlreadyExisted ) return false;

	Asura_Assertf( pxSkin, ("Failed to create render skin '%s'.", szFilename) );
	if( !pxSkin ) return false;

	xStream >> pxSkin->m_uNumStrips;

	u_int uTotalVertices, uTotalIndices, uTotalTriangles;
	xStream >> uTotalVertices >> uTotalIndices >> uTotalTriangles;

	// It's valid to have 0 strips. Sometimes empty skins are used for faking things up. We've
	// reached the end of the chunk in this case, so bail out now to avoid asserts about 0 size
	// reads and buffer creations
	if( pxSkin->m_uNumStrips == 0 ) return true;

	// Read strips

	pxSkin->m_pxStrips = new Asura_Xbox360_SkinStrip[ pxSkin->m_uNumStrips ];

	if( !pxSkin->m_pxStrips )
	{
		Asura_Assertf( false, ("Out of memory while allocating skin '%s'.", szFilename) );
		pxSkin->m_uNumStrips = 0;

		return false;
	}

	xStream.Read( sizeof( Asura_Xbox360_SkinStrip ) * pxSkin->m_uNumStrips, pxSkin->m_pxStrips );

	// Read vertices

	pxSkin->m_xVB.CreateStatic( Asura_Xbox360_SkinRenderer::uVERTEX_SIZE, uTotalVertices );

	void* const pVtxData = pxSkin->m_xVB.Lock();
	Asura_Assertf( pVtxData, ("Failed to lock vertex buffer for skin '%s'.", szFilename) );

	if( pVtxData )
	{
		xStream.Read( Asura_Xbox360_SkinRenderer::uVERTEX_SIZE * uTotalVertices, pVtxData );
		pxSkin->m_xVB.Unlock();
	}
	else
	{
		xStream.Skip( Asura_Xbox360_SkinRenderer::uVERTEX_SIZE * uTotalVertices );
	}

	// Read indices

	const u_int uIBSize = sizeof( u_short ) * uTotalIndices;
	pxSkin->m_xIB.CreateStatic( uIBSize );

	void* const pIdxData = pxSkin->m_xIB.Lock();
	Asura_Assertf( pIdxData, ("Failed to lock index buffer for skin '%s.'", szFilename) );

	if( pIdxData )
	{
		xStream.Read( uIBSize, pIdxData );
		pxSkin->m_xIB.Unlock();
	}
	else
	{
		xStream.Skip( uIBSize );
	}

	return true;
}
