///////////////////////////////////////////////////////////////////////////////
/// @file deRenderStates.hpp
///
/// @brief a header to include all renderstate classes
///
/// @author Lightning
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Aug 2001
/// @author Lightning
/// @remarks Creation
///
/// @date May 2002
/// @author Assassin
/// @remarks Interface implementation
///
/// @date Oct 2002
/// @author Assassin
/// @remarks deWorld integration
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DERENDERSTATES_HPP
#define DERENDERSTATES_HPP

#include "deGlobalTypes.hpp"
#include "deWorld.hpp"

//define to wether or not we are exporting the classes
#if defined(DEDRIVER_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define RENDERSTATE_API extern "C" DEDLL_EXPORT
#elif defined(DESTINY3D_STATIC_LINK)
#	define RENDERSTATE_API extern "C"
#else
#	define RENDERSTATE_API extern "C" DEDLL_IMPORT
#endif

//-------------------------------------------
// Defines
//-------------------------------------------

//how many texture stages are allowed, this can't really be moved to an ini as it is
//determined by direct3d's capability
#define TEXTURESTAGE_COUNT 8

//-------------------------------------------
// Classes
//-------------------------------------------
class IdeBitmapProxy;
class IdeRenderTexture;
class IdeRenderMaterial;
class IdeRenderLight;

// factory functions
	RENDERSTATE_API deBoolean IdeRenderState_SetDefaultTextureFilters(long MinFilter, long MagFilter, long MipFilter, deBoolean EnableMip);
	/// Get the IdeRenderState WorldObject interface ID
	RENDERSTATE_API long IdeRenderState_GetWOInterfaceID();
	/// Create an instance of IdeRenderTexture
	RENDERSTATE_API IdeRenderTexture* IdeRenderState_CreateRenderTexture();
	/// Create an instance of IdeRenderMaterial
	RENDERSTATE_API IdeRenderMaterial* IdeRenderState_CreateRenderMaterial();
	/// Create an instance of IdeRenderLight
	RENDERSTATE_API IdeRenderLight* IdeRenderState_CreateRenderLight();

/// The base renderstate class
//class IdeRenderState : virtual public IdeWorldObject
DE3D_INTERFACE(IdeRenderState, IdeWorldObject)
{
	//constructor and destructor
protected:
	virtual ~IdeRenderState() {}
public:
	enum Type
	{
		TYPE_RSTATE = -1,
		TYPE_TEXTURE = 0,
		TYPE_LIGHT,
		TYPE_MATERIAL,
		TYPE_COUNT,
		TYPE_FORCE_32BIT = 0x7FFFFFFF
	};
	
	//renderstate info
	virtual IdeRenderState::Type GetRSType() const = 0;
	virtual void * GetRSInterface(IdeRenderState::Type type) const = 0;
	
	//lock/unlock functions
	/// You must call this method before calling any Set*** methods.
	virtual deBoolean Lock() = 0;
	/// You must call this method once you are done setting data, so that something else may.
	virtual deBoolean Unlock() = 0;
};

