/*!
	@project Rune
	@file RuEngineD3D.h

	Copyright (c) 2004 All rights reserved

	@author John Tang
	@date 2004/06/15
*/

#ifndef _RUENGINED3D_H_
#define _RUENGINED3D_H_

#include "../../Core/Collection/RuCollections.h"
#include "../../Core/Collection/RuCollectionsHash.h"
#include "../../Core/Collection/RuCollectionsLRU.h"

#include "../../Engine/Base/RuEngineBase.h"

#include <d3d9.h>
#include <d3dx9.h>

#pragma unmanaged

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

enum RuEngineMode
{
	ruENGINEMODE_SOFTWARE			= 0,
	ruENGINEMODE_MIXED				= 1,
	ruENGINEMODE_HARDWARE			= 2,
	ruENGINEMODE_PURE				= 3,
	ruENGINEMODE_FORCE_DWORD		= 0x7FFFFFFF
};

// ************************************************************************************************************************************************************
// HELPERS

inline D3DFORMAT ToD3DFormat(RuSurfaceFormat surfaceFormat)
{
	return (D3DFORMAT) surfaceFormat;
}

inline RuSurfaceFormat ToRuSurfaceFormat(D3DFORMAT surfaceFormat)
{
	return (RuSurfaceFormat) surfaceFormat;
}

inline RuResourcePool ToRuResourcePool(D3DPOOL pool)
{
	switch(pool)
	{
		case D3DPOOL_DEFAULT:
			return ruRESPOOL_DEFAULT;
		case D3DPOOL_MANAGED:
			return ruRESPOOL_MANAGED;
		case D3DPOOL_SYSTEMMEM:
			return ruRESPOOL_SYSTEMMEMORY;
		case D3DPOOL_SCRATCH:
			return ruRESPOOL_SCRATCH;
	}

	return ruRESPOOL_DEFAULT;
}

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

typedef BOOL(* RuEngineConfirmDeviceCallback)(D3DCAPS9 *caps, RuEngineMode engineMode, RuSurfaceFormat adapterFormat, RuSurfaceFormat backBufferFormat);

// Forward declarations
class CRuEngineD3D;

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

class CRuVertexDeclarationD3D : public IRuVertexDeclaration
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	struct StreamDesc
	{
		UINT16								m_streamIndex;
		INT32								m_streamStride;

		StreamDesc(UINT16 streamIndex = 0)
		:	m_streamIndex(streamIndex),
			m_streamStride(0)
		{
		}

		BOOL								operator==(const StreamDesc &desc) const
		{
			return m_streamIndex ==desc.m_streamIndex;
		}
	};

	IDirect3DDevice9*						m_parentDevice;			// Parent device of this resource

	IDirect3DVertexDeclaration9*			m_vertexDeclaration;	// Direct3D vertex declaration object
	CRuVertexElement*						m_vertexElements;		// Rune vertex element structure array

	CRuArrayList<StreamDesc>				m_vertexStreams;		// Vertex streams

public:
											CRuVertexDeclarationD3D(IDirect3DVertexDeclaration9 *vertexDeclaration, const CRuVertexElement *vertexElements);
	virtual									~CRuVertexDeclarationD3D();

	virtual void							Invalidate();
	virtual BOOL							IsInvalidated() const;
	virtual BOOL							Restore();

	virtual const CRuVertexElement*			GetVertexElements() const;
	virtual void							Select() const;

	virtual INT32							GetNumStreams() const;
	virtual INT32							GetStreamStride(INT32 streamIndex) const;
};

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

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

protected:
	IDirect3DDevice9*				m_parentDevice;				// Parent device of this resource

	IDirect3DVertexBuffer9*			m_vertexBuffer;				// Direct3D vertex buffer object
	BOOL							m_isDynamic;				// Indicates whether this buffer is a dynamic buffer
	UINT32							m_offset;					// Offset, in bytes, to the beginning of vertex data
	UINT32							m_size;						// Size of the vertex buffer, in bytes
	BOOL							m_shared;					// * When this value is TRUE, it indicates that the vertex buffer
																//   is sharing a part of a D3D vertex buffer. This means the ruLOCK_DISCARD
																//   lock flag is always ignored. Almost always this would denote a static buffer.

	CRuVertexBufferD3D*				m_chainedVB;				// Chained vertex buffer - when invalidating, the entire chain is invalidated.
																// This is used by the subdivide function when it creates child vertex buffers
																// from an existing vertex buffer. The engine does not know the existence of such
																// buffers, and so they must be chained to the original buffer to ensure that they
																// are properly invalidated when such an event occurs.

