#ifndef _RUMATERIALBASE_H_
#define _RUMATERIALBASE_H_

// Aurora system core
#include "../../Engine/Base/RuCore.h"

// Aurora  base renderer core
#include "../../Engine/Base/RuShaderBase.h"

// Resource Manager
#include "../../Engine/Base/RuResourceManagerBase.h"

#pragma unmanaged

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

enum RuMaterial_Type
{
	ruMATERIAL_TYPE_STANDARD					= 0,							// Standard material
	ruMATERIAL_TYPE_TRANSLUCENT					= 1,							// Translucent material
	ruMATERIAL_TYPE_FX							= 2,							// FX material

	ruMATERIAL_TYPE_FORCE_DWORD					= 0x7FFFFFFF
};

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

enum RuMaterial_LightingType
{
	ruMATERIAL_LIGHTINGTYPE_STANDARD			= 0,							// Standard lighting
	ruMATERIAL_LIGHTINGTYPE_PRELIT				= 1,							// Pre-lit
	ruMATERIAL_LIGHTINGTYPE_SELFILLUMINATE		= 2,							// Self-illuminated

	ruMATERIAL_LIGHTINGTYPE_FORCE_DWORD			= 0x7FFFFFFF
};

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

/*
	NOTES
	-----
	The material interface directly uses a pointer to a shader interface.
	This is beCRuse of speed concerns - we don't want to be looking up shaders in
	a string hash at runtime whenever we render! Materials should presumably be read
	from an entity datafile which will specify the shader by name. So the shader
	is looked up during load-time and construction of the material.
*/
class IRuMaterial : public IRuObject
{
	ruRTTI_DECLARE
	ruCLASSGUID_DECLARE

public:
	virtual									~IRuMaterial();

	virtual DWORD							GetDiffuse() const = 0;														// ??? Not sure.... materials have a reflectance strength..
	virtual DWORD							GetSpecular() const = 0;

	virtual INT32							GetNumTextureChannels() const = 0;											// Gets the number of texture channels the material holds
	virtual RuTextureChannel				GetTextureChannel(INT32 index) const = 0;									// Gets the texture channel at the specified index

	virtual IRuBaseTexture*					GetTexture(RuTextureChannel texChannel) const = 0;							// Gets the texture specified by the texture channel
	virtual void							SetTexture(RuTextureChannel texChannel, IRuBaseTexture *texture) = 0;		// Sets the texture specified by the texture channel

	virtual const char*						GetShaderName() const = 0;													// Gets the material's preferred shader name
	virtual IRuShader*						GetShader() const = 0;														// Gets the interface to the shader used by the material
	virtual void							SetShader(IRuShader *shader) = 0;											// Sets the shader used by the material

	virtual CRuParameterBlock*		GetParameterBlock() = 0;
	virtual const CRuParameterBlock*	GetParameterBlock() const = 0;

	virtual INT32							GetMaterialPriority() const = 0;
	virtual void							SetMaterialPriority(INT32 priority) = 0;
};

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

class CRuMaterial : public IRuMaterial
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	struct RuMatTexture
	{
		RuTextureChannel					m_textureChannel;											// Texture channel associated with the texture
		IRuBaseTexture*						m_texture;													// The texture
	};

	CRuArrayList<RuMatTexture>				m_textures;													// List of textures used by this material
	char*									m_shaderName;												// Name of shader used by this material
	IRuShader*								m_shader;													// Shader used by this material
	CRuParameterBlock					m_parameterBlock;											// Parameter block
	INT32									m_materialPriority;

	BOOL									m_isDeprecatedMaterial;
	RuMaterial_Type							m_materialType;
	RuMaterial_LightingType					m_lightingType;

public:
											CRuMaterial();
	virtual									~CRuMaterial();

	virtual IRuObject*						Clone(IRuObject *clonedObject = NULL);

	// IRuObject serialization
	virtual BOOL							SerializeFrom(IRuStream *stream);
	virtual BOOL							SerializeTo(IRuStream *stream);

	virtual DWORD							GetDiffuse() const;
	virtual DWORD							GetSpecular() const;

	virtual INT32							GetNumTextureChannels() const;
	virtual RuTextureChannel				GetTextureChannel(INT32 index) const;
	BOOL									SetTextureChannel(INT32 index, RuTextureChannel texChannel);

	INT32									AddTextureChannel(RuTextureChannel texChannel);
	BOOL									DeleteTextureChannelAtIndex(INT32 index);

	virtual IRuBaseTexture*					GetTexture(RuTextureChannel texChannel) const;
	virtual void							SetTexture(RuTextureChannel texChannel, IRuBaseTexture *texture);

	virtual const char*						GetShaderName() const;
	void									SetShaderName(const char *shaderName);
	virtual IRuShader*						GetShader() const;
	virtual void							SetShader(IRuShader *shader);

	virtual CRuParameterBlock*		GetParameterBlock();
	virtual const CRuParameterBlock*	GetParameterBlock() const;

	virtual INT32							GetMaterialPriority() const;
	virtual void							SetMaterialPriority(INT32 priority);

protected:
	void									SelectShader();
};

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

ruOBJECTMODULE_DEFINE(CRuObjectModule_Material, CRuMaterial)

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

inline IRuMaterial::~IRuMaterial()
{
}

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

#pragma managed

#endif
