#pragma once

#include "dllinterface.h"
#include "d3d9.h"
#include "d3dx9.h"

#include "TextureManager.h"
#include "ShaderManager.h"
#include "DXViewPort.h"

#include "d3dapp.h"

class ShaderManager;
class TextureManager;
class BufferManager;
class FontManager;
class DXSwapChain;

#define SAMPLERSTAGES 16
#define STREAMS 8

enum PRIMITIVETYPE 
{
    PT_POINTLIST             = 1,
    PT_LINELIST              = 2,
    PT_LINESTRIP             = 3,
    PT_TRIANGLELIST          = 4,
    PT_TRIANGLESTRIP         = 5,
    PT_TRIANGLEFAN           = 6,
};

enum ZBUFFERTYPE 
{
    ZB_FALSE                 = 0,
    ZB_TRUE                  = 1, // Z buffering
    ZB_USEW                  = 2  // W buffering
};

typedef enum SHADEMODE 
{
    SHADE_FLAT               = 1,
    SHADE_GOURAUD            = 2,
    SHADE_PHONG              = 3
};

enum FILLMODE 
{
    FILL_POINT               = 1,
    FILL_WIREFRAME           = 2,
    FILL_SOLID               = 3
};

enum BLEND 
{
    BLEND_ZERO               = 1,
    BLEND_ONE                = 2,
    BLEND_SRCCOLOR           = 3,
    BLEND_INVSRCCOLOR        = 4,
    BLEND_SRCALPHA           = 5,
    BLEND_INVSRCALPHA        = 6,
    BLEND_DESTALPHA          = 7,
    BLEND_INVDESTALPHA       = 8,
    BLEND_DESTCOLOR          = 9,
    BLEND_INVDESTCOLOR       = 10,
    BLEND_SRCALPHASAT        = 11,
    BLEND_BOTHSRCALPHA       = 12,
    BLEND_BOTHINVSRCALPHA    = 13,
    BLEND_BLENDFACTOR        = 14, /* Only supported if D3DPBLENDCAPS_BLENDFACTOR is on */
    BLEND_INVBLENDFACTOR     = 15, /* Only supported if D3DPBLENDCAPS_BLENDFACTOR is on */
    BLEND_SRCCOLOR2          = 16,
    BLEND_INVSRCCOLOR2       = 17
};

enum CULL 
{
    CULL_NONE                = 1,
    CULL_CW                  = 2,
    CULL_CCW                 = 3
};

enum BLENDOP 
{
    BLENDOP_ADD              = 1,
    BLENDOP_SUBTRACT         = 2,
    BLENDOP_REVSUBTRACT      = 3,
    BLENDOP_MIN              = 4,
    BLENDOP_MAX              = 5
};

enum TEXTUREADDRESS 
{
    TADDRESS_WRAP            = 1,
    TADDRESS_MIRROR          = 2,
    TADDRESS_CLAMP           = 3,
    TADDRESS_BORDER          = 4,
    TADDRESS_MIRRORONCE      = 5
};

enum TEXTUREFILTERTYPE
{
    TEXF_NONE            = 0,
    TEXF_POINT           = 1,
    TEXF_LINEAR          = 2,
    TEXF_ANISOTROPIC     = 3,
    TEXF_PYRAMIDALQUAD   = 6,
	TEXF_GAUSSIANQUAD    = 7
};

enum CMPFUNC 
{
    CMP_NEVER                = 1,
    CMP_LESS                 = 2,
    CMP_EQUAL                = 3,
    CMP_LESSEQUAL            = 4,
    CMP_GREATER              = 5,
    CMP_NOTEQUAL             = 6,
    CMP_GREATEREQUAL         = 7,
    CMP_ALWAYS               = 8
};

struct STStage
{
	//Textures
	LPDIRECT3DBASETEXTURE9 Texture;

	//SamplerStates
	D3DTEXTUREADDRESS AddressU;
	D3DTEXTUREADDRESS AddressV;
	D3DTEXTUREADDRESS AddressW;
	D3DCOLOR BorderColor;
	D3DTEXTUREFILTERTYPE MagFilter;
	D3DTEXTUREFILTERTYPE MinFilter;
	D3DTEXTUREFILTERTYPE MipFilter;
	float MipMapLodBias;
	DWORD MaxMipLevel;
	DWORD MaxAnisotropy;

	//TextureStates
	D3DTEXTUREOP ColorOperation;
	DWORD ColorOperant0;
	DWORD ColorOperant1;
	DWORD ColorOperant2;
	D3DTEXTUREOP AlphaOperation;
	DWORD AlphaOperant0;
	DWORD AlphaOperant1;
	DWORD AlphaOperant2;
	float BumpEnvMat00;
	float BumpEnvMat01;
	float BumpEnvMat10;
	float BumpEnvMat11;
	DWORD TexCoordIndex;
	float BumpEnvLScale;
	float BumpEnvLOffset;
	DWORD TextureTransformFlags;
	DWORD RersultArg;
	DWORD Constant;
};

class DeviceStateManager;

