//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======//
//
// Purpose: 
//
// $Revision: $
// $NoKeywords: $
//
// This file contains code to allow us to associate client data with bsp leaves.
//
//===========================================================================//

#if !defined( CLIENTLEAFSYSTEM_H )
#define CLIENTLEAFSYSTEM_H
#ifdef _WIN32
#pragma once
#endif

#include "igamesystem.h"
#include "engine/IClientLeafSystem.h"
#include "cdll_int.h"
#include "ivrenderview.h"
#include "tier1/mempool.h"
#include "tier1/refcount.h"


//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
struct WorldListInfo_t;
class IClientRenderable;
class Vector;
class CGameTrace;
typedef CGameTrace trace_t;
struct Ray_t;
class Vector2D;
class CStaticProp;
class CVolumeCuller;


//-----------------------------------------------------------------------------
// Render groups
//-----------------------------------------------------------------------------
enum RenderGroup_t
{
	RENDER_GROUP_OPAQUE = 0,
	RENDER_GROUP_TRANSLUCENT,
	RENDER_GROUP_TRANSLUCENT_IGNOREZ,
	RENDER_GROUP_COUNT, // Indicates the groups above are real and used for bucketing a scene
};


//-----------------------------------------------------------------------------
// Handle to an renderables in the client leaf system
//-----------------------------------------------------------------------------
enum
{
	DETAIL_PROP_RENDER_HANDLE = (ClientRenderHandle_t)0xfffe
};


//-----------------------------------------------------------------------------
// Distance fade information
//-----------------------------------------------------------------------------
struct DistanceFadeInfo_t
{
	float m_flMaxDistSqr;		// distance at which everything is faded out
	float m_flMinDistSqr;		// distance at which everything is unfaded
	float m_flFalloffFactor;	// 1.0f / ( maxDistSqr - MinDistSqr )
								// opacity = ( maxDist - distSqr ) * falloffFactor 
};


class CClientRenderablesList : public CRefCounted<>
{
	DECLARE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList );

public:
	CClientRenderablesList()
	{
		int i;
		for( i=0; i < RENDER_GROUP_COUNT; i++ )
		{
			m_RenderGroupCounts[i] = 0;
		}
		m_nBoneSetupDependencyCount = 0;
	}

	enum
	{
		MAX_GROUP_ENTITIES = 4096,
		MAX_BONE_SETUP_DEPENDENCY = 64,
	};

	struct CEntry
	{
		IClientRenderable	*m_pRenderable;
		unsigned short		m_iWorldListInfoLeaf; // NOTE: this indexes WorldListInfo_t's leaf list.
		RenderableInstance_t m_InstanceData;
		uint8				m_nModelType : 6;		// See RenderableModelType_t
		uint8				m_bShadowDepthNoCache : 1;	// the renderable cannot be cached in shadow depth cache
		uint8				m_TwoPass : 1;
		bool				m_bIsCombinedModel;
	};

	// The leaves for the entries are in the order of the leaves you call CollateRenderablesInLeaf in.
	DistanceFadeInfo_t	m_DetailFade;
	CEntry				m_RenderGroups[RENDER_GROUP_COUNT][MAX_GROUP_ENTITIES];
	int					m_RenderGroupCounts[RENDER_GROUP_COUNT];
	int					m_nBoneSetupDependencyCount;
	IClientRenderable	*m_pBoneSetupDependency[MAX_BONE_SETUP_DEPENDENCY];
};

struct ViewmodelRenderableInstance_t : public RenderableInstance_t
{
	uint8 m_bTwoPass;
};
//-----------------------------------------------------------------------------
// Render list for viewmodels
//-----------------------------------------------------------------------------
class CViewModelRenderablesList
{
public:
	enum
	{
		VM_GROUP_OPAQUE = 0,
		VM_GROUP_TRANSLUCENT,
		VM_GROUP_COUNT,
	};

	struct CEntry
	{
		IClientRenderable	*m_pRenderable;
		ViewmodelRenderableInstance_t m_InstanceData;
	};

	typedef CUtlVectorFixedGrowable< CEntry, 32 > RenderGroups_t;

	// The leaves for the entries are in the order of the leaves you call CollateRenderablesInLeaf in.
	RenderGroups_t	m_RenderGroups[VM_GROUP_COUNT];
};


//-----------------------------------------------------------------------------
// Used to do batched screen size computations
//-----------------------------------------------------------------------------
struct ScreenSizeComputeInfo_t
{
	VMatrix m_matViewProj;
	Vector m_vecViewUp;
	int m_nViewportHeight;
};