public:
									CRuVertexBufferD3D(IDirect3DVertexBuffer9 *vertexBuffer, BOOL isDynamic = FALSE);
									CRuVertexBufferD3D(IDirect3DVertexBuffer9 *vertexBuffer, UINT32 offset, UINT32 size, BOOL shared, BOOL isDynamic = FALSE);
	virtual							~CRuVertexBufferD3D();

	virtual void					Invalidate();
	virtual BOOL					IsInvalidated() const;
	virtual BOOL					Restore();

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

	virtual void					Select(UINT32 streamIndex, UINT32 stride) const;

	virtual UINT32					GetSize() const;
	virtual UINT32					GetOffset() const;

	virtual BOOL					Subdivide(INT32 numChildVBs, IRuVertexBuffer **childVBOut);
	void							FreeVBChain(CRuVertexBufferD3D *currentVB);

									operator IDirect3DVertexBuffer9*() const;
};

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

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

protected:
	IDirect3DDevice9*				m_parentDevice;				// Parent device of this resource

	IDirect3DIndexBuffer9*			m_indexBuffer;				// Direct3D index buffer object
	BOOL							m_isDynamic;				// Indicates whether this buffer is a dynamic buffer
	UINT32							m_offset;					// Offset, in bytes, to the beginning of index data
	UINT32							m_size;						// Size of the index buffer, in bytes
	BOOL							m_shared;					// * When this value is TRUE, it indicates that the index buffer is sharing
																//   a part of a D3D index buffer. This means the ruLOCK_DISCARD lock flag is
																//   always ignored.

public:
									CRuIndexBufferD3D(IDirect3DIndexBuffer9 *indexBuffer, BOOL isDynamic = FALSE);
									CRuIndexBufferD3D(IDirect3DIndexBuffer9 *indexBuffer, UINT32 offset, UINT32 size, BOOL shared);
	virtual							~CRuIndexBufferD3D();

	virtual void					Invalidate();
	virtual BOOL					IsInvalidated() const;
	virtual BOOL					Restore();

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

	virtual void					Select() const;

	virtual UINT32					GetSize() const;
	virtual UINT32					GetOffset() const;
	virtual UINT32					GetIndexOffset() const;

									operator IDirect3DIndexBuffer9*() const;
};

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

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

protected:
	IDirect3DDevice9*				m_parentDevice;				// Parent device of this resource

	// Direct3D surface object
	IDirect3DSurface9*				m_surface;					// Surface object

	// D3D-specific information
	D3DSURFACE_DESC					m_surfaceDesc;				// Surface descriptor

	// Surface information
	RuResourcePool					m_resourcePool;				// Resource pool this texture belongs to
	RuSurfaceFormat					m_surfaceFormat;			// Surface format

public:
									CRuSurfaceD3D(IDirect3DSurface9 *surface);
	virtual							~CRuSurfaceD3D();

	virtual void					Invalidate();
	virtual BOOL					IsInvalidated() const;
	virtual BOOL					Restore();

	virtual RuResourcePool			GetPool() const;
	virtual	RuSurfaceFormat			GetSurfaceFormat() const;

	virtual	UINT32					GetWidth(UINT32 level) const;
	virtual	UINT32					GetHeight(UINT32 level) const;

	virtual BOOL					Lock(void **bitsOut, INT32 *pitchOut);
	virtual BOOL					Unlock();

	virtual BOOL					SelectRenderTarget();
	virtual BOOL					SelectDepthStencil();
};

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

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

protected:
	IDirect3DDevice9*				m_parentDevice;				// Parent device of this resource

	// Direct3D texture object
	IDirect3DTexture9*				m_texture;

	// D3D-specific information
	DWORD							m_levelCount;
	D3DSURFACE_DESC					m_surfaceDesc;
	CRuSurfaceD3D**					m_surfaces;

	// Texture information
	char*							m_textureName;
	BOOL							m_isDynamic;
	BOOL							m_isRenderTarget;			// Is this texture a render target?
	BOOL							m_isMatchedToBackBuffer;	// Does this texture have dimensions always matched to the backbuffer?
	RuResourcePool					m_resourcePool;				// Resource pool this texture belongs to
	RuSurfaceFormat					m_surfaceFormat;