/// the texture renderstate class
/// @todo split IdeRenderTexture into 2 separate ones - TextureSet and FFPixel
//class IdeRenderTexture : virtual public IdeRenderState
DE3D_INTERFACE(IdeRenderTexture, IdeRenderState)
{
public:
	/// texture operations
	enum TextureOp
	{
		TEXTUREOP_INVALID = -1,			// invalid texture operation
		TEXTUREOP_DISABLE = 0,			///< no texture operation

		//operation selection
		TEXTUREOP_SELECTARG1,			///< use texture arg1 as output
		TEXTUREOP_SELECTARG2,			///< use texture arg2 as output

		//modulation
		TEXTUREOP_MODULATE,				///< S = A * B
		TEXTUREOP_MODULATE2X,			///< S = (A * B) << 1
		TEXTUREOP_MODULATE4X,			///< S = (A * B) << 2

		//add/subtract
		TEXTUREOP_ADD,					///< S = A + B
		TEXTUREOP_ADDSIGNED,			///< S = A + B - 0.5
		TEXTUREOP_ADDSIGNED2X,			///< S = (A + B - 0.5) << 1
		TEXTUREOP_SUBTRACT,				///< S = A - B
		TEXTUREOP_ADDSMOOTH,			///< S = A + B - (A * B)

		//blending
		TEXTUREOP_BLENDDIFFUSEALPHA,	///< blend based on alpha of all previous textures
		TEXTUREOP_BLENDTEXTUREALPHA,	///< blend based on this texture's alpha
		TEXTUREOP_BLENDFACTORALPHA,		///< blend based on scalar alpha
		TEXTUREOP_BLENDTEXTUREALPHAPM,	///< blend based on this texture's alpha (alpha is pre-multiplied)
		TEXTUREOP_BLENDPREVIOUSALPHA,	///< blend based on alpha of previous texture

		//specular mapping
		TEXTUREOP_PREMODULATE,					///< modulate texture with next texture stage
		TEXTUREOP_MODULATEALPHA_ADDCOLOR,		///< S = A.rgb + (A.a * B.rgb)
		TEXTUREOP_MODULATECOLOR_ADDALPHA,		///< S = (A.rgb * B.rgb) + A.a
		TEXTUREOP_MODULATEINVALPHA_ADDCOLOR,	///< S = (1 - A.a) * B.rgb + A.rgb
		TEXTUREOP_MODULATEINVCOLOR_ADDALPHA,	///< S = (1 - A.rgb) * B.rgb + A.a

		//bump mapping
		TEXTUREOP_BUMPENVMAP,				///< bump mapping using environment of next texture stage without luminance
		TEXTUREOP_BUMPENVMAPLUMINANCE,		///< bump mapping using environment of next texture stage with luminance
		TEXTUREOP_DOTPRODUCT3,				///< S = (A.r * B.r) + (A.g * B.g) + (A.b * B.b)

		//triadic texture blending (whatever this is, just doing whatever d3d allows - Lightning)
		TEXTUREOP_MULTIPLYADD,		///< S =  A + (B * C)
		TEXTUREOP_LERP,				///< S = (A * B) + ((1 - A) * C)

		TEXTUREOP_COUNT,
		TEXTUREOP_FORCE_32BIT = 0x7FFFFFFF
	};

	/// texture arguments
	enum TextureArg
	{
		TEXTUREARG_INVALID = 0,
		TEXTUREARG_PREVIOUS =		0x0001,		///< use result of previous blending
		TEXTUREARG_DIFFUSE =		0x0002,		///< use diffuse color
		TEXTUREARG_SPECULAR =		0x0004,		///< use specular color
		TEXTUREARG_TEXTURE =		0x0010,		///< use texture itself
		TEXTUREARG_TFACTOR =		0x0020,		///< use color argument supplied with RENDER_TEXTUREFACTOR renderstate
		TEXTUREARG_TEMPREG =        0x0040,		///< can be used as a destination or source for intermediate calculations

		//texture flag modifiers
		TEXTUREARG_ALPHAREPLICATE =	0x0100,		///< replicate alpha to all color channels
		TEXTUREARG_COMPLEMENT =		0x0200,		///< invert the argument

		TEXTUREARG_COUNT,
		TEXTUREARG_FORCE_32BIT = 0x7FFFFFFF
	};

	/// texture addressing modes
	enum TextureAddress
	{
		TEXTUREADDRESS_INVALID = -1,		//invalid address mode
		TEXTUREADDRESS_WRAP = 0,			///< wrap a texture for U or V
		TEXTUREADDRESS_MIRROR,				///< mirror the texture for U or V
		TEXTUREADDRESS_CLAMP,				///< clamp the texture
		TEXTUREADDRESS_COUNT,
		TEXTUREADDRESS_FORCE_32BIT = 0x7FFFFFFF
	};

	/// texture filtering modes
	enum TextureFilter
	{
		TEXTUREFILTER_INVALID = -1,
		TEXTUREFILTER_NONE = 0,				///< no filterning (default for mip-maps)
		TEXTUREFILTER_POINT,				///< Closest-point filter
		TEXTUREFILTER_LINEAR,				///< linear blending filter (bilinear, trilinear)
		TEXTUREFILTER_ANISOTROPIC,			///< anisotropic blending filter
		TEXTUREFILTER_COUNT,
		TEXTUREFILTER_FORCE_32BIT = 0x7FFFFFFF
	};

	enum TextureCoordSource
	{
		TEXCOORD_INVALID = -1,
		TEXCOORD_NOPROCESSING					= 0x00000000,
		TEXCOORD_VIEWSPACE_NORMAL				= 0x00010000,
		TEXCOORD_VIEWSPACE_POSITION				= 0x00020000,
		TEXCOORD_VIEWSPACE_REFLECTIONVECTOR		= 0x00030000,
		TEXCOORD_FORCE_32BIT = 0x7FFFFFFF
	};

	//constructor/destructor
protected:
	virtual ~IdeRenderTexture() {}
public:

	virtual IdeRenderState::Type GetRSType() const = 0;

	//functions for setting/returning texture operations
	/// Set the Texture Stage's color operation
	virtual deBoolean SetColorOperation(long Stage, TextureOp ColorOp) = 0;
	/// Set the Texture Stage's alpha operation
	virtual deBoolean SetAlphaOperation(long Stage, TextureOp AlphaOp) = 0;
	/// Set where the result of this operation will go - either PREVIOUS or TEMPREG
	virtual deBoolean SetResultTarget(long Stage, TextureArg Target) = 0;
	virtual TextureOp GetColorOperation(long Stage) const = 0;
	virtual TextureOp GetAlphaOperation(long Stage) const = 0;
	virtual TextureArg GetResultTarget(long Stage) = 0;
	
	//functions for setting the arguments
	/// Set the Texture Stage's color input argument
	/// @param ArgNum min:1 max:3
	virtual deBoolean SetColorArg(long Stage, long ArgNum, TextureArg Arg) = 0;
	/// Set the Texture Stage's alpha input argument
	/// @param ArgNum min:1 max:3
	virtual deBoolean SetAlphaArg(long Stage, long ArgNum, TextureArg Arg) = 0;
	virtual TextureArg GetColorArg(long Stage, long ArgNum) const = 0;
	virtual TextureArg GetAlphaArg(long Stage, long ArgNum) const = 0;

	//texture information
	/// Set the Texture Stage's source bitmap
	virtual deBoolean SetBitmap(long Stage, IdeBitmapProxy* Bitmap) = 0;
	/// Retrieve the Texture Stage's source bitmap
	virtual IdeBitmapProxy*GetBitmap(long Stage) const = 0;

	//functions to set how the texture looks
	/// Set the Texture Stage's U (horizontal) addressing mode
	virtual deBoolean SetTextureAddressU(long Stage, TextureAddress Address) = 0;
	/// Set the Texture Stage's V (vertical) addressing mode
	virtual deBoolean SetTextureAddressV(long Stage, TextureAddress Address) = 0;
	virtual TextureAddress GetTextureAddressU(long Stage) const = 0;
	virtual TextureAddress GetTextureAddressV(long Stage) const = 0;

	// functions to set how the texture magnifies and minifies
	// ie, linear filter to magnify is very common
	/// Set the Texture Stage's minification filter (when more than 1 texel is in a screen pixel)
	virtual deBoolean SetTextureMinFilter(long Stage, TextureFilter Filter) = 0;
	/// Set the Texture Stage's magnification filter (when 1 texel affects more than 1 screen pixel)
	virtual deBoolean SetTextureMagFilter(long Stage, TextureFilter Filter) = 0;
	/// Set the Texture Stage's mipmap filter (when blending between two mipmaps)
	virtual deBoolean SetTextureMipFilter(long Stage, TextureFilter Filter) = 0;
	virtual TextureFilter GetTextureMinFilter(long Stage) const = 0;
	virtual TextureFilter GetTextureMagFilter(long Stage) const = 0;
	virtual TextureFilter GetTextureMipFilter(long Stage) const = 0;

	virtual deBoolean SetTexCoordSource(long Stage, long SourceStage) = 0;
	virtual deBoolean SetTexCoordGen(long Stage, TextureCoordSource SourcePipe, long CopyWrapModeStage = 0) = 0;
	virtual deBoolean GetTexCoordSource(long Stage, long &SourceStage, TextureCoordSource &SourceFlags) = 0;
	virtual long GetTexCoordSourceCombined(long Stage) = 0;

	virtual deBoolean SetTextureProjection(long Stage, deBoolean Enable) = 0;
	virtual deBoolean GetTextureProjection(long Stage) = 0;
	
	virtual deBoolean CopyStageSettings(IdeRenderTexture* Target, long SourceStage, long TargetStage) const = 0;
};

