#pragma once

#include "dllinterface.h"
#include "dxtexture.h"

class DXFUNCTIONS_API RenderSurface : public DXRessource
{
protected:

	friend TextureManager;
	friend ListElement<RenderSurface>;
	friend LList<RenderSurface>;

	FORMAT m_Format;

	TextureManager* const m_Manager;

	RenderSurface(TextureManager* const manager, const FORMAT fmt);
	~RenderSurface(void){}

public:

	FORMAT GetFormat(void) const { return m_Format; }
	TextureManager* GetManager(void) const { return m_Manager; }

	virtual void Release(void);
};

class DXFUNCTIONS_API DepthStencilBuffer : public RenderSurface
{
	friend TextureManager;
	friend ListElement<DepthStencilBuffer>;
	friend LList<DepthStencilBuffer>;

	LPDIRECT3DSURFACE9	m_Restore;
	LPDIRECT3DSURFACE9 m_Surface;

	unsigned m_XL;
	unsigned m_YL;

	void DoRestore(void);
	void DoInvalidate(void) { SAFERELEASE(m_Surface); }

protected:

	DepthStencilBuffer(TextureManager* const manager, const int xl, const int yl, const FORMAT fmt);
	~DepthStencilBuffer(void) { Invalidate(); }

public:

	void StartRender(void);
	void EndRender(void);
};

class DXFUNCTIONS_API DepthStencilTexture : public RenderSurface
{
	friend TextureManager;
	friend ListElement<DepthStencilTexture>;
	friend LList<DepthStencilTexture>;

	LPDIRECT3DSURFACE9	m_Restore;
	DXTexture*			m_Surface;

//	unsigned m_XL;
//	unsigned m_YL;

	//void DoRestore(void);
	//void DoInvalidate(void) { SAFERELEASE(m_Surface); }

protected:

	DepthStencilTexture(TextureManager* const manager, const int xl, const int yl, const FORMAT fmt);
	~DepthStencilTexture(void) {  SAFERELEASE(m_Surface); }

public:

	DXTexture* GetSurface(void) const { return m_Surface; }

	void StartRender(void);
	void EndRender(void);
};

class DXFUNCTIONS_API RenderTarget : public RenderSurface
{
	friend TextureManager;
	friend ListElement<RenderTarget>;
	friend LList<RenderTarget>;

	//unsigned			m_iRTRestore;
	//LPDIRECT3DSURFACE9	m_Restore;

	//surface is restored by manager, depthstencil either

protected:

	DXSurface*			m_Surface;
	DepthStencilBuffer*	m_DepthStencil;

	RenderTarget(TextureManager* const manager, const FORMAT fmt);
	virtual ~RenderTarget(void) { SAFERELEASE(m_Surface); SAFERELEASE(m_DepthStencil); }
	//depth stencil surface cant be released here, it is done in the Release(), because otherwise when the texturemanager list gets destroyed
	//the depthstencil surface deletion would conflict with the List.Clear();

public:

	void Release(void);

	virtual void CreateDepthStencil(const FORMAT fmt) = 0;

	void ReleaseDepthStencil(void) { SAFERELEASE(m_DepthStencil); }
	void SetDepthStencil(DepthStencilBuffer* surface) {SAFERELEASE(m_DepthStencil); m_DepthStencil = surface; }
	DepthStencilBuffer* GetDepthStencil(void) const {return m_DepthStencil;}

	DXSurface* GetSurface(void) const {return m_Surface;}
};

class DXFUNCTIONS_API RenderTexture : public RenderTarget
{
	unsigned			m_iRTRestore;
	LPDIRECT3DSURFACE9	m_Restore;

protected:
	friend TextureManager;

	unsigned m_XL;
	unsigned m_YL;

	FORMAT m_DSFormat;

	RenderTexture(TextureManager* const manager, const unsigned xl, const unsigned yl, const FORMAT fmt);

public:
	void StartRender(const unsigned iRT);
	void EndRender(void);

	virtual void CreateDepthStencil(const FORMAT fmt);

	unsigned GetXL(void) const { return m_XL; }
	unsigned GetYL(void) const { return m_YL; }

	DXTexture* GetTexture(void) { return (DXTexture*)m_Surface; }
};

class DXFUNCTIONS_API CubeRenderTexture : public RenderTarget
{
	unsigned m_EdgeLength;

	unsigned			m_iRTRestore;
	LPDIRECT3DSURFACE9	m_Restore;

protected:
	friend TextureManager;

	CubeRenderTexture(TextureManager* const manager, const unsigned edgelength, const FORMAT fmt);
	
public:

	void CreateDepthStencil(const FORMAT fmt);

	void StartRender(const unsigned iRT, const D3DCUBEMAP_FACES face);
	void EndRender(void);

	unsigned GetEdgeLength(void) const { return m_EdgeLength; }
};

class DXViewPort;

class DXFUNCTIONS_API ViewPortRenderTexture : public RenderTexture
{
	DXViewPort* m_pVP;
	float m_Scale;

protected:
	friend TextureManager;

	ViewPortRenderTexture(TextureManager* const manager, DXViewPort* const vp, const FORMAT fmt, const float scale);
	~ViewPortRenderTexture(void);

public:

	void DoInvalidate(void);
	void DoRestore(void);

	//void CreateDepthStencil(const FORMAT fmt);

	//void StartRender(const unsigned iRT);
	//void EndRender(void);
};

//TODO: derive from rendertexture
class DXFUNCTIONS_API OffscreenRenderTexture : public RenderSurface
{
	friend TextureManager;
	friend ListElement<OffscreenRenderTexture>;
	friend LList<OffscreenRenderTexture>;

	DXTexture* m_OffscreenSurface;
	RenderTexture* m_GPUSurface;

	unsigned			m_XL;
	unsigned			m_YL;

	unsigned			m_iRTRestore;
	LPDIRECT3DSURFACE9	m_RenderTargetRestore;

	bool m_AutoLock; //system surface is always locked and immediately readable
	bool m_AutoRestore; //copy conten from systemmem to device after restore
	bool m_AutoUpdate; //update system surface after endrender

protected:
	OffscreenRenderTexture(TextureManager* const manager, const unsigned xl, const unsigned yl, const FORMAT format, const bool autolock, const bool autorestore, const bool autoupdate);
	~OffscreenRenderTexture(void) { m_OffscreenSurface->Release(); /*m_GPUSurface->Release();*/} 
	//the gpu surface is not release in destructor, because there is a conflict in the destruct from the texturemanager with the order in the listelements
	//because in the texturemanager destructor everything is released anyway, it is only manually release in Relase();

	//surfaces automatically gets restored/invalidated by manager
	//just update gpusurface contnent only if flag set
	void DoRestore(void) { if(m_AutoRestore)UpdateGPUSurface(); }

public:

	void Release(void);

	void UpdateGPUSurface(void);
	void UpdateOffscreenSurface(void);

	RenderTexture* GetGPUSurface(void) const {return m_GPUSurface;}
	DXTexture* GetOffscreenSurface(void) const {return m_OffscreenSurface;}

	const LOCKED_RECT* GetLockedData(void) const {return m_OffscreenSurface->GetLockedData();}
	const LOCKED_RECT* Lock(void) { return m_OffscreenSurface->Lock();}
	void Unlock(void) {m_OffscreenSurface->Unlock();}

	TextureManager* GetManager(void) const {return m_Manager;}	

	void StartRender(const unsigned iRT);
	void EndRender(void);

	unsigned GetXL(void) const { return m_XL; }
	unsigned GetYL(void) const { return m_YL; }

//	bool InRenderSequence(void) const {return m_InRenderSequence;}
};