public:
									CRuTextureD3D(IDirect3DTexture9 *texture, BOOL isDynamic, BOOL isMatchedToBackBuffer = FALSE);
	virtual							~CRuTextureD3D();

	virtual void					Invalidate();
	virtual BOOL					IsInvalidated() const;
	virtual BOOL					Restore();

	virtual const char*				GetTextureName() const;
	virtual void					SetTextureName(const char *textureName);

	virtual void					Select(UINT32 samplerIndex);

	virtual BOOL					GenerateMipLevels();

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

	virtual UINT32					GetLevelCount() const;
	virtual UINT32					GetLOD() const;
	virtual UINT32					SetLOD(UINT32 lod) const;

	virtual RuResourcePool			GetPool() const;
	virtual	RuSurfaceFormat			GetSurfaceFormat() const;

	virtual BOOL					SelectRenderTarget(UINT32 level);

	virtual	UINT32					GetLevelWidth(UINT32 level) const;
	virtual	UINT32					GetLevelHeight(UINT32 level) const;
	virtual IRuSurface*				GetLevelSurface(UINT32 level);

	virtual BOOL					Lock(UINT32 level, void **bitsOut, INT32 *pitchOut);
	virtual BOOL					Unlock(UINT32 level);

	IDirect3DTexture9*				GetIDirect3DTexture();
};

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

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

protected:
	IDirect3DDevice9*				m_parentDevice;				// Parent device of this resource

	// Direct3D texture object
	IDirect3DVolumeTexture9*		m_texture;

	// D3D-specific information
	DWORD							m_levelCount;
	D3DVOLUME_DESC					m_surfaceDesc;
//	CRuSurfaceD3D**					m_surfaces;

	// Texture information
	char*							m_textureName;
	BOOL							m_isDynamic;
	RuResourcePool					m_resourcePool;				// Resource pool this texture belongs to
	RuSurfaceFormat					m_surfaceFormat;

public:
									CRuVolumeTextureD3D(IDirect3DVolumeTexture9 *texture, BOOL isDynamic, BOOL isMatchedToBackBuffer = FALSE);
	virtual							~CRuVolumeTextureD3D();

	virtual void					Invalidate();
	virtual BOOL					IsInvalidated() const;
	virtual BOOL					Restore();

	virtual const char*				GetTextureName() const;
	virtual void					SetTextureName(const char *textureName);

	virtual void					Select(UINT32 samplerIndex);

	virtual BOOL					GenerateMipLevels();

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

	virtual UINT32					GetLevelCount() const;
	virtual UINT32					GetLOD() const;
	virtual UINT32					SetLOD(UINT32 lod) const;

	virtual RuResourcePool			GetPool() const;
	virtual	RuSurfaceFormat			GetSurfaceFormat() const;

	virtual BOOL					SelectRenderTarget(UINT32 level);

	virtual	UINT32					GetLevelWidth(UINT32 level) const;
	virtual	UINT32					GetLevelHeight(UINT32 level) const;
	virtual	UINT32					GetLevelDepth(UINT32 level) const;

	virtual BOOL					Lock(UINT32 level, void **bitsOut, INT32 *rowPitchOut, INT32 *slicePitchOut);
	virtual BOOL					Unlock(UINT32 level);

	IDirect3DVolumeTexture9*		GetIDirect3DVolumeTexture();
};

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

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

protected:
	IDirect3DDevice9*				m_parentDevice;				// Parent device of this resource
	IDirect3DSwapChain9*			m_swapChain;				// Swap chain object
	IDirect3DSurface9*				m_backBuffer;				// Back buffer
	
	D3DPRESENT_PARAMETERS			m_presentParameters;		// Currently selected settings