class DXFUNCTIONS_API VertexDeclaration
{
	D3DVERTEXELEMENT9*  m_pDeclElements;
	unsigned			m_ElementCount;
	LPDIRECT3DVERTEXDECLARATION9 m_VDecl;

public:
	VertexDeclaration(DeviceStateManager* const device, const D3DVERTEXELEMENT9* decl);
	~VertexDeclaration(void);

	LPDIRECT3DVERTEXDECLARATION9 GetVDecl(void) const {return m_VDecl;}
	const D3DVERTEXELEMENT9* GetDeclElements(void) const { return m_pDeclElements; }
	unsigned GetElementCount(void) const { return m_ElementCount; }

	unsigned GetVertexSize(const unsigned iStream) const { return D3DXGetDeclVertexSize(m_pDeclElements, iStream); }
};

class DXFUNCTIONS_API DeviceStateManager
{
	D3DApp*					m_App;
	FontManager*			m_FontManager;
	ShaderManager*			m_ShaderManager;
	TextureManager*			m_TextureManager;
	BufferManager*			m_BufferManager;
	
	LList<DXSwapChain>		m_AddSwapChains;

	LPDIRECT3DDEVICE9	m_Device;
	D3DCAPS9			m_Caps;
	DXViewPort*			m_pViewPort;

	DWORD				m_PrimitiveCount; //Counts the primitives that got rendered
	DWORD				m_DrawCallCount;

	//PPL Parameters
	LPDIRECT3DVERTEXDECLARATION9 m_VertexDeclaration;
	LPDIRECT3DVERTEXSHADER9 m_VertexShader;
	LPDIRECT3DPIXELSHADER9 m_PixelShader;

	//StreamSources
	LPDIRECT3DINDEXBUFFER9 m_IndexBuffer;
	LPDIRECT3DVERTEXBUFFER9 m_VertexStreams[STREAMS];
	UINT m_StartOffset[STREAMS];
	UINT m_Stride[STREAMS];

	//Flexible Vertex Format
	DWORD m_FVF;

	STStage m_Stages[SAMPLERSTAGES];

	//Material (Ambient,Diffuse,Specular,Emissive,Power)
	D3DMATERIAL9 m_Material;

	//Transforms
	DXMatrix m_ViewMatrix;
	DXMatrix m_ProjMatrix;
	DXMatrix m_WorldMatrix;

	//RenderStates
	ZBUFFERTYPE m_ZEnable;
	FILLMODE m_Fillmode;
	SHADEMODE m_Shademode;
	bool m_ZWriteEnable;
	bool m_AlphaTestEnable;
	bool m_LastPixel;
	BLEND m_SrcBlend;
	BLEND m_DestBlend;
	CULL m_Cullmode;
	CMPFUNC m_ZFunc;
	DWORD m_AlphaRef;
	CMPFUNC m_AlphaFunc;
	bool m_DitherEnable;
	bool m_AlphaBlendEnable;
	bool m_FogEnable;
	bool m_SpecularEnable;
	D3DCOLOR m_FogColor;
	D3DFOGMODE m_FogTablemode;
	float m_FogStart;
	float m_FogEnd;
	float m_FogDensity;
    bool m_RangefogEnable;
	bool m_StencilEnable;
	D3DSTENCILOP m_StencilFail;
	D3DSTENCILOP m_StencilZFail;
	D3DSTENCILOP m_StencilPass;
	CMPFUNC m_StencilFunc;
	DWORD m_StencilRef;
	DWORD m_StencilMask;
	DWORD m_StencilWritemask;

	D3DCOLOR m_TextureFactor;

	D3DCOLOR m_AmbientLight;
	bool m_Clipping;
	bool m_Lighting;

	bool m_NormalizeNormals;
	D3DVERTEXBLENDFLAGS m_Vertexblend;

	DWORD m_ClipplaneEnable;
	float m_PointSize;

	bool m_IndexedVertexblendEnable;
	UINT m_ColorWriteEnable;

	DWORD F2DW( float f ){return *((DWORD*)&f);}

public:
	DeviceStateManager(LPDIRECT3DDEVICE9 device, D3DApp*app);
	~DeviceStateManager(void);

	void Invalidate(void);
	void Restore(void);

	LPDIRECT3DDEVICE9 GetDevice(void)        {return m_Device;}
	D3DApp*			  GetApp(void)			 {return m_App;}
	FontManager*	  GetFontManager(void)	 {return m_FontManager;}
	ShaderManager*	  GetShaderManager(void) {return m_ShaderManager;}
	TextureManager*	  GetTextureManager(void){return m_TextureManager;}
	BufferManager*	  GetBufferManager(void) {return m_BufferManager;}

	unsigned GetPrimitiveCount(void) const { return m_PrimitiveCount; }
	void ResetPrimitiveCount(void) { m_PrimitiveCount = 0; }
	unsigned GetDrawCallCount(void) const { return m_DrawCallCount; }
	void ResetDrawCallCount(void) { m_DrawCallCount = 0; }

	unsigned GetMaxAnisotropy(void) const { return m_Caps.MaxAnisotropy; }

