/*!
	@project Rune
	@file RuEngineBase.h

	Copyright (c) 2004 All rights reserved

	@author John Tang
	@date 2004/07/08
*/

#ifndef _RUENGINEBASE_H_
#define _RUENGINEBASE_H_

#include "../../Core/Type/RuType_Base.h"
#include "../../Core/Memory/RuMemoryManager.h"
#include "../../Core/Utility/RuUtility_Profile.h"

#include "../../Engine/Type/RuType_Core.h"
#include "../../Engine/Type/RuType_Flags.h"
#include "../../Engine/Type/RuType_Vertex.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

// Forward declarations
class IRuEngine;

// Globals
extern RUAPI IRuEngine*				g_ruEngine;
extern RUAPI CRuProfiler			g_ruProfiler;

// ************************************************************************************************************************************************************

// Profiler macros
//#define RUPROFILE_ENABLE

#ifdef RUPROFILE_ENABLE

	#define RUPROFILE_INITIALIZE													\
		g_ruProfiler.CreateProbe("scene manager");									\
		g_ruProfiler.CreateProbe("sorting");										\
		g_ruProfiler.CreateProbe("submission");										\
		g_ruProfiler.CreateProbe("parameters");										\
		g_ruProfiler.CreateProbe("render");											\
		g_ruProfiler.CreateProbe("instance");										\
		g_ruProfiler.CreateProbe("texture");

	#define RUPROFILE_SAMPLE_BEGIN(probeName)										\
		g_ruProfiler.BeginSample(probeName);

	#define RUPROFILE_SAMPLE_END(probeName)											\
		g_ruProfiler.EndSample(probeName);

	#define RUPROFILE_SAMPLE_CLEAR()												\
		g_ruProfiler.ClearProbeValues();

#else

	#define RUPROFILE_INITIALIZE
	#define RUPROFILE_SAMPLE_BEGIN(probeName)
	#define RUPROFILE_SAMPLE_END(probeName)
	#define RUPROFILE_SAMPLE_CLEAR()

#endif

// ************************************************************************************************************************************************************

/*!
	IRuEngineResource
	@author John Tang
	@version 2004/05/12
*/
class IRuEngineResource : public IRuObject
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	IRuEngine*								m_engine;													// Engine that owns this resource
	UINT32									m_priority;													// Resource priority

public:
											IRuEngineResource();
	virtual									~IRuEngineResource();

	IRuEngine*								GetEngine();												// Gets the engine that owns this resource
	void									SetEngine(IRuEngine *engine);								// Sets the engine that owns this resource

	virtual UINT32							GetPriority() const;										// Gets resource priority
	virtual void							SetPriority(UINT32 priority);								// Sets resource priority

	virtual void							Invalidate() = 0;											// Invalidate the resource
	virtual BOOL							IsInvalidated() const = 0;									// Check whether the resource is lost
	virtual BOOL							Restore() = 0;												// Attempt to restore the resource
};

// ************************************************************************************************************************************************************

/*!
	IRuVertexDeclaration
	@author John Tang
	@version 2004/10/07
*/
class IRuVertexDeclaration : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuVertexDeclaration();

	virtual const CRuVertexElement*			GetVertexElements() const = 0;								// Gets the vertex elements defining this vertex declaration
	virtual void							Select() const = 0;											// Selects the vertex declaration for use

	virtual INT32							GetNumStreams() const = 0;									// Gets the number of streams required by the vertex declaration
	virtual INT32							GetStreamStride(INT32 streamIndex) const = 0;				// Gets the size of each vertex in the specified stream
};

// ************************************************************************************************************************************************************

/*!
	IRuVertexBuffer
	@author John Tang
	@version 2004/05/12
*/
class IRuVertexBuffer : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuVertexBuffer();

	virtual void*							Lock(UINT offset = 0, UINT size = 0) = 0;						// Lock buffer using defaults
	virtual void*							Lock(UINT offset, UINT size, DWORD lockFlags) = 0;				// Lock buffer
	virtual void							Unlock() = 0;													// Unlock buffer

	virtual void							Select(UINT32 streamIndex, UINT32 stride) const = 0;			// Select the buffer into the specified stream for use

	virtual UINT32							GetSize() const = 0;											// Get the size of the buffer
	virtual UINT32							GetOffset() const = 0;											// Gets the offset to the start of vertex data if the buffer is shared

	virtual BOOL							Subdivide(INT32 numChildVBs, IRuVertexBuffer **childVBOut) = 0;	//!< Splits the vertex buffer into multiple child vertex buffers
};