public:
									CRuSwapChainD3D(IDirect3DSwapChain9 *swapChain);
	virtual							~CRuSwapChainD3D();

	virtual void					Invalidate();												// Invalidate the resource
	virtual BOOL					IsInvalidated() const;										// Check whether the resource is lost
	virtual BOOL					Restore();

	virtual BOOL					SelectRenderTarget();

	virtual UINT32					GetWidth() const;
	virtual UINT32					GetHeight() const;

	virtual BOOL					Present();

	IDirect3DSurface9*				GetIDirect3DSurface();

protected:
	BOOL							SetD3DSwapChain(IDirect3DSwapChain9 *swapChain);
	D3DPRESENT_PARAMETERS&			PresentParameters();

	friend CRuEngineD3D;
};

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

/*!
	This is the detailed class description

	´ú¸Õ¤¤¤å

	@author John Tang
	@version 2004/06/15
*/
class CRuEngineD3D : public IRuEngine
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	struct RuMultisampleConflictD3D
	{
		D3DFORMAT								m_depthStencilFormat;				// Depth/Stencil format with conflict
		D3DMULTISAMPLE_TYPE						m_multisampleType;					// Multisample type with conflict
	};

	struct RuDeviceComboD3D
	{
		INT32									m_adapterOrdinal;					// Adapter ordinal
		D3DDEVTYPE								m_deviceType;						// Device type
		D3DFORMAT								m_adapterFormat;					// Adapter surface format
		D3DFORMAT								m_backBufferFormat;					// Back buffer surface format
		BOOL									m_isWindowed;						// Whether the combination is a windowed mode
		CRuArrayList<D3DFORMAT>					m_depthStencilFormatList;			// List of D3DFORMATs
		CRuArrayList<D3DMULTISAMPLE_TYPE>		m_multisampleTypeList;				// List of D3DMULTISAMPLE_TYPEs
		CRuArrayList<DWORD>						m_multisampleQualityList;			// List of DWORDs (number of quality levels for each multisample type)
		CRuArrayList<RuMultisampleConflictD3D>	m_multisampleConflictList;			// List of RuMultisampleConflictD3Ds
		CRuArrayList<RuEngineMode>				m_engineModeList;					// List of RuEngineModes
		CRuArrayList<DWORD>						m_presentIntervalList;				// List of D3DPRESENT_INTERVALs
	};

	struct RuDeviceInfoD3D
	{
		INT32									m_adapterOrdinal;					// Adapter ordinal
		D3DDEVTYPE								m_deviceType;						// Direct3D device type
		D3DCAPS9								m_caps;								// Direct3D cap bits
		CRuArrayList<RuDeviceComboD3D *>		m_deviceComboList;					// List of D3DDeviceCombo pointers

												~RuDeviceInfoD3D();
	};

	struct RuAdapterInfoD3D
	{
		INT32									m_adapterOrdinal;					// Adapter ordinal
		D3DADAPTER_IDENTIFIER9					m_adapterIdentifier;				// Adapter identifier
		CRuArrayList<D3DDISPLAYMODE>			m_displayModeList;					// List of D3DDISPLAYMODEs
		CRuArrayList<RuDeviceInfoD3D *>			m_deviceInfoList;					// List of D3DDeviceInfo pointers

												~RuAdapterInfoD3D();
	};

	struct RuEngineSettingD3D
	{
		BOOL									m_isWindowed;						// Is windowed mode selected?

		INT32									m_windowedWidth;					// Primary window width in windowed mode
		INT32									m_windowedHeight;					// Primary window height in windowed mode

		DWORD									m_preferredFullscreenWidth;			// Preferred fullscreen width
		DWORD									m_preferredFullscreenHeight;		// Preferred fullscreen height
		DWORD									m_preferredFullscreenRefreshRate;	// Preferred fullscreen refresh rate

		// Windowed mode information
		RuAdapterInfoD3D*						m_windowedAdapterInfo;
		RuDeviceInfoD3D*						m_windowedDeviceInfo;
		RuDeviceComboD3D*						m_windowedDeviceCombo;

		D3DDISPLAYMODE							m_windowedDisplayMode;				// Not changable by the user
		D3DFORMAT								m_windowedDepthStencilBufferFormat;
		D3DMULTISAMPLE_TYPE						m_windowedMultisampleType;
		DWORD									m_windowedMultisampleQuality;
		RuEngineMode							m_windowedEngineMode;
		UINT32									m_windowedPresentInterval;

		// Fullscreen mode information
		RuAdapterInfoD3D*						m_fullscreenAdapterInfo;
		RuDeviceInfoD3D*						m_fullscreenDeviceInfo;
		RuDeviceComboD3D*						m_fullscreenDeviceCombo;

		D3DDISPLAYMODE							m_fullscreenDisplayMode;			// Changable by the user
		D3DFORMAT								m_fullscreenDepthStencilBufferFormat;
		D3DMULTISAMPLE_TYPE						m_fullscreenMultisampleType;
		DWORD									m_fullscreenMultisampleQuality;
		RuEngineMode							m_fullscreenEngineMode;
		UINT32									m_fullscreenPresentInterval;

		// Property access methods
		RuAdapterInfoD3D*						AdapterInfo();
		RuDeviceInfoD3D*						DeviceInfo();
		RuDeviceComboD3D*						DeviceCombo();
		D3DDISPLAYMODE&							DisplayMode();
		D3DFORMAT&								DepthStencilBufferFormat();
		D3DMULTISAMPLE_TYPE&					MultisampleType();
		DWORD&									MultisampleQuality();
		RuEngineMode&							EngineMode();
		UINT32&									PresentInterval();

		// Value retrieval shortcuts
		INT32									GetAdapterOrdinal();
		D3DDEVTYPE								GetDeviceType();
		D3DFORMAT								GetBackBufferFormat();

		// Mode selection
		BOOL									FindBestWindowedMode(IDirect3D9 *d3dObject, CRuArrayList<RuAdapterInfoD3D *> &adapterInfoList, BOOL requireHAL, BOOL requireREF);
		BOOL									FindBestFullscreenMode(IDirect3D9 *d3dObject, CRuArrayList<RuAdapterInfoD3D *> &adapterInfoList, BOOL requireHAL, BOOL requireREF);
		BOOL									FindBestFullscreenMode();
		void									BuildPresentParamsFromSettings(HWND deviceWindow, D3DPRESENT_PARAMETERS &presentParamsOut);
		void									BuildPresentParamsForWindowed(HWND deviceWindow, UINT32 width, UINT32 height,  D3DPRESENT_PARAMETERS &presentParamsOut);
	};

	struct RuMemoryBlock
	{
		void*									m_deviceBuffer;						// Optional pointer to the device buffer occupying this block
		UINT32									m_index;							// Index to the buffer in the buffer array
		UINT32									m_offset;							// Offset, in pages, to beginning of the block
		UINT32									m_blockSize;						// Length, in pages, of the block
	};

	struct RuManagedVertexBuffer
	{
		IDirect3DVertexBuffer9*					m_vertexBuffer;						// Pointer to the vertex buffer containing the free block
		CRuArrayList<RuMemoryBlock>				m_freeList;							// List of free pages
		UINT32									m_bufferSize;						// Size of the vertex buffer, in pages
	};

	struct RuManagedIndexBuffer
	{
		IDirect3DIndexBuffer9*					m_indexBuffer;						// Pointer to the index buffer containing the free block
		CRuArrayList<RuMemoryBlock>				m_freeList;							// List of free pages
		UINT32									m_bufferSize;						// Size of the index buffer, in pages
	};

	struct RuVEC
	{
		const CRuVertexElement*					m_vertexElements;

		BOOL									operator==(const RuVEC &ve) const;
	};

	struct RuEngineMetric
	{
		INT32									m_vb_TotalPages;
		INT32									m_vb_TotalBytes;
		INT32									m_vb_Allocations;					//!< Number of vertex buffer allocations
		INT32									m_vb_CommittedPages;				//!< Number of committed pages
		INT32									m_vb_CommittedBytes;
		INT32									m_vb_UtilizedBytes;					//!< Number of utilized bytes
		REAL									m_vb_PercentWaste;

		INT32									m_ib_TotalPages;
		INT32									m_ib_TotalBytes;
		INT32									m_ib_Allocations;					//!< Number of vertex buffer allocations
		INT32									m_ib_CommittedPages;				//!< Number of committed pages
		INT32									m_ib_CommittedBytes;
		INT32									m_ib_UtilizedBytes;					//!< Number of utilized bytes
		REAL									m_ib_PercentWaste;
	};

	const static DWORD							s_maxRenderStates = 256;
	const static DWORD							s_maxStages = 8;
	const static DWORD							s_maxTextureStates = 33;
	const static DWORD							s_maxSamplerStates = 16;
	const static DWORD							s_maxVertexStreams = 8;
	const static DWORD							s_maxSamplers = 8;

	// ...
	HWND										m_primaryWindow;					// Handle to primary swap chain window

	// Direct3D objects
	IDirect3D9*									m_d3dObject;						// Direct3D object
	IDirect3DDevice9*							m_d3dDevice;						// Direct3D device
	IDirect3DSurface9*							m_defaultDepthStencilSurface;		// Default depth stencil surface
	D3DCAPS9									m_d3dDeviceCaps;					// Direct3D device caps

	// Engine state cache
	BOOL										m_renderStatesOK[s_maxRenderStates];
	DWORD										m_renderStates[s_maxRenderStates];

	BOOL										m_textureStageStatesOK[s_maxStages][s_maxTextureStates];
	DWORD										m_textureStageStates[s_maxStages][s_maxTextureStates];

	BOOL										m_samplerStageStatesOK[s_maxStages][s_maxSamplerStates];
	DWORD										m_samplerStageStates[s_maxStages][s_maxSamplerStates];

	BOOL										m_currentVertexDeclarationOK;
	IDirect3DVertexDeclaration9*				m_currentVertexDeclaration;

	BOOL										m_currentVertexShaderOK;
	IDirect3DVertexShader9*						m_currentVertexShader;

	BOOL										m_currentPixelShaderOK;
	IDirect3DPixelShader9*						m_currentPixelShader;

	BOOL										m_currentVertexStreamOK[s_maxVertexStreams];
	IDirect3DVertexBuffer9*						m_currentVertexStream[s_maxVertexStreams];
	UINT32										m_currentVertexStreamOffset[s_maxVertexStreams];
	UINT32										m_currentVertexStreamStride[s_maxVertexStreams];

	BOOL										m_currentIndexStreamOK;
	IDirect3DIndexBuffer9*						m_currentIndexStream;

	BOOL										m_currentTextureOK[s_maxSamplers];
	IDirect3DBaseTexture9*						m_currentTexture[s_maxSamplers];

	// Resource management data structures
	BOOL										m_resourceArenaInvalidated;			// Is the resource arena in an invalidated state?
	float										m_vbToIBRatio;						// Arena allocation ratio (VB:IB)

	UINT32										m_vbPageSize;						// Size of each allocation page for the vertex buffer
	UINT32										m_vbBufferSize;						// Size of each shared vertex buffer, in pages
	UINT32										m_vbMaxAllocationSize;

	UINT32										m_ibPageSize;						// Size of each allocation page for the index buffer
	UINT32										m_ibBufferSize;						// Size of each shared index buffer, in pages
	UINT32										m_ibMaxAllocationSize;

	CRuArrayList<RuManagedVertexBuffer *>		m_vertexBuffers;					// List of managed vertex buffers
	CRuHashMap<DWORD, RuMemoryBlock>*			m_allocatedVertexBuffers;			// Hash of allocated vertex buffer blocks, hashed on pointer to the VB interface

	CRuArrayList<RuManagedIndexBuffer *>		m_indexBuffers;						// List of managed index buffers
	CRuHashMap<DWORD, RuMemoryBlock>*			m_allocatedIndexBuffers;			// Hash of allocated index buffer blocks, hashed on pointer to the IB interface

	CRuArrayList<CRuVertexBufferD3D *>			m_dynamicVertexBuffers;				// List of managed dynamic vertex buffers

	CRuArrayList<CRuIndexBufferD3D *>			m_dynamicIndexBuffers;				// List of managed dynamic index buffers

	CRuHashMap<RuVEC, IRuVertexDeclaration *>*	m_vertexDeclarations;				// Hash of existing vertex declarations

	// Swap chains
	CRuArrayList<CRuSwapChainD3D *>				m_swapChains;						// List of swap chains, there is always one primary swap chain at index 0

	// Depth-stencil surfaces
	CRuArrayList<CRuSurfaceD3D *>				m_depthStencilSurfaces;

	// Render targets
	CRuArrayList<CRuTextureD3D *>				m_renderTargets;					// List of render targets

	// Metric values
	INT32										m_numRequestedStateChanges;			// Number of state change requests made during the last BeginScene/EndScene block
	INT32										m_numStateChanges;					// Number of state changes made during the last BeginScene/EndScene block

	// Enumerated adapter information
	CRuArrayList<RuAdapterInfoD3D *>			m_adapterInfoList;					// List of adapter info structures
	CRuArrayList<D3DFORMAT>						m_allowedAdapterFormatList;			// List of allowable adapter formats
	RuEngineSettingD3D							m_engineSetting;

	// Filtering values
	UINT32										m_appMinFullscreenWidth;			// Minimum fullscreen width
	UINT32										m_appMinFullscreenHeight;			// Minimum fullscreen height
	UINT32										m_appMinColorChannelBits;			// Minimum color bits per channel in adapter format
	UINT32										m_appMinAlphaChannelBits;			// Minimum alpha bits per pixel in back buffer format
	UINT32										m_appMinDepthBits;					// Minimum depth buffer bits
	UINT32										m_appMinStencilBits;				// Minimum stencil bits
	BOOL										m_appUsesDepthBuffer;				// Is depth buffer required?
	BOOL										m_appUsesMixedMode;					// Is mixed vertex processing mode required?
	BOOL										m_appRequiresWindowed;				// Is windowed mode required?
	BOOL										m_appRequiresFullscreen;			// Is fullscreen mode required?
	RuEngineConfirmDeviceCallback				m_confirmDeviceCallback;			// Device confirmation callback

