forked from metin2/client
1
0
Fork 0
client/EterLib/StateManager.h

342 lines
11 KiB
C++

/******************************************************************************
Copyright (C) 1999, 2000 NVIDIA Corporation
This file is provided without support, instruction, or implied warranty of any
kind. NVIDIA makes no guarantee of its fitness for a particular purpose and is
not liable under any circumstances for any damages or loss whatsoever arising
from the use or inability to use this file or items derived from it.
Comments:
A simple class to manage rendering state. Created as a singleton.
Create it as a static global, or with new. It doesn't matter as long as it is created
before you use the CStateManager::GetSingleton() API to get a reference to it.
Call it with STATEMANAGER.SetRenderState(...)
Call it with STATEMANAGER.SetTextureStageState(...), etc.
Call the 'Save' versions of the function if you want to deviate from the current state.
Call the 'Restore' version to retrieve the last Save.
There are two levels of caching:
- All Sets/Saves/Restores are tracked for redundancy. This reduces the size of the batch to
be flushed
- The flush function is called before rendering, and only copies state that is
different from the current chip state.
If you get an assert it is probably because an API call failed.
See NVLink for a good example of how this class is used.
Don't be afraid of the vector being used to track the flush batch. It will grow as big as
it needs to be and then stop, so it shouldn't be reallocated.
The state manager holds a reference to the d3d device.
- cmaughan@nvidia.com
******************************************************************************/
#ifndef __CSTATEMANAGER_H
#define __CSTATEMANAGER_H
#include <d3d8.h>
#include <d3dx8.h>
#include <vector>
#include "../eterBase/Singleton.h"
#define CHECK_D3DAPI(a) \
{ \
HRESULT hr = (a); \
\
if (hr != S_OK) \
assert(!#a); \
}
static const DWORD STATEMANAGER_MAX_RENDERSTATES = 256;
static const DWORD STATEMANAGER_MAX_TEXTURESTATES = 128;
static const DWORD STATEMANAGER_MAX_STAGES = 8;
static const DWORD STATEMANAGER_MAX_VCONSTANTS = 96;
static const DWORD STATEMANAGER_MAX_PCONSTANTS = 8;
static const DWORD STATEMANAGER_MAX_TRANSFORMSTATES = 300; // World1 lives way up there...
static const DWORD STATEMANAGER_MAX_STREAMS = 16;
class CStreamData
{
public:
CStreamData(LPDIRECT3DVERTEXBUFFER8 pStreamData = NULL, UINT Stride = 0) : m_lpStreamData(pStreamData), m_Stride(Stride)
{
}
bool operator == (const CStreamData& rhs) const
{
return ((m_lpStreamData == rhs.m_lpStreamData) && (m_Stride == rhs.m_Stride));
}
LPDIRECT3DVERTEXBUFFER8 m_lpStreamData;
UINT m_Stride;
};
class CIndexData
{
public:
CIndexData(LPDIRECT3DINDEXBUFFER8 pIndexData = NULL, UINT BaseVertexIndex = 0)
: m_lpIndexData(pIndexData),
m_BaseVertexIndex(BaseVertexIndex)
{
}
bool operator == (const CIndexData& rhs) const
{
return ((m_lpIndexData == rhs.m_lpIndexData) && (m_BaseVertexIndex == rhs.m_BaseVertexIndex));
}
LPDIRECT3DINDEXBUFFER8 m_lpIndexData;
UINT m_BaseVertexIndex;
};
// State types managed by the class
typedef enum eStateType
{
STATE_MATERIAL = 0,
STATE_RENDER,
STATE_TEXTURE,
STATE_TEXTURESTAGE,
STATE_VSHADER,
STATE_PSHADER,
STATE_TRANSFORM,
STATE_VCONSTANT,
STATE_PCONSTANT,
STATE_STREAM,
STATE_INDEX
} eStateType;
class CStateID
{
public:
CStateID(eStateType Type, DWORD dwValue0 = 0, DWORD dwValue1 = 0)
: m_Type(Type),
m_dwValue0(dwValue0),
m_dwValue1(dwValue1)
{
}
CStateID(eStateType Type, DWORD dwStage, D3DTEXTURESTAGESTATETYPE StageType)
: m_Type(Type),
m_dwStage(dwStage),
m_TextureStageStateType(StageType)
{
}
CStateID(eStateType Type, D3DRENDERSTATETYPE RenderType)
: m_Type(Type),
m_RenderStateType(RenderType)
{
}
eStateType m_Type;
union
{
DWORD m_dwValue0;
DWORD m_dwStage;
D3DRENDERSTATETYPE m_RenderStateType;
D3DTRANSFORMSTATETYPE m_TransformStateType;
};
union
{
DWORD m_dwValue1;
D3DTEXTURESTAGESTATETYPE m_TextureStageStateType;
};
};
typedef std::vector<CStateID> TStateID;
class CStateManagerState
{
public:
CStateManagerState()
{
}
void ResetState()
{
DWORD i, y;
for (i = 0; i < STATEMANAGER_MAX_RENDERSTATES; i++)
m_RenderStates[i] = 0x7FFFFFFF;
for (i = 0; i < STATEMANAGER_MAX_STAGES; i++)
for (y = 0; y < STATEMANAGER_MAX_TEXTURESTATES; y++)
m_TextureStates[i][y] = 0x7FFFFFFF;
for (i = 0; i < STATEMANAGER_MAX_STREAMS; i++)
m_StreamData[i] = CStreamData();
m_IndexData = CIndexData();
for (i = 0; i < STATEMANAGER_MAX_STAGES; i++)
m_Textures[i] = NULL;
// Matrices and constants are not cached, just restored. It's silly to check all the
// data elements (by which time the driver could have been sent them).
for (i = 0; i < STATEMANAGER_MAX_TRANSFORMSTATES; i++)
D3DXMatrixIdentity(&m_Matrices[i]);
for (i = 0; i < STATEMANAGER_MAX_VCONSTANTS; i++)
m_VertexShaderConstants[i] = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f);
for (i = 0; i < STATEMANAGER_MAX_PCONSTANTS; i++)
m_PixelShaderConstants[i] = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f);
m_dwPixelShader = 0;
m_dwVertexShader = D3DFVF_XYZ;
ZeroMemory(&m_Matrices, sizeof(D3DXMATRIX) * STATEMANAGER_MAX_TRANSFORMSTATES);
}
// Renderstates
DWORD m_RenderStates[STATEMANAGER_MAX_RENDERSTATES];
// Texture stage states
DWORD m_TextureStates[STATEMANAGER_MAX_STAGES][STATEMANAGER_MAX_TEXTURESTATES];
// Vertex shader constants
D3DXVECTOR4 m_VertexShaderConstants[STATEMANAGER_MAX_VCONSTANTS];
// Pixel shader constants
D3DXVECTOR4 m_PixelShaderConstants[STATEMANAGER_MAX_PCONSTANTS];
// Textures
LPDIRECT3DBASETEXTURE8 m_Textures[STATEMANAGER_MAX_STAGES];
// Shaders
DWORD m_dwPixelShader;
DWORD m_dwVertexShader;
D3DXMATRIX m_Matrices[STATEMANAGER_MAX_TRANSFORMSTATES];
D3DMATERIAL8 m_D3DMaterial;
CStreamData m_StreamData[STATEMANAGER_MAX_STREAMS];
CIndexData m_IndexData;
};
class CStateManager : public CSingleton<CStateManager>
{
public:
CStateManager(LPDIRECT3DDEVICE8 lpDevice);
virtual ~CStateManager();
void SetDefaultState();
void Restore();
bool BeginScene();
void EndScene();
// Material
void SaveMaterial();
void SaveMaterial(const D3DMATERIAL8 * pMaterial);
void RestoreMaterial();
void SetMaterial(const D3DMATERIAL8 * pMaterial);
void GetMaterial(D3DMATERIAL8 * pMaterial);
void SetLight(DWORD index, CONST D3DLIGHT8* pLight);
void GetLight(DWORD index, D3DLIGHT8* pLight);
// Renderstates
void SaveRenderState(D3DRENDERSTATETYPE Type, DWORD dwValue);
void RestoreRenderState(D3DRENDERSTATETYPE Type);
void SetRenderState(D3DRENDERSTATETYPE Type, DWORD Value);
void GetRenderState(D3DRENDERSTATETYPE Type, DWORD * pdwValue);
// Textures
void SaveTexture(DWORD dwStage, LPDIRECT3DBASETEXTURE8 pTexture);
void RestoreTexture(DWORD dwStage);
void SetTexture(DWORD dwStage, LPDIRECT3DBASETEXTURE8 pTexture);
void GetTexture(DWORD dwStage, LPDIRECT3DBASETEXTURE8 * ppTexture);
// Texture stage states
void SaveTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE Type, DWORD dwValue);
void RestoreTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE Type);
void SetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE Type, DWORD dwValue);
void GetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE Type, DWORD * pdwValue);
void SetBestFiltering(DWORD dwStage); // if possible set anisotropy filtering, or use trilinear
// Vertex Shader
void SaveVertexShader(DWORD dwShader);
void RestoreVertexShader();
void SetVertexShader(DWORD dwShader);
void GetVertexShader(DWORD * pdwShader);
// Pixel Shader
void SavePixelShader(DWORD dwShader);
void RestorePixelShader();
void SetPixelShader(DWORD dwShader);
void GetPixelShader(DWORD * pdwShader);
// *** These states are cached, but not protected from multiple sends of the same value.
// Transform
void SaveTransform(D3DTRANSFORMSTATETYPE Transform, const D3DMATRIX* pMatrix);
void RestoreTransform(D3DTRANSFORMSTATETYPE Transform);
// Don't cache-check the transform. To much to do
void SetTransform(D3DTRANSFORMSTATETYPE Type, const D3DMATRIX* pMatrix);
void GetTransform(D3DTRANSFORMSTATETYPE Type, D3DMATRIX * pMatrix);
// SetVertexShaderConstant
void SaveVertexShaderConstant(DWORD dwRegister, CONST void* pConstantData, DWORD dwConstantCount);
void RestoreVertexShaderConstant(DWORD dwRegister, DWORD dwConstantCount);
void SetVertexShaderConstant(DWORD dwRegister, CONST void* pConstantData, DWORD dwConstantCount);
// SetPixelShaderConstant
void SavePixelShaderConstant(DWORD dwRegister, CONST void* pConstantData, DWORD dwConstantCount);
void RestorePixelShaderConstant(DWORD dwRegister, DWORD dwConstantCount);
void SetPixelShaderConstant(DWORD dwRegister, CONST void* pConstantData, DWORD dwConstantCount);
void SaveStreamSource(UINT StreamNumber, LPDIRECT3DVERTEXBUFFER8 pStreamData, UINT Stride);
void RestoreStreamSource(UINT StreamNumber);
void SetStreamSource(UINT StreamNumber, LPDIRECT3DVERTEXBUFFER8 pStreamData, UINT Stride);
void SaveIndices(LPDIRECT3DINDEXBUFFER8 pIndexData, UINT BaseVertexIndex);
void RestoreIndices();
void SetIndices(LPDIRECT3DINDEXBUFFER8 pIndexData,UINT BaseVertexIndex);
HRESULT DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount);
HRESULT DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
HRESULT DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount);
HRESULT DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertexIndices, UINT PrimitiveCount, CONST void * pIndexData, D3DFORMAT IndexDataFormat, CONST void * pVertexStreamZeroData, UINT VertexStreamZeroStride);
// Codes For Debug
DWORD GetRenderState(D3DRENDERSTATETYPE Type);
private:
void SetDevice(LPDIRECT3DDEVICE8 lpDevice);
private:
CStateManagerState m_ChipState;
CStateManagerState m_CurrentState;
CStateManagerState m_CopyState;
TStateID m_DirtyStates;
bool m_bForce;
bool m_bScene;
DWORD m_dwBestMinFilter;
DWORD m_dwBestMagFilter;
LPDIRECT3DDEVICE8 m_lpD3DDev;
#ifdef _DEBUG
// Saving Flag
BOOL m_bRenderStateSavingFlag[STATEMANAGER_MAX_RENDERSTATES];
BOOL m_bTextureStageStateSavingFlag[STATEMANAGER_MAX_STAGES][STATEMANAGER_MAX_TEXTURESTATES];
BOOL m_bTransformSavingFlag[STATEMANAGER_MAX_TRANSFORMSTATES];
#endif _DEBUG
};
#define STATEMANAGER (CStateManager::Instance())
#endif __CSTATEMANAGER_H