// ************************************************************************************************************************************************************

/*!
	IRuIndexBuffer
	@author John Tang
	@version 2004/05/12
*/
class IRuIndexBuffer : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuIndexBuffer();

	virtual void*							Lock(UINT offset = 0, UINT size = 0) = 0;					// Lock buffer using defaults
	virtual void*							Lock(UINT offset, UINT size, DWORD lockFlags) = 0;			// Lock buffer
	virtual void							Unlock() = 0;												// Unlock buffer

	virtual void							Select() const = 0;											// Select the buffer for use

	virtual UINT32							GetSize() const = 0;										// Get the size of the buffer
	virtual UINT32							GetOffset() const = 0;										// Gets the offset to the start of index data if the buffer is shared
	virtual UINT32							GetIndexOffset() const = 0;									// Gets the offset to the start of index data, in number of indices, if the buffer is shared
};

// ************************************************************************************************************************************************************

/*!
	IRuVertexShader
	@author John Tang
	@version 2004/05/14
*/
class IRuVertexShader : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuVertexShader() { }

	virtual void							Select() const = 0;											// Select the vertex shader for use
};

// ************************************************************************************************************************************************************

/*!
	IRuPixelShader
	@author John Tang
	@version 2004/05/14
*/
class IRuPixelShader : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuPixelShader() { }

	virtual void							Select() const = 0;											// Select the pixel shader for use
};

// ************************************************************************************************************************************************************

/*!
	IRuSurface
	@author John Tang
	@version 2004/05/18
*/
class IRuSurface : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuSurface();

	virtual RuResourcePool					GetPool() const = 0;										// Gets the resource pool this texture resides in
	virtual	RuSurfaceFormat					GetSurfaceFormat() const = 0;								// Gets the surface format of this texture

	virtual	UINT32							GetWidth(UINT32 level) const = 0;							// Gets the width for the specified level
	virtual	UINT32							GetHeight(UINT32 level) const = 0;							// Gets the height for the specified level

	virtual BOOL							Lock(void **bitsOut, INT32 *pitchOut) = 0;					// Lock the surface
	virtual BOOL							Unlock() = 0;												// Unlock the surface

	virtual BOOL							SelectRenderTarget() = 0;									// Selects the surface as a render target
	virtual BOOL							SelectDepthStencil() = 0;									// Selects the surface as a depth stencil surface
};

// ************************************************************************************************************************************************************

/*!
	IRuBaseTexture
	@author John Tang
	@version 2004/05/12
*/
class IRuBaseTexture : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuBaseTexture();

	virtual const char*						GetTextureName() const = 0;									// Gets the texture name
	virtual void							SetTextureName(const char *textureName) = 0;				// Sets the texture name

	virtual void							Select(UINT32 samplerIndex) = 0;							// Select the texture into the specified sampler for use

	virtual BOOL							GenerateMipLevels() = 0;									// Generates the mipmap levels

	virtual BOOL							IsDynamic() const = 0;
	virtual BOOL							IsRenderTarget() const = 0;

	virtual UINT32							GetLevelCount() const = 0;									// Gets the number of available mipmap levels
	virtual UINT32							GetLOD() const = 0;											// Gets the currently set maximum LOD level
	virtual UINT32							SetLOD(UINT32 lod) const = 0;								// Sets the maximum LOD level

	virtual RuResourcePool					GetPool() const = 0;										// Gets the resource pool this texture resides in
	virtual	RuSurfaceFormat					GetSurfaceFormat() const = 0;								// Gets the surface format of this texture
};

// ************************************************************************************************************************************************************

/*!
	IRuTexture
	@author John Tang
	@version 2004/05/12
*/
class IRuTexture : public IRuBaseTexture
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuTexture();

	virtual BOOL							SelectRenderTarget(UINT32 level) = 0;						// Selects the specified level as a render target

	virtual	UINT32							GetLevelWidth(UINT32 level) const = 0;						// Gets the width for the specified level
	virtual	UINT32							GetLevelHeight(UINT32 level) const = 0;						// Gets the height for the specified level
	virtual IRuSurface*						GetLevelSurface(UINT32 level) = 0;							// Gets the surface for the specified level

	virtual BOOL							Lock(UINT32 level, void **bitsOut, INT32 *pitchOut) = 0;	// Lock the texture level
	virtual BOOL							Unlock(UINT32 level) = 0;									// Unlock the texture level
};

// ************************************************************************************************************************************************************