public:
												CRuEngineD3D();
	virtual										~CRuEngineD3D();

	// Engine startup & shutdown
	BOOL										Startup(HWND primaryWindow);
	BOOL										Shutdown();

	// Direct3D access
	IDirect3DDevice9*							GetD3DDevice();
	const D3DCAPS9&								GetD3DDeviceCaps();

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

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

	// Render state access
	HRESULT										SetRenderState(D3DRENDERSTATETYPE state, DWORD value);
	HRESULT										SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value);
	HRESULT										SetSamplerState(DWORD stage, D3DSAMPLERSTATETYPE state, DWORD value);
	HRESULT										SetVertexDeclaration(IDirect3DVertexDeclaration9 *decl);
	HRESULT										SetVertexShader(IDirect3DVertexShader9 *vs);
	HRESULT										SetPixelShader(IDirect3DPixelShader9 *ps);
	HRESULT										SetStreamSource(UINT32 streamNumber, IDirect3DVertexBuffer9 *vertexBuffer, UINT32 offset, UINT32 stride);
	HRESULT										SetIndices(IDirect3DIndexBuffer9 *indexBuffer);
	HRESULT										SetTexture(DWORD sampler, IDirect3DBaseTexture9 *texture);

	// Depth-stencil
	virtual BOOL								RestoreDefaultDepthStencil();

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

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

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

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

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

	virtual BOOL								DestroyVertexDeclaration(IRuVertexDeclaration *vertexDeclaration);

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

	virtual BOOL								DestroyTexture(IRuTexture *texture);

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

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

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

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

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

	// Metrics
	virtual INT32								Metric_GetNumStateChanges();
	virtual void								Metric_OutputAllocationReport();

	// Environment enumeration and selection
	BOOL										EnumerateAdapters();
	BOOL										SelectInitialDisplaySettings(BOOL fullscreen);

	void										FlushStateChanges();

