//
// Asura_Visibility_Node.h
//
// Created by KJFL - 15 December 2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_VISIBILITY_NODE_H__
#define __ASURA_VISIBILITY_NODE_H__

#if defined(ASURA_USE_NEW_VISIBILITY_SYSTEM)

#include "Core/Asura_Maths.h"


class Asura_Chunk_Stream;

// KJFL - 21 November 2007 -
// Currently 32 bytes for cache friendly-ness, though it may
// be worth compressing the BB etc. Don't want to optimise
// memory too early.
class Asura_Visibility_Node
{
	public:
		
		const Asura_Bounding_Box& GetAABB( void ) const { return m_xAABB; }

		u_int GetParent( void ) const { return m_usParent; }
		u_int GetLeftChild( void ) const { return m_usLeftChild; }
		u_int GetRightChild( void ) const { return m_usLeftChild+1; }
		u_int GetLeafIndex( void ) const { return m_usLeafIndex; }
		
#ifdef ASURA_TOOLS // cleaner than making it a friend?
		
		void Tools_Initialise( const Asura_Bounding_Box& xAABB, u_int uParent, u_int uLeftChild, u_int uLeafIndex )
		{
			m_xAABB = xAABB;
			m_usParent = static_cast<u_short>(uParent);
			m_usLeftChild = static_cast<u_short>(uLeftChild);
			m_usLeafIndex = static_cast<u_short>(uLeafIndex);
		}

#endif //ASURA_TOOLS

		bool RaySegmentIntersectsViewCell( const Asura_Vector_3& xStart, const Asura_Vector_3& xEnd ) const
		{
			Asura_Vector_3 xBeta = xEnd - xStart;

			float fLimit = xBeta.Normalise();
			float fDistance = fLimit;
			bool bHit = Asura_Maths::RayIntersectsBoundingBox( xStart, xBeta, m_xAABB, &fDistance );

			return ( bHit && fDistance <= fLimit );
		}

	private: 

		friend class Asura_Chunk_Visibility;

		// bounding box for the node - inside parent's, 
		// and completely contains children's.
		Asura_Bounding_Box	m_xAABB; 

		// want to be able to move up and down the tree
		// so store parent and left child. Right child
		// index will be left + 1 implicitly.
		// Hmm, might use left child == 0 to indicate
		// leaf node, so LeafIndex can be any value.
		u_short				m_usParent;
		u_short				m_usLeftChild;

		// if this is a leaf, give lookup index.
		u_short				m_usLeafIndex;

		// Used to have two bytes here I removed.

		// TODO - change the above u_shorts to u_int and merge LeafIndex and LeftChild? 
		// (Do something like if m_usLeftChild > Number of Nodes then it's a leaf index (with offset)
		// u_ints might run faster.
};

class Asura_Visibility_NodeFlags
{
	public:

		u_char GetANDedViewIndependentFlags( void ) const { return m_ucANDedViewIndependentFlags; }
		u_char GetORedViewIndependentFlags( void ) const { return m_ucORedViewIndependentFlags; }
		u_char GetANDedVisibilityFlags( void ) const { return m_ucANDedVisibilityFlags; }
		u_char GetORedVisibilityFlags( void ) const { return m_ucORedVisibilityFlags; }

		void SetANDedViewIndependentFlags( u_char ucFlags ) { m_ucANDedViewIndependentFlags = ucFlags; }
		void SetORedViewIndependentFlags( u_char ucFlags ) { m_ucORedViewIndependentFlags = ucFlags; }
		void SetANDedVisibilityFlags( u_char ucFlags ) { m_ucANDedVisibilityFlags = ucFlags; }
		void SetORedVisibilityFlags( u_char ucFlags ) { m_ucORedVisibilityFlags = ucFlags; }

	private:
		// A neat 32 bit structure.
		
		// ORed data straight from the visibility system - before any frustum culling.
		// This is updated only as the camera changes visibility node (so not every frame).
		u_char				m_ucANDedViewIndependentFlags;	
		u_char				m_ucORedViewIndependentFlags;

		// ORed and ANDed visibility data made from using the above data combined with 
		// hierarchical frustum checks (so changes every frame).
		u_char				m_ucANDedVisibilityFlags;
		u_char				m_ucORedVisibilityFlags;
};