/*!
	IRuCubeTexture
	@author John Tang
	@version 2004/05/12
*/
class IRuCubeTexture : public IRuBaseTexture
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuCubeTexture();

	virtual BOOL							SelectRenderTarget(RuCubeTextureFace cubeFace, UINT32 level) = 0;						// Selects the specified level as a render target

	virtual	UINT32							GetLevelWidth(UINT32 level) const = 0;						// Gets the width for the specified level
	virtual	UINT32							GetLevelHeight(UINT32 level) const = 0;						// Gets the height for the specified level

	virtual BOOL							Lock(RuCubeTextureFace cubeFace, UINT32 level, void **bitsOut, INT32 *pitchOut) = 0;
	virtual BOOL							Unlock(RuCubeTextureFace cubeFace, UINT32 level) = 0;		// Unlock the texture level
};

// ************************************************************************************************************************************************************

/*!
	IRuVolumeTexture
	@author John Tang
	@version 2004/05/12
*/
class IRuVolumeTexture : public IRuBaseTexture
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuVolumeTexture();

	virtual	UINT32							GetLevelWidth(UINT32 level) const = 0;						// Gets the width for the specified level
	virtual	UINT32							GetLevelHeight(UINT32 level) const = 0;						// Gets the height for the specified level
	virtual	UINT32							GetLevelDepth(UINT32 level) const = 0;						// Gets the depth for the specified level

	virtual BOOL							Lock(UINT32 level, void **bitsOut, INT32 *rowPitchOut, INT32 *slicePitchOut) = 0;	// Lock the texture level
	virtual BOOL							Unlock(UINT32 level) = 0;									// Unlock the texture level
};

// ************************************************************************************************************************************************************

/*!
	IRuSwapChain
	@author John Tang
	@version 2004/05/18
*/
class IRuSwapChain : public IRuEngineResource
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuSwapChain();

	virtual BOOL							SelectRenderTarget() = 0;						// Selects the specified swap chain as a render target

	virtual UINT32							GetWidth() const = 0;							// Gets the width for the swap chain
	virtual UINT32							GetHeight() const = 0;							// Gets the height for the swap chain

	virtual BOOL							Present() = 0;									// Presents the swap chain to the display
};

// ************************************************************************************************************************************************************

/*!
	IRuEngine
	@author John Tang
	@version 2004/07/08
*/
class IRuEngine : public IRuObject
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuEngine();

	// State management
	virtual void							ClearStateCache() = 0;
	virtual void							ClearSampler(DWORD sampler) = 0;

	// Scene management
	virtual BOOL							BeginScene() = 0;
	virtual BOOL							EndScene() = 0;
	virtual BOOL							Clear(DWORD clearFlags, RUCOLOR color, float z, DWORD stencil) = 0;

	// Depth-stencil
	virtual BOOL							RestoreDefaultDepthStencil() = 0;

	// Scissor test
	virtual BOOL							SetScissorRect(RECT *scissorRect) = 0;

	// Resource arena management
	virtual BOOL							SetResourceArenaSize(UINT32 arenaSize) = 0;
	virtual BOOL							GetResourceArenaSize(UINT32 &vbArenaSizeOut, UINT32 &ibArenaSizeOut, UINT32 &vbArenaPagesOut, UINT32 &ibArenaPagesOut) = 0;
	virtual BOOL							DestroyResourceArena() = 0;
	virtual BOOL							InvalidateResourceArena() = 0;
	virtual BOOL							RestoreResourceArena() = 0;

	// Resource management
	virtual IRuVertexDeclaration*			CreateVertexDeclaration(const CRuVertexElement *vertexElements) = 0;

	virtual IRuVertexBuffer*				CreateVertexBuffer(UINT32 size) = 0;						// Creates a pooled static vertex buffer
	virtual IRuVertexBuffer*				CreateDynamicVertexBuffer(UINT32 size) = 0;					// Creates a dynamic vertex buffer
	virtual IRuIndexBuffer*					CreateIndexBuffer(UINT32 size) = 0;							// Creates a pooled static index buffer
	virtual IRuIndexBuffer*					CreateDynamicIndexBuffer(UINT32 size) = 0;					// Creates a dynamic index buffer

	virtual IRuTexture*						CreateTexture(UINT32 width, UINT32 height, UINT32 mipLevels, RuSurfaceFormat surfaceFormat, RuResourcePool resourcePool) = 0;
	virtual IRuVolumeTexture*				CreateVolumeTexture(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevels, RuSurfaceFormat surfaceFormat, RuResourcePool resourcePool) = 0;
	virtual IRuTexture*						CreateRenderTarget(UINT32 width, UINT32 height, UINT32 mipLevels, RuSurfaceFormat surfaceFormat) = 0;
	virtual IRuTexture*						CreateMatchedRenderTarget(UINT32 mipLevels, RuSurfaceFormat surfaceFormat) = 0;

	virtual BOOL							DestroyVertexDeclaration(IRuVertexDeclaration *vertexDeclaration) = 0;

	virtual BOOL							DestroyVertexBuffer(IRuVertexBuffer *vertexBuffer) = 0;		// Destroys a vertex buffer
	virtual BOOL							DestroyIndexBuffer(IRuIndexBuffer *indexBuffer) = 0;		// Destroys a index buffer

	virtual BOOL							DestroyTexture(IRuTexture *texture) = 0;

	virtual IRuSurface*						CreateDepthStencilSurface(UINT32 width, UINT32 height, RuSurfaceFormat surfaceFormat) = 0;
	virtual BOOL							DestroyDepthStencilSurface(IRuSurface *surface) = 0;

	// Texture utilities
	virtual BOOL							CopyTexture(IRuEngineResource *srcTexture, IRuEngineResource *destTexture, INT32 surfLevel) = 0;

	// Rendering
	virtual UINT32							Render(UINT32 numVertices, UINT32 numPrimitives, RuPrimitiveType primType) = 0;

	// Environment setup and management
	virtual IRuSwapChain*					CreateSwapChain(UINT32 width, UINT32 height, HWND deviceWindow) = 0;
	virtual BOOL							DestroySwapChain(IRuSwapChain *swapChain) = 0;
	virtual BOOL							SetResolution(IRuSwapChain *swapChain, UINT32 width, UINT32 height, BOOL fullscreen, HWND deviceWindow = NULL) = 0;

	// Enviroment queries
	virtual BOOL							GetRenderTargetSize(UINT32 &widthOut, UINT32 &heightOut) = 0;

	// Metric
	virtual INT32							Metric_GetNumStateChanges() = 0;
	virtual void							Metric_OutputAllocationReport() = 0;
};