protected:
	BOOL										EnumerateDevices(RuAdapterInfoD3D *adapterInfo, CRuArrayList<D3DFORMAT> &adapterFormatList);
	BOOL										EnumerateDeviceCombos(RuDeviceInfoD3D *deviceInfo, CRuArrayList<D3DFORMAT> &adapterFormatList);
	void										BuildDepthStencilFormatList(RuDeviceComboD3D *deviceCombo);
	void										BuildMultisampleTypeList(RuDeviceComboD3D *deviceCombo);
	void										BuildMultisampleConflictList(RuDeviceComboD3D *deviceCombo);
	void										BuildEngineModeList(RuDeviceInfoD3D *deviceInfo, RuDeviceComboD3D *deviceCombo);
	void										BuildPresentIntervalList(RuDeviceInfoD3D *deviceInfo, RuDeviceComboD3D *deviceCombo);

	void										ClearVertexDeclarationCache();


	static UINT32								ColorChannelBits(D3DFORMAT format);
	static UINT32								AlphaChannelBits(D3DFORMAT format);
	static UINT32								DepthBits(D3DFORMAT format);
	static UINT32								StencilBits(D3DFORMAT format);
	static int									SortModesCallback(const void *arg1, const void *arg2);

	static BOOL									ResArenaVBCollectMetricCallback(const void *key, const void *data, void *userData);
	static BOOL									ResArenaIBCollectMetricCallback(const void *key, const void *data, void *userData);
	static BOOL									ResArenaVBInvalidateCallback(const void *key, const void *data, void *userData);
	static BOOL									ResArenaIBInvalidateCallback(const void *key, const void *data, void *userData);
	static BOOL									ClearVertexDeclarationCacheCallback(const void *key, const void *data, void *userData);
};

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

