Sign in to follow this  
cozzie

State manager, code review/ suggestions?

Recommended Posts

Hi,

To prevent/ minimize redundant state setting in my engine, I've added my own 'state machine'.

It all seems to be working fine, even with d3d debug on highest warning level, there's nothing redundant left tongue.png

 

I've pasted the code below, with the question if you have any remarks or suggestions (things I've overlooked or so).

Any input appreciated as always.

// DEFINITIONS, from my header file

/**************************************************************************************/
/***								D3D_STATES structs								***/
/*** keeps track of a D3D state and it's value										***/
/*** values based on the d3dtypes.h enums, i.e. D3DRS_ZENABLE = 7, D3DZB_TRUE = 1	***/
/**************************************************************************************/

typedef struct D3D_RENDERSTATE
{
	D3DRENDERSTATETYPE	state;
	DWORD				value;
} D3D_RENDERSTATE;

typedef struct D3D_TEXSTAGE
{
	DWORD						stage;
	D3DTEXTURESTAGESTATETYPE	state;
	DWORD						value;
} D3D_TEXSTAGE;

typedef struct D3D_SAMPLER
{
	DWORD						sampler;
	D3DSAMPLERSTATETYPE			type;
	DWORD						value;
} D3D_SAMPLER;

/**************************************************************************************/
/***								CD3DSTATEMACH class								***/
/*** stores a (single) direct3d9 state machine with it's members and functions		***/
/**************************************************************************************/

class CD3dstateMach
{
public:
	bool Setup(IDirect3DDevice9 *pD3ddev);

	bool SetRenderState(const D3DRENDERSTATETYPE pState, const DWORD pValue);
	bool SetTextureStageState(const DWORD pStage, const D3DTEXTURESTAGESTATETYPE pState, const DWORD pValue);
	bool SetSamplerState(const DWORD pSampler, const D3DSAMPLERSTATETYPE pType, const DWORD pValue);

	CD3dstateMach();
	~CD3dstateMach();

private:
	CComPtr<IDirect3DDevice9>	mD3ddev;		// smart pointer

	std::vector<D3D_RENDERSTATE>	mRender;
	std::vector<D3D_TEXSTAGE>		mTexStage;
	std::vector<D3D_SAMPLER>		mSampler;
};

// IMPLEMENTATION

#define DEF_RENDER		9
#define DEF_TEXSTAGE	2
#define DEF_SAMPLER		6

D3D_RENDERSTATE defRenderState[] = 		{	{D3DRS_LIGHTING,			FALSE					},
											{D3DRS_SRCBLEND,			D3DBLEND_SRCALPHA		},
											{D3DRS_DESTBLEND,			D3DBLEND_INVSRCALPHA	},
											{D3DRS_ZENABLE,				D3DZB_TRUE				},
											{D3DRS_ZWRITEENABLE,		TRUE					},
											{D3DRS_CULLMODE,			D3DCULL_CCW				},
											{D3DRS_STENCILENABLE,		FALSE					},
											{D3DRS_FILLMODE,			D3DFILL_SOLID			},
											{D3DRS_ALPHABLENDENABLE,	FALSE					}};

D3D_TEXSTAGE defTexStageState[] = {			{0,	D3DTSS_ALPHAOP,			D3DTOP_SELECTARG1		},
											{0,	D3DTSS_ALPHAARG1,		D3DTA_TEXTURE			}};

D3D_SAMPLER defSamplerState[] = {			{0, D3DSAMP_MAGFILTER,		D3DTEXF_LINEAR			},
											{0, D3DSAMP_MIPFILTER,		D3DTEXF_LINEAR			},
											{0, D3DSAMP_MINFILTER,		D3DTEXF_ANISOTROPIC		},
											{0, D3DSAMP_MAXANISOTROPY,	4						},
											{0, D3DSAMP_ADDRESSU,		D3DTADDRESS_WRAP		},
											{0, D3DSAMP_ADDRESSV,		D3DTADDRESS_WRAP		}};

/**************************************************************************************/
/***								CONSTRUCTOR										***/
/*** ==> usage: when creating a CD3dstatemach object								***/
/*** ==> sets all variables to initial values										***/
/**************************************************************************************/

CD3dstateMach::CD3dstateMach()
{
	mD3ddev = NULL;		// smart pointer

	// renderstates
	mRender.reserve(10);
	mRender.resize(0);

	// texturestage states
	mTexStage.reserve(10);
	mTexStage.resize(0);

	// sampler states
	mSampler.reserve(10);
	mSampler.resize(0);
}

/**************************************************************************************/
/***								DESTRUCTOR										***/
/*** ==> usage: when CD3dstateMach object is not needed anymore						***/
/*** ==> resets values and cleans up if necessary									***/
/**************************************************************************************/

CD3dstateMach::~CD3dstateMach()
{
	mD3ddev = NULL;		// smart pointer
}

/**************************************************************************************/
/***									SETUP								  CONST	***/
/*** ==> usage: initial setup of d3d state machine					  				***/
/*** ==> sets the default d3d states applicable for the engine						***/
/**************************************************************************************/