void ComputeScreenSizeInfo( ScreenSizeComputeInfo_t *pInfo );
float ComputeScreenSize( const Vector &vecOrigin, float flRadius, const ScreenSizeComputeInfo_t& info );


//-----------------------------------------------------------------------------
// Used by CollateRenderablesInLeaf
//-----------------------------------------------------------------------------
struct SetupRenderInfo_t
{
	mutable WorldListInfo_t *		m_pWorldListInfo;
	mutable CClientRenderablesList *m_pRenderList;
	Vector m_vecRenderOrigin;
	Vector m_vecRenderForward;
	int m_nRenderFrame;
	int m_nDetailBuildFrame;	// The "render frame" for detail objects

	float m_flRenderDistSq;
	int m_nViewID;
	int m_nBuildViewID;
	int m_nOcclustionViewID;
	mutable const CVolumeCuller *	m_pCSMVolumeCuller;
	mutable const Frustum_t*		m_pFrustum;
	mutable Frustum_t**				m_ppFrustumList;
	ScreenSizeComputeInfo_t m_screenSizeInfo;

	bool m_bDrawDetailObjects : 1;
	bool m_bDrawTranslucentObjects : 1;
	bool m_bFastEntityRendering: 1;
	bool m_bDrawDepthViewNonCachedObjectsOnly : 1;
	bool m_bCSMView : 1;

	SetupRenderInfo_t()
	{
		m_pWorldListInfo = NULL;
		m_pRenderList = NULL;
		m_pCSMVolumeCuller = NULL;
		m_pFrustum = NULL;
		m_ppFrustumList = NULL;
		m_nBuildViewID = -1;
		m_nOcclustionViewID = -1;

		m_bDrawDetailObjects = true;
		m_bDrawTranslucentObjects = true;
		m_bFastEntityRendering = false;
		m_bDrawDepthViewNonCachedObjectsOnly = false;
		m_bCSMView = false;
	}
};


//-----------------------------------------------------------------------------
// A handle associated with shadows managed by the client leaf system
//-----------------------------------------------------------------------------
typedef unsigned short ClientLeafShadowHandle_t;
enum
{
	CLIENT_LEAF_SHADOW_INVALID_HANDLE = (ClientLeafShadowHandle_t)~0 
};


//-----------------------------------------------------------------------------
// The client leaf system
//-----------------------------------------------------------------------------
abstract_class IClientLeafShadowEnum
{
public:
	// The user ID is the id passed into CreateShadow
	virtual void EnumShadow( ClientShadowHandle_t userId ) = 0;
};


// subclassed by things which wish to add per-leaf data managed by the client leafsystem
class CClientLeafSubSystemData
{
public:
	virtual ~CClientLeafSubSystemData( void )
	{
	}
};


// defines for subsystem ids. each subsystem id uses up one pointer in each leaf
#define CLSUBSYSTEM_DETAILOBJECTS 0
#define N_CLSUBSYSTEMS 1



//-----------------------------------------------------------------------------
// The client leaf system
//-----------------------------------------------------------------------------
abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameSystemPerFrame
{
public:
	// Adds and removes renderables from the leaf lists
	virtual void AddRenderable( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled = 0xFFFFFFFF ) = 0;

	// This tells if the renderable is in the current PVS. It assumes you've updated the renderable
	// with RenderableChanged() calls
	virtual bool IsRenderableInPVS( IClientRenderable *pRenderable ) = 0;

	virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ) =0;
	virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ) =0;

	virtual void SetDetailObjectsInLeaf( int leaf, int firstDetailObject, int detailObjectCount ) = 0;
	virtual void GetDetailObjectsInLeaf( int leaf, int& firstDetailObject, int& detailObjectCount ) = 0;

	// Indicates which leaves detail objects should be rendered from, returns the detais objects in the leaf
	virtual void DrawDetailObjectsInLeaf( int leaf, int frameNumber, int& firstDetailObject, int& detailObjectCount ) = 0;

	// Should we draw detail objects (sprites or models) in this leaf (because it's close enough to the view)
	// *and* are there any objects in the leaf?
	virtual bool ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber ) = 0;

	// Call this when a renderable origin/angles/bbox parameters has changed
	virtual void RenderableChanged( ClientRenderHandle_t handle ) = 0;

	// Put renderables into their appropriate lists.
	virtual void BuildRenderablesList( const SetupRenderInfo_t &info ) = 0;
#if defined(_PS3)
	virtual void BuildRenderablesList_PS3_Epilogue( void ) = 0;