extern CRuEngineD3D*							g_ruEngineD3D;

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

inline void CRuVertexBufferD3D::Invalidate()
{
	if(m_vertexBuffer)
	{
		m_vertexBuffer->Release();
		m_vertexBuffer = NULL;
	}

	if(m_chainedVB)
	{
		m_chainedVB->Invalidate();
	}
}

inline BOOL CRuVertexBufferD3D::IsInvalidated() const
{
	return m_vertexBuffer == NULL;
}

inline BOOL CRuVertexBufferD3D::Restore()
{
	if(m_vertexBuffer == NULL && m_parentDevice && !m_shared && m_isDynamic)
	{
		// Create D3D buffer
		if(m_parentDevice->CreateVertexBuffer(m_size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &m_vertexBuffer, NULL) == D3D_OK)
		{
			return TRUE;
		}
	}

	return FALSE;
}

inline UINT32 CRuVertexBufferD3D::GetSize() const
{
	return m_size;
}

inline UINT32 CRuVertexBufferD3D::GetOffset() const
{
	return m_offset;
}

inline void CRuVertexBufferD3D::Select(UINT32 streamIndex, UINT32 stride) const
{
	// Set the vertex buffer through the engine
	static_cast<CRuEngineD3D *>(m_engine)->SetStreamSource(streamIndex, m_vertexBuffer, m_offset, stride);
}