class Asura_Visibility_Bitfield
{
	public:

		Asura_Visibility_Bitfield()
		: m_uSizeOfCompressedData(0)
		, m_pucCompressedData(0)
		{}

		~Asura_Visibility_Bitfield()
		{
			delete [] m_pucCompressedData;
		}

		void Reset( void )
		{
			delete [] m_pucCompressedData;
			
			m_pucCompressedData = 0;
			m_uSizeOfCompressedData = 0;
		}

		void Save( Asura_Chunk_Stream& xStream ) const;
		void Load( Asura_Chunk_Stream& xStream );

		void Compress( const bool* const pbSource, u_int uNumberOfBytes );

		u_int Decompress( bool* pbTarget ) const;
		
		u_int Decompress( u_char* pucTarget ) const;

		bool Query( u_int uIndex ) const;

		// returns true if data changed
		bool Set( u_int uIndex );

		// Memory used doesn't include the pointer (which pretty much
		// all classes would need for dynamic sizes) but it does
		// include the extra u_int to store the compressed size
		u_int GetMemoryUsed( void ) const
		{
			u_int uMemoryUsed = sizeof ( u_int );

			if ( m_pucCompressedData )
			{
				uMemoryUsed += m_uSizeOfCompressedData;
			}

			return uMemoryUsed;
		}

	private:

		u_int	m_uSizeOfCompressedData;
		u_char*	m_pucCompressedData;
};

class Asura_Visibility_Leaf
{
	public:

		// KJFL - 21 November 2007 - 
		// So... simple arrays to begin with. 
		// Toying with using a RLE bitfield for the leaf visibilities.
		// Unsure about the best storage for the module/feature visibilities;
		// needs some research into usage on "average" environments.

		Asura_Visibility_Leaf()
		: m_xLeafVisibilities()
	//	, m_pucLeafVisibilities(0)
		, m_pucFeatureVisibilities(0)
	//	, m_uCompressedLeafVisibilitiesSize(0)
		{
		}

		~Asura_Visibility_Leaf()
		{
	//		delete [] m_pucLeafVisibilities;
			delete [] m_pucFeatureVisibilities;

		}

		void Reset( void )
		{
			m_xLeafVisibilities.Reset();
			
			delete [] m_pucFeatureVisibilities;
			m_pucFeatureVisibilities = 0;
		}

		bool IsLeafVisible( u_int uLeafIndex ) const;

		bool IsFeatureVisible( u_int uFeatureIndex ) const;

		bool SetVisibleFeaturesArray( u_char* pucArray, u_char ucBitPattern, u_int uNumberOfFeatures ) const;

		#ifdef ASURA_TOOLS // Data can only be refined in Tools builds 

		bool Tools_RefineFeatureVisibility( u_int uFeatureID0, u_int uFeatureID1 );
	
		bool Tools_RefineLeafVisibility( u_int uLeafIndex );

		void Tools_DeleteModule( u_int uModuleIndex );

		void Tools_RemoveLinks( void );
	
		#endif

		void Compress( const bool* const pbSource, u_int uNumberOfBytes );

		void Decompress( bool* pbTarget );

	private: 
		
		// TODO: can probably remove this friend level all together if careful
		friend class Tools_Visibility_System;
		friend class Asura_Chunk_Visibility;

		Asura_Visibility_Bitfield m_xLeafVisibilities;

	//	u_char*	m_pucLeafVisibilities;
		u_char*	m_pucFeatureVisibilities;
	//	u_int	m_uCompressedLeafVisibilitiesSize;
};

#endif //#if defined(ASURA_USE_NEW_VISIBILITY_SYSTEM)

#if defined(ASURA_USE_VISIBILITY_SYSTEM)

#include "Core/Asura_Maths.h"

class Asura_Visibility_Node
{
	public:

		u_int				m_uFrameStamp;

		u_int				m_uStrip;

		bool				m_bVisible;
		bool				m_bPreviouslyVisible;

		Asura_Bounding_Box	m_xBB;

		u_int				m_uLeftChild;
		u_int				m_uRightChild;

		u_int				m_uParent;

};

#endif //#if defined(ASURA_USE_VISIBILITY_SYSTEM)

#endif//__ASURA_VISIBILITY_NODE_H__