/// the material renderstate class. Methods are pretty self-explanatory
//class IdeRenderMaterial : virtual public IdeRenderState
DE3D_INTERFACE(IdeRenderMaterial, IdeRenderState)
{
public:
	enum MatSource_t
	{
		MATSOURCE_INVALID = -1,
		MATSOURCE_MATERIAL = 0,	///< Use the material's values
		MATSOURCE_DIFFUSE,		///< Use the vertex diffuse values
		MATSOURCE_SPECULAR,		///< Use the vertex diffuse values
		MATSOURCE_COUNT,
		MATSOURCE_FORCE_32BIT = 0x7FFFFFFF
	};
	struct MatData
	{
		deColor		AmbientColor;	//ambient color
		deColor		DiffuseColor;	//diffuse color
		deColor		EmissiveColor;	//emissive color
		deColor		SpecularColor;	//specular color
		MatSource_t	AmbientSource;
		MatSource_t	DiffuseSource;
		MatSource_t	SpecularSource;
		MatSource_t	EmissiveSource;
		float		Power;			//power of the light
	};
	//constructor/destructor
protected:
	virtual ~IdeRenderMaterial() {}
public:

	virtual IdeRenderState::Type GetRSType() const = 0;

	//color information
	virtual deBoolean SetAmbientColor(deColor *AmbientColor) = 0;
	virtual deBoolean GetAmbientColor(deColor *AmbientColor) const = 0;
	
	virtual deBoolean SetDiffuseColor(deColor *DiffuseColor) = 0;
	virtual deBoolean GetDiffuseColor(deColor *DiffuseColor) const = 0;
	
	virtual deBoolean SetSpecularColor(deColor *SpecularColor) = 0;
	virtual deBoolean GetSpecularColor(deColor *SpecularColor) const = 0;
	
	virtual deBoolean SetEmissiveColor(deColor *EmissiveColor) = 0;
	virtual deBoolean GetEmissiveColor(deColor *EmissiveColor) const = 0;

	// base source info
	virtual deBoolean SetAmbientSource(MatSource_t Source) = 0;
	virtual MatSource_t GetAmbientSource() const = 0;

	virtual deBoolean SetDiffuseSource(MatSource_t Source) = 0;
	virtual MatSource_t GetDiffuseSource() const = 0;

	virtual deBoolean SetSpecularSource(MatSource_t Source) = 0;
	virtual MatSource_t GetSpecularSource() const = 0;
	
	virtual deBoolean SetEmissiveSource(MatSource_t Source) = 0;
	virtual MatSource_t GetEmissiveSource() const = 0;
	
	//power of the light
	virtual deBoolean SetSpecularPower(float Power) = 0;
	virtual float GetSpecularPower() const = 0;

	virtual const MatData* GetAllData() const = 0;
	virtual deBoolean SetAllData(const MatData* Data) = 0;
};