#endif

	// Put renderables in the leaf into their appropriate lists.
	virtual void CollateViewModelRenderables( CViewModelRenderablesList *pList ) = 0;

	// Call this to deactivate static prop rendering..
	virtual void DrawStaticProps( bool enable ) = 0;

	// Call this to deactivate small object rendering
	virtual void DrawSmallEntities( bool enable ) = 0;

	// The following methods are related to shadows...
	virtual ClientLeafShadowHandle_t AddShadow( ClientShadowHandle_t userId, unsigned short flags ) = 0;
	virtual void RemoveShadow( ClientLeafShadowHandle_t h ) = 0;

	// Project a shadow
	virtual void ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0;

	// Project a projected texture spotlight
	virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0;

	// Find all shadow casters in a set of leaves
	virtual void EnumerateShadowsInLeaves( int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum ) = 0;

	// Fill in a list of the leaves this renderable is in.
	// Returns -1 if the handle is invalid.
	virtual int GetRenderableLeaves( ClientRenderHandle_t handle, int leaves[128] ) = 0;

	// Get leaves this renderable is in
	virtual bool GetRenderableLeaf ( ClientRenderHandle_t handle, int* pOutLeaf, const int* pInIterator = 0, int* pOutIterator = 0 ) = 0;

	// Draw translucent objects in the opaque renderables pass
	virtual void EnableForceOpaquePass( ClientRenderHandle_t handle, bool bEnable ) = 0;
	virtual bool IsEnableForceOpaquePass( ClientRenderHandle_t handle ) const = 0;

	// Use alternate translucent sorting algorithm (draw translucent objects in the furthest leaf they lie in)
	virtual void EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable ) = 0;

	// Mark this as rendering with viewmodels
	virtual void RenderWithViewModels( ClientRenderHandle_t handle, bool bEnable ) = 0;
	virtual bool IsRenderingWithViewModels( ClientRenderHandle_t handle ) const = 0;

	// Call this if the model changes
	virtual void SetTranslucencyType( ClientRenderHandle_t handle, RenderableTranslucencyType_t nType ) = 0;
	virtual RenderableTranslucencyType_t GetTranslucencyType( ClientRenderHandle_t handle ) const = 0;
	virtual void SetModelType( ClientRenderHandle_t handle, RenderableModelType_t nType = RENDERABLE_MODEL_UNKNOWN_TYPE ) = 0;
	virtual void EnableSplitscreenRendering( ClientRenderHandle_t handle, uint32 nFlags ) = 0;

	// Suppress rendering of this renderable
	virtual void EnableRendering( ClientRenderHandle_t handle, bool bEnable ) = 0;

	// Indicates this renderable should bloat its client leaf bounds over time
	// used for renderables with oscillating bounds to reduce the cost of
	// them reinserting themselves into the tree over and over.
	virtual void EnableBloatedBounds( ClientRenderHandle_t handle, bool bEnable ) = 0;

	// Indicates this renderable should always recompute its bounds accurately
	virtual void DisableCachedRenderBounds( ClientRenderHandle_t handle, bool bDisable ) = 0;

	// Recomputes which leaves renderables are in
	virtual void RecomputeRenderableLeaves() = 0;

	// Warns about leaf reinsertion
	virtual void DisableLeafReinsertion( bool bDisable ) = 0;

	//Assuming the renderable would be in a properly built render list, generate a render list entry
	virtual RenderGroup_t GenerateRenderListEntry( IClientRenderable *pRenderable, CClientRenderablesList::CEntry &entryOut ) = 0; 

	// Get renderable that render bound intersect with the query box
	virtual int GetEntitiesInBox( C_BaseEntity **pEntityList, int listMax, const Vector& vWorldSpaceMins, const Vector& vWorldSpaceMaxs ) = 0;

	// Mark as rendering in the reflection
	virtual bool IsRenderingInFastReflections( ClientRenderHandle_t handle ) const = 0;

	// Enable/disable rendering into the shadow depth buffer
	virtual void DisableShadowDepthRendering( ClientRenderHandle_t handle, bool bDisable ) = 0;

	// Enable/disable rendering into the CSM buffer and rendering usig CSM's
	virtual void DisableCSMRendering( ClientRenderHandle_t handle, bool bDisable ) = 0;

	// Enable/disable caching in the shadow depth buffer
	virtual void DisableShadowDepthCaching( ClientRenderHandle_t handle, bool bDisable ) = 0;

	virtual void ComputeAllBounds( void ) = 0;

#if defined(_PS3)
	virtual void PrepRenderablesListForSPU( void ) = 0;
#endif
};


//-----------------------------------------------------------------------------
// Singleton accessor
//-----------------------------------------------------------------------------
extern IClientLeafSystem *g_pClientLeafSystem;
inline IClientLeafSystem* ClientLeafSystem()
{
	return g_pClientLeafSystem;
}


#endif	// CLIENTLEAFSYSTEM_H