	void SetMaterial(D3DMATERIAL9&material)
	{
		if(m_Material.Ambient.a != material.Ambient.a || m_Material.Ambient.r != material.Ambient.r || m_Material.Ambient.g != material.Ambient.g || m_Material.Ambient.b != material.Ambient.b ||
			m_Material.Diffuse.a != material.Diffuse.a || m_Material.Diffuse.r != material.Diffuse.r || m_Material.Diffuse.g != material.Diffuse.g || m_Material.Diffuse.b != material.Diffuse.b ||
			m_Material.Emissive.a != material.Emissive.a ||  m_Material.Emissive.r != material.Emissive.r || m_Material.Emissive.g != material.Emissive.g || m_Material.Emissive.b != material.Emissive.b ||
			m_Material.Power != material.Power || 
			m_Material.Specular.a != material.Specular.a || m_Material.Specular.r != material.Specular.r || m_Material.Specular.g != material.Specular.g || m_Material.Specular.b != material.Specular.b)
		{
			m_Material = material;
			m_Device->SetMaterial(&material);
		}
	}
	D3DMATERIAL9 GetMaterial(void)
	{
		return m_Material;
	}
	void SetAmbientMaterial(D3DCOLORVALUE ambient)
	{
		if(m_Material.Ambient.a != ambient.a || m_Material.Ambient.r != ambient.r || m_Material.Ambient.g != ambient.g || m_Material.Ambient.b != ambient.b)
		{
			m_Material.Ambient = ambient;
			m_Device->SetMaterial(&m_Material);
		}
	}
	D3DCOLORVALUE GetAmbientMaterial(void)
	{
		return m_Material.Ambient;
	}
	void SetDiffuseMaterial(D3DCOLORVALUE diffuse)
	{
		if(m_Material.Diffuse.a != diffuse.a || m_Material.Diffuse.r != diffuse.r || m_Material.Diffuse.g != diffuse.g || m_Material.Diffuse.b != diffuse.b)
		{
			m_Material.Diffuse = diffuse;
			m_Device->SetMaterial(&m_Material);
		}
	}
	D3DCOLORVALUE GetDiffuseMaterial(void)
	{
		return m_Material.Diffuse;
	}
	void SetSpecularMaterial(D3DCOLORVALUE specular)
	{
		if(m_Material.Specular.a != specular.a || m_Material.Specular.r != specular.r || m_Material.Specular.g != specular.g || m_Material.Specular.b != specular.b)
		{
			m_Material.Specular = specular;
			m_Device->SetMaterial(&m_Material);
		}
	}
	D3DCOLORVALUE GetSpecularMaterial(void)
	{
		return m_Material.Specular;
	}
	void SetEmissiveMaterial(D3DCOLORVALUE emissive)
	{
		if(m_Material.Emissive.a != emissive.a || m_Material.Emissive.r != emissive.r || m_Material.Emissive.g != emissive.g || m_Material.Emissive.b != emissive.b)
		{
			m_Material.Emissive = emissive;
			m_Device->SetMaterial(&m_Material);
		}
	}
	D3DCOLORVALUE GetEmissiveMaterial(void)
	{
		return m_Material.Emissive;
	}
	void SetMaterialPower(float power)
	{
		if(m_Material.Power != power)
		{
			m_Material.Power = power;
			m_Device->SetMaterial(&m_Material);
		}
	}
	float GetMaterialPower(void)
	{
		return m_Material.Power;
	}

	//Transforms
	void SetViewMatrix(const DXMatrix& view)
	{
		if(m_ViewMatrix != view)
		{
			m_ViewMatrix = view;
			m_Device->SetTransform(D3DTS_VIEW, (D3DXMATRIX*)&view);
		}
	}
	D3DXMATRIX GetViewMatrix(void)
	{
		return m_ViewMatrix;
	}
	void SetProjMatrix(const DXMatrix& proj)
	{
		if(m_ProjMatrix != proj)
		{
			m_ProjMatrix = proj;
			m_Device->SetTransform(D3DTS_PROJECTION, (D3DXMATRIX*)&proj);
		}

	}
	D3DXMATRIX GetProjMatrix(void)
	{
		return m_ProjMatrix;
	}
	void SetWorldMatrix(const DXMatrix& world)
	{
		if(m_WorldMatrix != world)
		{
			m_WorldMatrix = world;
			m_Device->SetTransform(D3DTS_WORLD, (D3DXMATRIX*)&world);
		}
	}
	D3DXMATRIX GetWorldMatrix(void)
	{
		return m_WorldMatrix;
	}

