#ifndef __POSTPROCMANAGER__
#define __POSTPROCMANAGER__

#include "Singleton.h"

// Including STL lists for the effect list
#pragma warning(push)			// Pushing a warning disabler...
#pragma warning(disable:4995)	// to disable deprecated warning...
#include <list>
using namespace std;
#pragma warning(pop)			// Restoring the previous warning states


//------------------------------------------------------------------------------------------
// Forward declarations
//------------------------------------------------------------------------------------------
struct PPVert;					// The vertex used for the quad mesh

class TargetableTexture;		// A class that manage a texture and its use as render target
class PPEffectsCommon;			// Our common effect
class PostProcFXFilesManager;	// The post-process files manager
class PostProcFXChain;			// The post-process effects chain
class ScaledPPEffect;			// To communicate scaled effect own parameters (if any) to PerformSinglePostprocess


//------------------------------------------------------------------------------------------
// PostProcManager is a singleton-type class
// Managing the render targets for post-process
//------------------------------------------------------------------------------------------
class PostProcManager : public Singleton<PostProcManager>
{

	// My friend singleton is no simpleton...(in fact he IS but, sssshh) :P
	friend class Singleton<PostProcManager>;


	private:

		// The targets
		int m_nNbSimultRTs;									// The max number of simultaneous RTs (see D3DCAPS)
		int m_nNbAvailableRTs;								// The number of RTs we created
		D3DFORMAT m_TargetFormat;							// The format we'll use for our targets (64 / 32 bits ARGB)
		TargetableTexture * m_pInitialTextureTargets;		// A set of render targets to keep the initial scene render intact through the post-processing
		TargetableTexture * m_pTextureTargetsSwapSet[2];	// Two sets of render targets (will be swapped for effect chaining)
		
		// The postprocess helpers
		int m_nCurrentSrcSet;								// The current set of render targets to use
		PPEffectsCommon * m_pCurrentEffect;					// The currently used effect
		LPDIRECT3DTEXTURE9 * m_pSrcTextures;				// A set of pointer to textures to propagate the result of every effect for every RTs
		LPDIRECT3DSURFACE9 m_pOldRT;						// An extra surface to backup one important when needed (most of the time, RT0)

		// The geometry (basically a quad on which we'll do every renders
		PPVert * m_pQuad;									// The quad vertices list used for post processing
		LPDIRECT3DVERTEXBUFFER9 m_pQuadVB;					// The quad mesh in form of a vertex buffer
		LPDIRECT3DVERTEXDECLARATION9 m_pVertDeclPP;			// The vertex declaration to use with the quad mesh
		D3DXVECTOR2 m_vUVExtend;							// The extends for the quad post-process UVs

		// Construction / Destruction
		PostProcManager();
		~PostProcManager();


	public:

		// RTs management
		HRESULT CreateRTTextureSets(const UINT Width, const UINT Height, const int nIndex);	// Create a texture with RT usage
		HRESULT Init(const UINT Width, const UINT Height, const int nCount);				// Create a serie of identical RT textures
		HRESULT SwapRTSets();		// Swap m_nCurrentSrcSet and change the render targets
		void EmptyRTsArrays();		// Empty the render targets array
		HRESULT BackupRT0();		// Store RT0 in m_pOldRT
		
		// Quad management
		void CreateQuad();								// Create a quad the same resolution as the screen
		void SetQuadDimToScreen();						// Setup the quad to be the same size as the screen
		void ScaleQuad(const D3DXVECTOR2 * pScaler);	// Scale the quad using the X&Y scalers parameters
		void UpdateQuadVB();							// Update the quad vertex buffer with vertices list (create the VB if not exist)
		void ReleaseQuad();								// Delete the quad mesh

		// Post-processing functions
		HRESULT SetupInitialRenderTargets(const bool bClearRTs = true);
		HRESULT PerformPostProcess(PostProcFXChain * pFXChain, float fTime);
		HRESULT PerformSinglePostProcess(ScaledPPEffect * pScaledPPEffect) const;

		// DirectX device handling
		HRESULT OnResetDevice(const int nWidth, const int nHeight);
		void OnLostDevice();
};

#endif