// ************************************************************************************************************************************************************

inline IRuEngineResource::IRuEngineResource()
:	m_engine(NULL),
	m_priority(0)
{
}

inline IRuEngineResource::~IRuEngineResource()
{
}

inline IRuEngine *IRuEngineResource::GetEngine()
{
	return m_engine;
}

inline void IRuEngineResource::SetEngine(IRuEngine *engine)
{
	// Allow setting the owning engine only once
	if(m_engine == NULL)
	{
		m_engine = engine;
	}
}

inline UINT32 IRuEngineResource::GetPriority() const
{
	return m_priority;
}

inline void IRuEngineResource::SetPriority(UINT32 priority)
{
	m_priority = priority;
}

// ************************************************************************************************************************************************************

inline IRuVertexDeclaration::~IRuVertexDeclaration()
{
	// Call the resource manager to free this vertex declaration if applicable
	if(m_engine)
	{
		m_engine->DestroyVertexDeclaration(this);
	}
}

// ************************************************************************************************************************************************************

inline IRuVertexBuffer::~IRuVertexBuffer()
{
	// Call the resource manager to free this vertex buffer if applicable
	if(m_engine)
	{
		m_engine->DestroyVertexBuffer(this);
	}
}

// ************************************************************************************************************************************************************

inline IRuIndexBuffer::~IRuIndexBuffer()
{
	// Call the resource manager to free this index buffer if applicable
	if(m_engine)
	{
		m_engine->DestroyIndexBuffer(this);
	}
}

// ************************************************************************************************************************************************************

inline IRuSurface::~IRuSurface()
{
}

// ************************************************************************************************************************************************************

inline IRuBaseTexture::~IRuBaseTexture()
{
}

// ************************************************************************************************************************************************************

inline IRuTexture::~IRuTexture()
{
	// Call the resource manager to free this texture if applicable
	if(m_engine)
	{
		m_engine->DestroyTexture(this);
	}
}

// ************************************************************************************************************************************************************

inline IRuCubeTexture::~IRuCubeTexture()
{
}

// ************************************************************************************************************************************************************

inline IRuVolumeTexture::~IRuVolumeTexture()
{
}

// ************************************************************************************************************************************************************

inline IRuSwapChain::~IRuSwapChain()
{
	// Call the resource manager to free this swap chain if applicable
	if(m_engine)
	{
		m_engine->DestroySwapChain(this);
	}
}

// ************************************************************************************************************************************************************

inline IRuEngine::~IRuEngine()
{
}

// ************************************************************************************************************************************************************

#pragma managed

#endif