	//Renderstates
	void SetZEnable(ZBUFFERTYPE zenable)
	{
		if(m_ZEnable != zenable)
		{
			m_ZEnable = zenable;
			m_Device->SetRenderState(D3DRS_ZENABLE,zenable);
		}
	}
	void SetFillmode(FILLMODE fillmode)
	{
		if(m_Fillmode != fillmode)
		{
			m_Fillmode = fillmode;
			m_Device->SetRenderState(D3DRS_FILLMODE,fillmode);
		}
	}
	FILLMODE GetFillmode(void)
	{
		return m_Fillmode;
	}
	void SetShademode(SHADEMODE shademode)
	{
		if(m_Shademode != shademode)
		{
			m_Shademode = shademode;
			m_Device->SetRenderState(D3DRS_SHADEMODE,(D3DSHADEMODE)shademode);
		}
	}
	void SetZWriteEnable(bool zwriteenable)
	{
		if(m_ZWriteEnable != zwriteenable)
		{
			m_ZWriteEnable = zwriteenable;
			m_Device->SetRenderState(D3DRS_ZWRITEENABLE,zwriteenable);
		}
	}
	void SetAlphaTestEnable(bool alphatestenable)
	{
		if(m_AlphaTestEnable != alphatestenable)
		{
			m_AlphaTestEnable = alphatestenable;
			m_Device->SetRenderState(D3DRS_ALPHATESTENABLE,alphatestenable);
		}
	}
	void SetLastPixel(bool lastpixel)
	{
		if(m_LastPixel != lastpixel)
		{
			m_LastPixel = lastpixel;
			m_Device->SetRenderState(D3DRS_LASTPIXEL,lastpixel);
		}
	}
	void SetSrcBlend(BLEND srcblend)
	{
		//if(m_SrcBlend != srcblend)
		{
			m_SrcBlend = srcblend;
			m_Device->SetRenderState(D3DRS_SRCBLEND,srcblend);
		}
	}
	void SetDestBlend(BLEND destblend)
	{
		//if(m_DestBlend != destblend)
		{
			m_DestBlend = destblend;
			m_Device->SetRenderState(D3DRS_DESTBLEND,destblend);
		}
	}
	void SetCullmode(CULL cullmode)
	{
		if(m_Cullmode != cullmode)
		{
			m_Cullmode = cullmode;
			m_Device->SetRenderState(D3DRS_CULLMODE,cullmode);
		}
	}
	void SetZFunc(CMPFUNC zfunc)
	{
		if(m_ZFunc != zfunc)
		{
			m_ZFunc = zfunc;
			m_Device->SetRenderState(D3DRS_ZFUNC,zfunc);
		}
	}
	void SetAlphaRef(DWORD alpharef)
	{
		//if(m_AlphaRef != alpharef)
		{
			m_AlphaRef = alpharef;
			m_Device->SetRenderState(D3DRS_ALPHAREF,alpharef);
		}
	}
	void SetAlphaFunc(CMPFUNC alphafunc)
	{
		//if(m_AlphaFunc != alphafunc)
		{
			m_AlphaFunc = alphafunc;
			m_Device->SetRenderState(D3DRS_ALPHAFUNC,(D3DCMPFUNC)alphafunc);
		}
	}
	void SetDitherEnable(bool ditherenable)
	{
		if(m_DitherEnable != ditherenable)
		{
			m_DitherEnable = ditherenable;
			m_Device->SetRenderState(D3DRS_DITHERENABLE,ditherenable);
		}
	}
	void SetAlphaBlendEnable(bool alphablendenable)
	{
		if(m_AlphaBlendEnable != alphablendenable)
		{
			m_AlphaBlendEnable = alphablendenable;
			m_Device->SetRenderState(D3DRS_ALPHABLENDENABLE,alphablendenable);
		}
	}
	void SetFogEnable(bool fogenable)
	{
		if(m_FogEnable != fogenable)
		{
			m_FogEnable = fogenable;
			m_Device->SetRenderState(D3DRS_FOGENABLE,fogenable);
		}
	}
	void SetSpecularEnable(bool specularenable)
	{
		if(m_SpecularEnable != specularenable)
		{
			m_SpecularEnable = specularenable;
			m_Device->SetRenderState(D3DRS_SPECULARENABLE,specularenable);
		}
	}
	void SetFogColor(D3DCOLOR fogcolor)
	{
		if(m_FogColor != fogcolor)
		{
			m_FogColor = fogcolor;
			m_Device->SetRenderState(D3DRS_FOGCOLOR,fogcolor);
		}
	}
	void SetFogTablemode(D3DFOGMODE fogtablemode)
	{
		if(m_FogTablemode != fogtablemode)
		{
			m_FogTablemode = fogtablemode;
			m_Device->SetRenderState(D3DRS_FOGTABLEMODE,fogtablemode);
		}
	}
	void SetFogStart(float fogstart)
	{
		if(m_FogStart != fogstart)
		{
			m_FogStart = fogstart;
			m_Device->SetRenderState(D3DRS_FOGSTART,F2DW(fogstart));
		}
	}
	void SetFogEnd(float fogend)
	{
		if(m_FogEnd != fogend)
		{
			m_FogEnd = fogend;
			m_Device->SetRenderState(D3DRS_FOGEND,F2DW(fogend));
		}
	}
	void SetFogDensity(float fogdensity)
	{
		if(m_FogDensity != fogdensity)
		{
			m_FogDensity = fogdensity;
			m_Device->SetRenderState(D3DRS_FOGDENSITY,F2DW(fogdensity));
		}
	}
	void SetRangefogEnable(bool rangefogenable)
	{
		if(m_RangefogEnable != rangefogenable)
		{
			m_RangefogEnable = rangefogenable;
			m_Device->SetRenderState(D3DRS_RANGEFOGENABLE,rangefogenable);
		}
	}
	void SetStencilEnalbe(bool stencilenable)
	{
		if(m_StencilEnable != stencilenable)
		{
			m_StencilEnable = stencilenable;
			m_Device->SetRenderState(D3DRS_STENCILENABLE,stencilenable);
		}
	}
	void SetStencilFail(D3DSTENCILOP stencilfail)
	{
		if(m_StencilFail != stencilfail)
		{
			m_StencilFail = stencilfail;
			m_Device->SetRenderState(D3DRS_STENCILFAIL,stencilfail);
		}
	}
	void SetStencilZFail(D3DSTENCILOP stencilzfail)
	{
		if(m_StencilZFail != stencilzfail)
		{
			m_StencilZFail = stencilzfail;
			m_Device->SetRenderState(D3DRS_STENCILZFAIL,stencilzfail);
		}
	}
	void SetStencilPass(D3DSTENCILOP stencilpass)
	{
		if(m_StencilPass != stencilpass)
		{
			m_StencilPass = stencilpass;
			m_Device->SetRenderState(D3DRS_STENCILPASS,stencilpass);
		}
	}
	void SetStencilFunc(CMPFUNC stencilfunc)
	{
		if(m_StencilFunc != stencilfunc)
		{
			m_StencilFunc = stencilfunc;
			m_Device->SetRenderState(D3DRS_STENCILFUNC,(D3DCMPFUNC)stencilfunc);
		}
	}
	void SetStencilRef(DWORD stencilref)
	{
		if(m_StencilRef != stencilref)
		{
			m_StencilRef = stencilref;
			m_Device->SetRenderState(D3DRS_STENCILREF,stencilref);
		}
	}
	void SetStencilMask(DWORD stencilmask)
	{
		if(m_StencilMask != stencilmask)
		{
			m_StencilMask = stencilmask;
			m_Device->SetRenderState(D3DRS_STENCILMASK,stencilmask);
		}
	}
	void SetStencilWritemask(DWORD stencilwritemask)
	{
		if(m_StencilWritemask != stencilwritemask)
		{
			m_StencilWritemask = stencilwritemask;
			m_Device->SetRenderState(D3DRS_STENCILWRITEMASK,stencilwritemask);
		}
	}
	void SetTextureFactor(D3DCOLOR texturefactor)
	{
		if(m_TextureFactor != texturefactor)
		{
			m_TextureFactor = texturefactor;
			m_Device->SetRenderState(D3DRS_TEXTUREFACTOR,texturefactor);
		}
	}