/// the light renderstate class. Methods are pretty self-explanatory
//class IdeRenderLight : virtual public IdeRenderState
DE3D_INTERFACE(IdeRenderLight, IdeRenderState)
{
public:
	enum LightType_t
	{
		LIGHTTYPE_INVALID = -1,
		LIGHTTYPE_POINT = 0,		///< A point light - has position only
		LIGHTTYPE_SPOT,				///< A spotlight - has position and direction
		LIGHTTYPE_DIRECTIONAL,		///< A directional light - has direction only
		LIGHTTYPE_COUNT,
		LIGHTTYPE_FORCE_32BIT = 0x7FFFFFFF
	};
	struct LightData
	{
		LightType_t	LightType;		//type of light
		deColor		AmbientColor;	//ambient color
		deColor		DiffuseColor;	//diffuse color
		deColor		SpecularColor;	//specular color
		deVec3f		Position;		//position of the light
		deVec3f		Direction;		//direction to face
		deFloat		MaxRange;		//maximum range for the light
		deFloat		FallOff;		//how the light changes as it gets farther away from the source
		deFloat		Attenuation[3];	//light attenuation
		deFloat		Theta;			//angle, in radians, of the inner cone
		deFloat		Phi;			//angle, in radians, of the outer cone
		s32			ID;				//the id/number of the light
		deBoolean	Status;			//the status of the light (on/off)
	};

	//constructor/destructor
protected:
	virtual ~IdeRenderLight() {}
public:

	virtual IdeRenderState::Type GetRSType() const = 0;

	//the light type
	virtual deBoolean SetLightType(LightType_t Type) = 0;
	virtual LightType_t GetLightType() const = 0;

	//color information
	virtual deBoolean SetAmbientColor(deColor *AmbientColor) = 0;
	virtual deBoolean GetAmbientColor(deColor *AmbientColor) const = 0;

	virtual deBoolean SetDiffuseColor(deColor *DiffuseColor) = 0;
	virtual deBoolean GetDiffuseColor(deColor *DiffuseColor) const = 0;

	virtual deBoolean SetSpecularColor(deColor *SpecularColor) = 0;
	virtual deBoolean GetSpecularColor(deColor *SpecularColor) const = 0;

	//position/direction information
	virtual deBoolean SetPosition(deVertex *Position) = 0;
	virtual deBoolean GetPosition(deVertex *Position) const = 0;

	virtual deBoolean SetDirection(deVertex *Direction) = 0;
	virtual deBoolean GetDirection(deVertex *Direction) const = 0;

	//anything that affects the way the light looks/acts
	virtual deBoolean SetRange(float MaxRange) = 0;
	virtual float GetRange() const = 0;

	virtual deBoolean SetFallOff(float FallOff) = 0;
	virtual float GetFallOff() const = 0;

	virtual deBoolean SetAttenuation(long Number, float Value) = 0;
	virtual float GetAttenuation(long Number) const = 0;

	virtual deBoolean SetTheta(float Theta) = 0;
	virtual float GetTheta() const = 0;

	virtual deBoolean SetPhi(float Phi) = 0;
	virtual float GetPhi() const = 0;

	//which light number it is
	virtual deBoolean SetID(long Number) = 0;
	virtual long GetID() const = 0;

	//light status (on/off)
	virtual deBoolean SetStatus(deBoolean On) = 0;
	virtual deBoolean GetStatus() const = 0;

	virtual const LightData* GetAllData() const = 0;
	virtual deBoolean SetAllData(const LightData* Data) = 0;
};

#endif
