//
// Asura_Chunk_Visibility.cpp
//
// Created by KJFL - 14 December 2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

#if defined(ASURA_USE_NEW_VISIBILITY_SYSTEM)

// This file's header.
#include "ChunkSystem/Asura_Chunk_Visibility.h"

#include "Core/Memory/Asura_Mem.h"
#include "ChunkSystem/Asura_Chunk_ModuleLinking.h" // for the module index conversion
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Rendering/Asura_Module.h"
#include "Visibility/Asura_Visibility_Node.h"
#include "Visibility/Asura_Visibility_System.h"

bool Asura_Chunk_Visibility::Process( Asura_Handle iFileHandle ) const
{
	Asura_Chunk_File_Stream xStream( iFileHandle );

	Asura_Visibility_System::Reset();

	// skip if version is too old
	if ( Version <= 1 )
	{
		Asura_Assertf( false, ("Chunk version %d for Asura_Chunk_Visibility is too old", Version) );
		return false;
	}

	// or too new
	if ( Version > Asura_Chunk_Visibility::CHUNK_VERSION )
	{
		Asura_Assertf( false, ("Unknown chunk version %d for Asura_Chunk_Visibility", Version) );
		return false;
	}

	xStream >> Asura_Visibility_System::s_uNumberOfNodes;
	xStream >> Asura_Visibility_System::s_uNumberOfLeaves;

	u_int uOriginalNumberOfVisibilityFeatures;
	xStream >> uOriginalNumberOfVisibilityFeatures;

    if ( Asura_Visibility_System::s_uNumberOfNodes == 0 ) return true;

	// The number of visibility features (currently modules + skybox) may have changed externally
	// due to mesh work etc.
	u_int uCurrentNumberOfModules = Asura_Module_System::GetNumberOfModules();
	u_int uOriginalNumberOfModules = uOriginalNumberOfVisibilityFeatures - 1;

	Asura_Visibility_System::s_uNumberOfVisibilityFeatures = uCurrentNumberOfModules + 1;

	Asura_Visibility_System::s_pxVisibilityNodes = new Asura_Visibility_Node[ Asura_Visibility_System::s_uNumberOfNodes ];

	Asura_Visibility_System::s_pxVisibilityLeaves = new Asura_Visibility_Leaf[ Asura_Visibility_System::s_uNumberOfLeaves ];

	for( u_int u = 0; u < Asura_Visibility_System::s_uNumberOfNodes; ++u )
	{
		Asura_Visibility_Node& xNode = Asura_Visibility_System::s_pxVisibilityNodes[ u ];

		xStream >> xNode.m_xAABB;

		xStream >> xNode.m_usParent;
		xStream >> xNode.m_usLeftChild;

		xStream >> xNode.m_usLeafIndex;

		if ( Version < 3 ) // dropped this data in newer versions
		{
			u_char uDummy;
			xStream >> uDummy;
			xStream >> uDummy;
		}
	}

	Asura_ModuleIndex_Conversion::CheckNumberOfModules( uOriginalNumberOfModules, uCurrentNumberOfModules );

	for( u_int u=0; u<Asura_Visibility_System::s_uNumberOfLeaves; ++u )
	{
		Asura_Visibility_Leaf& xLeaf = Asura_Visibility_System::s_pxVisibilityLeaves[ u ];

		xLeaf.Reset();

		xLeaf.m_xLeafVisibilities.Load( xStream );

//		xLeaf.m_pucLeafVisibilities = new u_char [ Asura_Visibility_System::s_uNumberOfLeaves ];
		xLeaf.m_pucFeatureVisibilities = new u_char [ Asura_Visibility_System::s_uNumberOfVisibilityFeatures ];

		// because some of these visibility features may be new, we need to zero the array first
		Asura_Mem::Set( xLeaf.m_pucFeatureVisibilities, 0, Asura_Visibility_System::s_uNumberOfVisibilityFeatures );

		// stream in old module visibilities and store them using the new module indices
		for ( u_int v=0; v<uOriginalNumberOfVisibilityFeatures-1; ++v )
		{
			u_char ucVisible;
			xStream >> ucVisible;
			
			// find what the index is for this module
			const int iModuleIndex = Asura_ModuleIndex_Conversion::ConvertIndex( v );

			if (iModuleIndex>=0)
			{
				xLeaf.m_pucFeatureVisibilities[ iModuleIndex ] = ucVisible;
			}
		}

		// stream in the skybox visibilty into the last slot
		xStream >> xLeaf.m_pucFeatureVisibilities[ Asura_Visibility_System::s_uNumberOfVisibilityFeatures - 1 ];
	}

	Asura_Visibility_System::CreateNodeVisibilityFlags();

	Asura_Visibility_System::s_bForceVisRecalcForCurrentCameraNode = true;

	return true;
}

#if defined( ASURA_TOOLS )

bool Asura_Chunk_Visibility::Create( class Asura_Chunk_Stream& xStream )
{
	// KJFL - 15 December 2005 - see header for breakdown of chunk layout
	xStream.WriteChunk_Start( ASURA_CHUNK_VISIBILITY, CHUNK_VERSION, 0 );

	xStream << Asura_Visibility_System::s_uNumberOfNodes;
	xStream << Asura_Visibility_System::s_uNumberOfLeaves;
	xStream << Asura_Visibility_System::s_uNumberOfVisibilityFeatures;

	if ( Asura_Visibility_System::s_uNumberOfNodes == 0 )
	{
		xStream.WriteChunk_End();
		return true;
	}

	for( u_int u=0; u<Asura_Visibility_System::s_uNumberOfNodes; ++u )
	{
		Asura_Visibility_Node& xNode = Asura_Visibility_System::s_pxVisibilityNodes[ u ];
	
		xStream << xNode.m_xAABB;  

		xStream << xNode.m_usParent;
		xStream << xNode.m_usLeftChild;

		xStream << xNode.m_usLeafIndex;
	}

	for( u_int u=0; u<Asura_Visibility_System::s_uNumberOfLeaves; ++u )
	{
		Asura_Visibility_Leaf& xLeaf = Asura_Visibility_System::s_pxVisibilityLeaves[ u ];

		xLeaf.m_xLeafVisibilities.Save( xStream );

		for ( u_int v=0; v<Asura_Visibility_System::s_uNumberOfVisibilityFeatures; ++v )
		{
			xStream << xLeaf.m_pucFeatureVisibilities[v];
		}

	}
	

	xStream.WriteChunk_End();

	return true;
}
#endif // ASURA_TOOLS

#endif // #if defined(ASURA_USE_NEW_VISIBILITY_SYSTEM)