	// void SetWrapN();

	void SetClipping(bool clipping)
	{
		if(m_Clipping != clipping)
		{
			m_Clipping = clipping;
			m_Device->SetRenderState(D3DRS_CLIPPING,clipping);
		}
	}
	void SetLighting(bool lighting)
	{
		if(m_Lighting != lighting)
		{
			m_Lighting = lighting;
			m_Device->SetRenderState(D3DRS_LIGHTING,lighting);
		}
	}
	void SetAmbientLight(D3DCOLOR ambientlight)
	{
		if(m_AmbientLight != ambientlight)
		{
			m_AmbientLight = ambientlight;
			m_Device->SetRenderState(D3DRS_AMBIENT,ambientlight);
		}
	}
	D3DCOLOR GetAmbientLight(void)
	{
		return m_AmbientLight;
	}

	/*void SetFogVertexmode();
	void SetColorVertex();
	void SetLocalViewer();*/

	void SetNormalizeNormals(bool normalizenormals)
	{
		if(m_NormalizeNormals != normalizenormals)
		{
			m_NormalizeNormals = normalizenormals;
			m_Device->SetRenderState(D3DRS_NORMALIZENORMALS,normalizenormals);
		}
	}

	/*void SetDiffuseMaterialSource();
	void SetSpecularMaterialSource();
	void SetAmbientMaterialSource();
	void SetEmissiveMaterialSource();*/

	void SetVertexblend(D3DVERTEXBLENDFLAGS vertexblend)
	{
		if(m_Vertexblend != vertexblend)
		{
			m_Vertexblend = vertexblend;
			m_Device->SetRenderState(D3DRS_VERTEXBLEND,vertexblend);
		}
	}
	void SetClipplaneEnable(DWORD clipplaneenable)
	{
		if(m_ClipplaneEnable != clipplaneenable)
		{
			m_ClipplaneEnable = clipplaneenable;
			m_Device->SetRenderState(D3DRS_CLIPPLANEENABLE,clipplaneenable);
		}
	}
	void SetPointSize(float pointsize)
	{
		if(m_PointSize != pointsize)
		{
			m_PointSize = pointsize;
			m_Device->SetRenderState(D3DRS_POINTSIZE,F2DW(pointsize));
		}
	}
	/*void SetPointSize_Min();
	void SetPointSpriteEnable();
	void SetPointScaleEnable();
	void SetPointScale_A();
	void SetPointScale_B();
	void SetPointScale_C();
	void SetMultisampleAntialias();
	void SetMultisampleMask();
	void SetPatchEdgeStyle();
	void SetDebugmonitorToken();
	void SetPointsize_Max();*/