inline CRuVertexBufferD3D::operator IDirect3DVertexBuffer9*() const
{
	return m_vertexBuffer;
}

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

inline void CRuIndexBufferD3D::Invalidate()
{
	if(m_indexBuffer)
	{
		m_indexBuffer->Release();
		m_indexBuffer = NULL;
	}
}

inline BOOL CRuIndexBufferD3D::IsInvalidated() const
{
	return m_indexBuffer == NULL;
}

inline BOOL CRuIndexBufferD3D::Restore()
{
	if(m_indexBuffer == NULL && m_parentDevice && !m_shared && m_isDynamic)
	{
		// Create D3D buffer
		if(m_parentDevice->CreateIndexBuffer(m_size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_indexBuffer, NULL) == D3D_OK)
		{
			return TRUE;
		}
	}

	return FALSE;
}

inline UINT32 CRuIndexBufferD3D::GetSize() const
{
	return m_size;
}

inline UINT32 CRuIndexBufferD3D::GetOffset() const
{
	return m_offset;
}

inline UINT32 CRuIndexBufferD3D::GetIndexOffset() const
{
	// hack... should determine the size of each index before returning
	return m_offset / 2;
}

inline void CRuIndexBufferD3D::Select() const
{
	// Set the index buffer through the engine
	static_cast<CRuEngineD3D *>(m_engine)->SetIndices(m_indexBuffer);
}

inline CRuIndexBufferD3D::operator IDirect3DIndexBuffer9*() const
{
	return m_indexBuffer;
}

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

inline IDirect3DDevice9 *CRuEngineD3D::GetD3DDevice()
{
	return m_d3dDevice;
}

inline const D3DCAPS9 &CRuEngineD3D::GetD3DDeviceCaps()
{
	return m_d3dDeviceCaps;
}

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

#pragma managed

#endif