bool CD3dstateMach::Setup(IDirect3DDevice9 *pD3ddev)
{
	// save pointer (smart) of the d3d device
	if((mD3ddev = pD3ddev) == NULL) return false;

	// renderstates
	D3D_RENDERSTATE newRenderState;
	for(int rs=0;rs<DEF_RENDER;++rs)
	{
		newRenderState.state	= defRenderState[rs].state;
		newRenderState.value	= defRenderState[rs].value;
		mRender.push_back(newRenderState);
	}

	// texturestage states
	D3D_TEXSTAGE newTexStage;
	for(int ts=0;ts<DEF_TEXSTAGE;++ts)
	{
		newTexStage.stage	= defTexStageState[ts].stage;
		newTexStage.state	= defTexStageState[ts].state;
		newTexStage.value	= defTexStageState[ts].value;
		mTexStage.push_back(newTexStage);
	}

	// sampler states	
	D3D_SAMPLER newSampler;
	for(int ss=0;ss<DEF_SAMPLER;++ss)
	{
		newSampler.sampler	= defSamplerState[ss].sampler;
		newSampler.type		= defSamplerState[ss].type;
		newSampler.value	= defSamplerState[ss].value;
		mSampler.push_back(newSampler);
	}

	/** set renderstates directly to D3D API						**\
	\** ONLY when engine default is other then API default state	**/

	for(int rs=0;rs<3;++rs) mD3ddev->SetRenderState(mRender[rs].state, mRender[rs].value);
	for(int ss=0;ss<4;++ss) mD3ddev->SetSamplerState(mSampler[ss].sampler, mSampler[ss].type, mSampler[ss].value);

	return true;
}

/**************************************************************************************/
/***								SET RENDERSTATE									***/
/*** ==> usage: sets a renderstate to the d3d device if needed 		  				***/
/*** ==> checks current value/states and only updates when needed					***/
/**************************************************************************************/

bool CD3dstateMach::SetRenderState(const D3DRENDERSTATETYPE pState, const DWORD pValue)
{
	for(size_t rs=0;rs<mRender.size();++rs)
	{
		if(mRender[rs].state == pState)
		{
			if(mRender[rs].value != pValue)
			{
				mRender[rs].value = pValue;
				mD3ddev->SetRenderState(mRender[rs].state, mRender[rs].value);
				return true;
			}
			else return false;
		}
	}

	// NEW STATE
	D3D_RENDERSTATE newState = { pState, pValue };
	mRender.push_back(newState);
	mD3ddev->SetRenderState(mRender.back().state, mRender.back().value);
	return true;
}

/**************************************************************************************/
/***							SET TEXTURESTAGE STATE								***/
/*** ==> usage: sets a texturestage state to the d3d device if needed 				***/
/*** ==> checks current value/states and only updates when needed					***/
/**************************************************************************************/

bool CD3dstateMach::SetTextureStageState(const DWORD pStage, const D3DTEXTURESTAGESTATETYPE pState, const DWORD pValue)
{
	for(size_t ts=0;ts<mTexStage.size();++ts)
	{
		if(mTexStage[ts].stage == pStage)
		{
			if(mTexStage[ts].state == pState)
			{
				if(mTexStage[ts].value != pValue)
				{
					mTexStage[ts].value = pValue;
					mD3ddev->SetTextureStageState(mTexStage[ts].stage, mTexStage[ts].state, mRender[ts].value);
					return true;
				}
				else return false;
			}
			else		
			{
				// new state, existing stage
				D3D_TEXSTAGE newState = { pStage, pState, pValue };
				mTexStage.push_back(newState);
				mD3ddev->SetTextureStageState(mTexStage.back().stage, mTexStage.back().state, mTexStage.back().value);
				return true;
			}
		}
	}

	// NEW STAGE & NEW STATE
	D3D_TEXSTAGE newState = { pStage, pState, pValue };
	mTexStage.push_back(newState);
	mD3ddev->SetTextureStageState(mTexStage.back().stage, mTexStage.back().state, mTexStage.back().value);
	return true;
}

/**************************************************************************************/
/***								SET SAMPLER STATE								***/
/*** ==> usage: sets a sampler sate to the d3d device if needed 	  				***/
/*** ==> checks current value/states and only updates when needed					***/
/**************************************************************************************/

bool CD3dstateMach::SetSamplerState(const DWORD pSampler, const D3DSAMPLERSTATETYPE pType, const DWORD pValue)
{
	for(size_t ss=0;ss<mSampler.size();++ss)
	{
		if(mSampler[ss].sampler == pSampler)
		{
			if(mSampler[ss].type == pType)
			{
				if(mSampler[ss].value != pValue)
				{
					mSampler[ss].value = pValue;
					mD3ddev->SetSamplerState(mSampler[ss].sampler, mSampler[ss].type, mSampler[ss].value);
					return true;
				}
				else return false;
			}
			else		
			{
				// new state, existing stage
				D3D_SAMPLER newSampler = { pSampler, pType, pValue };
				mSampler.push_back(newSampler);
				mD3ddev->SetSamplerState(mSampler.back().sampler, mSampler.back().type, mSampler.back().value);
				return true;
			}
		}
	}

	// NEW SAMPLER & TYPE
	D3D_SAMPLER newSampler = { pSampler, pType, pValue };
	mSampler.push_back(newSampler);
	mD3ddev->SetSamplerState(mSampler.back().sampler, mSampler.back().type, mSampler.back().value);
	return true;
}



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this