	void SetIndexedVertexblendEnable(bool indexedvertexblendenable)
	{
		if(m_IndexedVertexblendEnable != indexedvertexblendenable)
		{
			m_IndexedVertexblendEnable = indexedvertexblendenable;
			m_Device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE,indexedvertexblendenable);
		}
	}
	void SetColorWriteEnable(UINT colorwriteenable)
	{
		if(m_ColorWriteEnable != colorwriteenable)
		{
			m_ColorWriteEnable = colorwriteenable;
			m_Device->SetRenderState(D3DRS_COLORWRITEENABLE,colorwriteenable);
		}
	}

	/*void SetTweenfactor();
	void SetBlendOp();
	void SetPositionDegree();
	void SetNormalDegree();
	void SetScissorTestEnable();
	void SetSlopeScaleDepthbias();
	void SetAntialiasedLineEnable();
	void SetMinTessellationLevel();
	void SetMaxTessellationLevel();
	void SetAdaptiveTess_X();
	void SetAdaptiveTess_Y();
	void SetAdaptiveTess_Z();
	void SetAdaptiveTess_W();
	void SetEnableAdaptiveTessellation();
	void SetTwoSidedStencilmode();
	void SetCCW_StencilFail();
	void SetCCW_StencilZFail();
	void SetCCW_StencilPass();
	void SetCCW_StencilFunc();
	void SetColorWriteEnable1();
	void SetColorWriteEnable2();
	void SetColorWriteEnable3();
	void SetBlendFactor();
	void SetSRGBWriteEnable();
	void SetDepthBias();
	void SetSeparateAlphablendEnable();
	void SetSrcBlendAlpha();
	void SetDestBlendAlpha();
	void SetBlendOpAlpha();*/

	//PPL Parameters
	void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 vertexdeclaration)
	{
	//	if(m_VertexDeclaration != vertexdeclaration)
		{
			m_FVF = 0;
			m_VertexDeclaration = vertexdeclaration;
			m_Device->SetVertexDeclaration(vertexdeclaration);
		}
	}

	void SetVertexDeclaration(VertexDeclaration* vertexdeclaration)
	{
	//	if(m_VertexDeclaration != vertexdeclaration)
		{
			m_FVF = 0;
			m_VertexDeclaration = vertexdeclaration->GetVDecl();
			m_Device->SetVertexDeclaration(vertexdeclaration->GetVDecl());
		}
	}

	void SetVertexShader(VertexShader* vertexshader)
	{
		if(vertexshader)
			SetVertexShader(vertexshader->GetShader());
		else
			SetVertexShader((LPDIRECT3DVERTEXSHADER9)NULL);
	}
	void SetVertexShader(HLVertexShader* vertexshader)
	{
		if(vertexshader)
			SetVertexShader(vertexshader->GetShader());
		else
			SetVertexShader((LPDIRECT3DVERTEXSHADER9)NULL);
	}
	void SetVertexShader(LPDIRECT3DVERTEXSHADER9 vertexshader)
	{
		if(m_VertexShader != vertexshader)
		{
			m_VertexShader = vertexshader;
			m_Device->SetVertexShader(vertexshader);
		}
	}
	void SetPixelShader(HLPixelShader* pixelshader)
	{
		if(pixelshader)
			SetPixelShader(pixelshader->GetShader());
		else
			SetPixelShader((LPDIRECT3DPIXELSHADER9)NULL);
	}
	void SetPixelShader(PixelShader* pixelshader)
	{
		if(pixelshader)
			SetPixelShader(pixelshader->GetShader());
		else
			SetPixelShader((LPDIRECT3DPIXELSHADER9)NULL);
	}
	void SetPixelShader(LPDIRECT3DPIXELSHADER9 pixelshader)
	{
		if(m_PixelShader != pixelshader)
		{
			m_PixelShader = pixelshader;
			m_Device->SetPixelShader(pixelshader);
		}
	}

	//StreamSources
	void SetIndices(LPDIRECT3DINDEXBUFFER9 indexbuffer)
	{
		//if(m_IndexBuffer != indexbuffer)
		{
			m_IndexBuffer = indexbuffer;
			m_Device->SetIndices(indexbuffer);
		}
	}
	void SetStreamSource(UINT stream,LPDIRECT3DVERTEXBUFFER9 vertexbuffer,UINT startoffset,UINT stride)
	{
		//if(m_VertexStreams[stream] != vertexbuffer || m_StartOffset[stream] != startoffset || m_Stride[stream] != stride)
		{
			m_VertexStreams[stream] = vertexbuffer;
			m_StartOffset[stream] = startoffset;
			m_Stride[stream] = stride;
			m_Device->SetStreamSource(stream,vertexbuffer,startoffset,stride);
		}
	}

	//FVF
	void SetFVF(DWORD fvf)
	{
	//	if(m_FVF != fvf)
		{
			m_VertexDeclaration = NULL;
			m_FVF = fvf;
			m_Device->SetFVF(fvf);
		}
	}

	//Textures
	void SetTexture(DWORD stage,DXSurface* texture)
	{
		if(texture)
			SetTexture(stage,texture->GetSurface());
		else
			SetTexture(stage,(LPDIRECT3DBASETEXTURE9)NULL);
	}
	void SetTexture(DWORD stage,LPDIRECT3DBASETEXTURE9 texture)
	{
		if(m_Stages[stage].Texture != texture)
		{
			m_Stages[stage].Texture = texture;
			m_Device->SetTexture(stage,texture);
		}
	}

	void SetMagFilter(DWORD stage,D3DTEXTUREFILTERTYPE magfilter)
	{
		//if(m_Stages[stage].MagFilter != magfilter)
		{
			m_Stages[stage].MagFilter = magfilter;
			m_Device->SetSamplerState(stage,D3DSAMP_MAGFILTER,magfilter);
		}
	}

	void SetMinFilter(DWORD stage,D3DTEXTUREFILTERTYPE minfilter)
	{
		//if(m_Stages[stage].MinFilter != minfilter)
		{
			m_Stages[stage].MinFilter = minfilter;
			m_Device->SetSamplerState(stage,D3DSAMP_MINFILTER,minfilter);
		}
	}

	void SetMipFilter(DWORD stage,D3DTEXTUREFILTERTYPE mipfilter)
	{
		//if(m_Stages[stage].MipFilter != mipfilter)
		{
			m_Stages[stage].MipFilter = mipfilter;
			m_Device->SetSamplerState(stage,D3DSAMP_MIPFILTER,mipfilter);
		}
	}

	void SetMipMapLodBias(DWORD stage,float mipmaplodbias)
	{
		if(m_Stages[stage].MipMapLodBias != mipmaplodbias)
		{
			m_Stages[stage].MipMapLodBias = mipmaplodbias;
			m_Device->SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,F2DW(mipmaplodbias));
		}
	}

	void SetMaxAnisotropy(DWORD stage,DWORD maxanisotropy)
	{
		if(m_Stages[stage].MaxAnisotropy != maxanisotropy)
		{
			m_Stages[stage].MaxAnisotropy = maxanisotropy;
			m_Device->SetSamplerState(stage,D3DSAMP_MAXANISOTROPY,maxanisotropy);
		}
	}

	void SetTextureAddressU(DWORD stage,D3DTEXTUREADDRESS addressu)
	{
		if(m_Stages[stage].AddressU != addressu)
		{
			m_Stages[stage].AddressU = addressu;
			m_Device->SetSamplerState(stage,D3DSAMP_ADDRESSU,addressu);
		}
	}

	void SetTextureAddressV(DWORD stage,D3DTEXTUREADDRESS addressv)
	{
		if(m_Stages[stage].AddressV != addressv)
		{
			m_Stages[stage].AddressV = addressv;
			m_Device->SetSamplerState(stage,D3DSAMP_ADDRESSV,addressv);
		}
	}

	void SetTextureAddressW(DWORD stage,D3DTEXTUREADDRESS addressw)
	{
		if(m_Stages[stage].AddressW != addressw)
		{
			m_Stages[stage].AddressW = addressw;
			m_Device->SetSamplerState(stage,D3DSAMP_ADDRESSW,addressw);
		}
	}

	void SetBorderColor(DWORD stage,D3DCOLOR color)
	{
		if(m_Stages[stage].BorderColor != color)
		{
			m_Stages[stage].BorderColor = color;
			m_Device->SetSamplerState(stage,D3DSAMP_BORDERCOLOR,color);
		}
	}

	void SetColorOperant0(DWORD stage,DWORD op0)
	{
		//if(m_Stages[stage].ColorOperant0 != op0)
		{
			m_Stages[stage].ColorOperant0 = op0;
			m_Device->SetTextureStageState(stage,D3DTSS_COLORARG0,op0);
		}
	}

	void SetColorOperant1(DWORD stage,DWORD op1)
	{
		//if(m_Stages[stage].ColorOperant1 != op1)
		{
			m_Stages[stage].ColorOperant1 = op1;
			m_Device->SetTextureStageState(stage,D3DTSS_COLORARG1,op1);
		}
	}

	void SetColorOperant2(DWORD stage,DWORD op2)
	{
		//if(m_Stages[stage].ColorOperant2 != op2)
		{
			m_Stages[stage].ColorOperant2 = op2;
			m_Device->SetTextureStageState(stage,D3DTSS_COLORARG2,op2);
		}
	}

	void SetAlphaOperant0(DWORD stage,DWORD op0)
	{
		//if(m_Stages[stage].AlphaOperant0 != op0)
		{
			m_Stages[stage].AlphaOperant0 = op0;
			m_Device->SetTextureStageState(stage,D3DTSS_ALPHAARG0,op0);
		}
	}

	void SetAlphaOperant1(DWORD stage,DWORD op1)
	{
		//if(m_Stages[stage].AlphaOperant1 != op1)
		{
			m_Stages[stage].AlphaOperant1 = op1;
			m_Device->SetTextureStageState(stage,D3DTSS_ALPHAARG1,op1);
		}
	}

	void SetAlphaOperant2(DWORD stage,DWORD op2)
	{
		//if(m_Stages[stage].AlphaOperant2 != op2)
		{
			m_Stages[stage].AlphaOperant2 = op2;
			m_Device->SetTextureStageState(stage,D3DTSS_ALPHAARG2,op2);
		}
	}

	void SetColorOperation(DWORD stage,D3DTEXTUREOP op)
	{
		//if(m_Stages[stage].ColorOperation != op)
		{
			m_Stages[stage].ColorOperation = op;
			m_Device->SetTextureStageState(stage,D3DTSS_COLOROP,op);
		}
	}

	void SetAlphaOperation(DWORD stage,D3DTEXTUREOP op)
	{
		//if(m_Stages[stage].AlphaOperation != op)
		{
			m_Stages[stage].AlphaOperation = op;
			m_Device->SetTextureStageState(stage,D3DTSS_ALPHAOP,op);
		}
	}

	void SetTextureStageConstant(DWORD stage,DWORD constant)
	{
		if(m_Stages[stage].Constant != constant)
		{
			m_Stages[stage].Constant = constant;
			m_Device->SetTextureStageState(stage,D3DTSS_CONSTANT,constant);
		}
	}

	void SetTextureCoordIndex(DWORD stage,DWORD coordindex)
	{
		if(m_Stages[stage].TexCoordIndex != coordindex)
		{
			m_Stages[stage].TexCoordIndex = coordindex;
			m_Device->SetTextureStageState(stage,D3DTSS_TEXCOORDINDEX,coordindex);
		}
	}

	//Grouped Functions
	void SetTextureFilter(DWORD stage,D3DTEXTUREFILTERTYPE magfilter,D3DTEXTUREFILTERTYPE minfilter,D3DTEXTUREFILTERTYPE mipfilter)
	{
		SetMagFilter(stage,magfilter);
		SetMinFilter(stage,minfilter);
		SetMipFilter(stage,mipfilter);
	}

	void SetTextureAddressing(DWORD stage,D3DTEXTUREADDRESS addressu,D3DTEXTUREADDRESS addressv,D3DTEXTUREADDRESS addressw)
	{
		SetTextureAddressU(stage,addressu);
		SetTextureAddressV(stage,addressv);
		SetTextureAddressW(stage,addressw);
	}

	void SetStageColorOperation(DWORD stage,DWORD operant1,D3DTEXTUREOP operation,DWORD operant2)
	{
		SetColorOperant1(stage,operant1);
		SetColorOperation(stage,operation);
		SetColorOperant2(stage,operant2);
	}

	void SetStageAlphaOperation(DWORD stage,DWORD operant1,D3DTEXTUREOP operation,DWORD operant2)
	{
		SetAlphaOperant1(stage,operant1);
		SetAlphaOperation(stage,operation);
		SetAlphaOperant2(stage,operant2);
	}

	DXViewPort* GetViewPort(void) const { return m_pViewPort; }
	const D3DCAPS9* GetCaps(void) const { return &m_Caps; }
	float GetAspectRatio(void)const { return m_pViewPort->GetWidth() / (float)m_pViewPort->GetHeight(); }

	void Clear(DWORD flags, DWORD color, float z, DWORD stencil)
	{
		m_Device->Clear(0, NULL, flags, color, z, stencil);
	}

	//advanced draw functions

	//void Draw2DTexQuad(float xs,float ys,float xe,float ye);
	//void Draw2DTexSprite(float xcenter,float ycenter,float xl,float yl,float rotation);

	//basic draw functions
	void DrawPrimitiveUP(PRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,const void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
	{
		m_PrimitiveCount += PrimitiveCount;
		m_DrawCallCount++;
		SetStreamSource(0,NULL,0,0);
		m_Device->DrawPrimitiveUP((D3DPRIMITIVETYPE)PrimitiveType,PrimitiveCount,pVertexStreamZeroData,VertexStreamZeroStride);
	}

	void DrawPrimitive(PRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount)
	{
		m_PrimitiveCount += PrimitiveCount;
		m_DrawCallCount++;
		m_Device->DrawPrimitive((D3DPRIMITIVETYPE)PrimitiveType,StartVertex,PrimitiveCount);
	}

	void DrawIndexedPrimitiveUP(PRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertices,UINT PrimitiveCount,const void * pIndexData,D3DFORMAT IndexDataFormat,const void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
	{
		m_PrimitiveCount += PrimitiveCount;
		m_DrawCallCount++;
		SetIndices(0);
		SetStreamSource(0,NULL,0,0);
		m_Device->DrawIndexedPrimitiveUP((D3DPRIMITIVETYPE)PrimitiveType,MinVertexIndex,NumVertices,PrimitiveCount,pIndexData,IndexDataFormat,pVertexStreamZeroData,VertexStreamZeroStride);
	}

	void DrawIndexedPrimitive(PRIMITIVETYPE PrimitiveType,INT BaseVertexIndex,UINT MinIndex,UINT NumVertices,UINT StartIndex,UINT PrimitiveCount)
	{
		m_PrimitiveCount += PrimitiveCount;
		m_DrawCallCount++;
		m_Device->DrawIndexedPrimitive((D3DPRIMITIVETYPE)PrimitiveType,BaseVertexIndex,MinIndex,NumVertices,StartIndex,PrimitiveCount);
	} 
	
	DXSwapChain* CreateSwapChain(const STSelMode& mode, const int hwnd);

protected:

	friend DXSwapChain;
	
	void ReleaseSwapChain(DXSwapChain* sc);
};
