//////////////////////////////////////////////////////////////////////////
/// <summary>
/// A helper class for setting render states of the graphics device.
/// </summary>
//////////////////////////////////////////////////////////////////////////
public static class RSHelper
{
/*********************************************************************/
// Members.
/*********************************************************************/
#region Enumerations
[Flags]
public enum RSVar : ulong
{
AlphaBlendEnable = 1,
AlphaBlendOperation = AlphaBlendEnable << 1,
AlphaDestinationBlend = AlphaBlendOperation << 1,
AlphaFunction = AlphaDestinationBlend << 1,
AlphaSourceBlend = AlphaFunction << 1,
AlphaTestEnable = AlphaSourceBlend << 1,
BlendFactor = AlphaTestEnable << 1,
BlendFunction = BlendFactor << 1,
ColorWriteChannels = BlendFunction << 1,
ColorWriteChannels1 = ColorWriteChannels << 1,
ColorWriteChannels2 = ColorWriteChannels1 << 1,
ColorWriteChannels3 = ColorWriteChannels2 << 1,
CounterClockwiseStencilDepthBufferFail = ColorWriteChannels3 << 1,
CounterClockwiseStencilFail = CounterClockwiseStencilDepthBufferFail << 1,
CounterClockwiseStencilFunction = CounterClockwiseStencilFail << 1,
CounterClockwiseStencilPass = CounterClockwiseStencilFunction << 1,
CullMode = CounterClockwiseStencilPass << 1,
DepthBias = CullMode << 1,
DepthBufferEnable = DepthBias << 1,
DepthBufferFunction = DepthBufferEnable << 1,
DepthBufferWriteEnable = DepthBufferFunction << 1,
DestinationBlend = DepthBufferWriteEnable << 1,
FillMode = DestinationBlend << 1,
FogColor = FillMode << 1,
FogDensity = FogColor << 1,
FogEnable = FogDensity << 1,
FogEnd = FogEnable << 1,
FogStart = FogEnd << 1,
FogTableMode = FogStart << 1,
FogVertexMode = FogTableMode << 1,
MultiSampleAntiAlias = FogVertexMode << 1,
MultiSampleMask = MultiSampleAntiAlias << 1,
PointSize = MultiSampleMask << 1,
PointSizeMax = PointSize << 1,
PointSizeMin = PointSizeMax << 1,
PointSpriteEnable = PointSizeMin << 1,
RangeFogEnable = PointSpriteEnable << 1,
ReferenceAlpha = RangeFogEnable << 1,
ReferenceStencil = ReferenceAlpha << 1,
ScissorTestEnable = ReferenceStencil << 1,
SeparateAlphaBlendEnabled = ScissorTestEnable << 1,
SlopeScaleDepthBias = SeparateAlphaBlendEnabled << 1,
SourceBlend = SlopeScaleDepthBias << 1,
StencilDepthBufferFail = SourceBlend << 1,
StencilEnable = StencilDepthBufferFail << 1,
StencilFail = StencilEnable << 1,
StencilFunction = StencilFail << 1,
StencilMask = StencilFunction << 1,
StencilPass = StencilMask << 1,
StencilWriteMask = StencilPass << 1,
TwoSidedStencilMode = StencilWriteMask << 1,
}
#endregion // Enumerations
#region Internal Data Structures
//////////////////////////////////////////////////////////////////////////
/// <summary>
/// Render state data structure.
/// </summary>
//////////////////////////////////////////////////////////////////////////
private struct RSData
{
/*********************************************************************/
// Members.
/*********************************************************************/
#region Fields
/// <summary>Index reference.</summary>
public int Index;
/// <summary>Shift data.</summary>
public ulong ShiftData;
/// <summary>Object type.</summary>
public object ObjectType;
#endregion // Fields
/*********************************************************************/
// Functions.
/*********************************************************************/
#region Intialization
//////////////////////////////////////////////////////////////////////////
/// <summary>
/// Alternate constructor.
/// </summary>
/// <param name="_nIndex">Index reference.</param>
/// <param name="_ulShiftDatta">Shift data.</param>
/// <param name="_objType">Object type.</param>
//////////////////////////////////////////////////////////////////////////
public RSData(int _nIndex, ulong _ulShiftDatta, object _objType)
{
Index = _nIndex;
ShiftData = _ulShiftDatta;
ObjectType = _objType;
}
#endregion // Initialization
}
#endregion // Internal Data Structures
#region Fields
/// <summary>Stored previous state.</summary>
private static ulong m_prevState = 0x00;
/// <summary>List of render state data.</summary>
private static List
<RSData
> m_RSList
= new List
<RSData
>();
#endregion // Fields
/*********************************************************************/
// Functions.
/*********************************************************************/
#region Private Methods
//////////////////////////////////////////////////////////////////////////
/// <summary>
/// Determine if the bit is on.
/// </summary>
/// <param name="_nBitField">The bitfield to manipulate.</param>
/// <param name="_nBitPos">The bit position to toggle on/off.</param>
//////////////////////////////////////////////////////////////////////////
private static bool IsBitOn(ulong _nBitField, ulong _nShiftBitPos)
{
return ((_nShiftBitPos & _nBitField) == _nShiftBitPos) ? true : false;
}
//////////////////////////////////////////////////////////////////////////
/// <summary>
/// Set the current renderstate based on parameters passed in.
/// </summary>
/// <param name="_RenderState">The current renderstate to use.</param>
/// <param name="_ulRSVariable">Variables to set.</param>
/// <param name="_nIndex">Current index of the _Values.</param>
/// <param name="_Values">Values used to set the variables. (Must be in sequence with _Variables).</param>
//////////////////////////////////////////////////////////////////////////
private static void SetRenderState(RenderState _RenderState, ulong _ulRSVariable, int _nIndex, params object[] _Values)
{
switch ((RSVar)_ulRSVariable)
{
case RSVar.AlphaBlendEnable: _RenderState.AlphaBlendEnable = (bool)_Values[_nIndex]; break;
case RSVar.AlphaBlendOperation: _RenderState.AlphaBlendOperation = (BlendFunction)_Values[_nIndex]; break;
case RSVar.AlphaDestinationBlend: _RenderState.AlphaDestinationBlend = (Blend)_Values[_nIndex]; break;
case RSVar.AlphaFunction: _RenderState.AlphaFunction = (CompareFunction)_Values[_nIndex]; break;
case RSVar.AlphaSourceBlend: _RenderState.AlphaSourceBlend = (Blend)_Values[_nIndex]; break;
case RSVar.AlphaTestEnable: _RenderState.AlphaTestEnable = (bool)_Values[_nIndex]; break;
case RSVar.BlendFactor: _RenderState.BlendFactor = (Color)_Values[_nIndex]; break;
case RSVar.BlendFunction: _RenderState.BlendFunction = (BlendFunction)_Values[_nIndex]; break;
case RSVar.ColorWriteChannels: _RenderState.ColorWriteChannels = (ColorWriteChannels)_Values[_nIndex]; break;
case RSVar.ColorWriteChannels1: _RenderState.ColorWriteChannels1 = (ColorWriteChannels)_Values[_nIndex]; break;
case RSVar.ColorWriteChannels2: _RenderState.ColorWriteChannels2 = (ColorWriteChannels)_Values[_nIndex]; break;
case RSVar.ColorWriteChannels3: _RenderState.ColorWriteChannels3 = (ColorWriteChannels)_Values[_nIndex]; break;
case RSVar.CounterClockwiseStencilDepthBufferFail: _RenderState.CounterClockwiseStencilDepthBufferFail = (StencilOperation)_Values[_nIndex]; break;
case RSVar.CounterClockwiseStencilFail: _RenderState.CounterClockwiseStencilFail = (StencilOperation)_Values[_nIndex]; break;
case RSVar.CounterClockwiseStencilFunction: _RenderState.CounterClockwiseStencilFunction = (CompareFunction)_Values[_nIndex]; break;
case RSVar.CounterClockwiseStencilPass: _RenderState.CounterClockwiseStencilPass = (StencilOperation)_Values[_nIndex]; break;
case RSVar.CullMode: _RenderState.CullMode = (CullMode)_Values[_nIndex]; break;
case RSVar.DepthBias: _RenderState.DepthBias = (float)_Values[_nIndex]; break;
case RSVar.DepthBufferEnable: _RenderState.AlphaBlendEnable = (bool)_Values[_nIndex]; break;
case RSVar.DepthBufferFunction: _RenderState.DepthBufferFunction = (CompareFunction)_Values[_nIndex]; break;
case RSVar.DepthBufferWriteEnable: _RenderState.DepthBufferWriteEnable = (bool)_Values[_nIndex]; break;
case RSVar.DestinationBlend: _RenderState.DestinationBlend = (Blend)_Values[_nIndex]; break;
case RSVar.FillMode: _RenderState.FillMode = (FillMode)_Values[_nIndex]; break;
case RSVar.FogColor: _RenderState.FogColor = (Color)_Values[_nIndex]; break;
case RSVar.FogDensity: _RenderState.FogDensity = (float)_Values[_nIndex]; break;
case RSVar.FogEnable: _RenderState.FogEnable = (bool)_Values[_nIndex]; break;
case RSVar.FogEnd: _RenderState.FogEnd = (float)_Values[_nIndex]; break;
case RSVar.FogStart: _RenderState.FogStart = (float)_Values[_nIndex]; break;
case RSVar.FogTableMode: _RenderState.FogTableMode = (FogMode)_Values[_nIndex]; break;
case RSVar.FogVertexMode: _RenderState.FogVertexMode = (FogMode)_Values[_nIndex]; break;
case RSVar.MultiSampleAntiAlias: _RenderState.MultiSampleAntiAlias = (bool)_Values[_nIndex]; break;
case RSVar.MultiSampleMask: _RenderState.MultiSampleMask = (int)_Values[_nIndex]; break;
case RSVar.PointSize: _RenderState.PointSize = (float)_Values[_nIndex]; break;
case RSVar.PointSizeMax: _RenderState.PointSizeMax = (float)_Values[_nIndex]; break;
case RSVar.PointSizeMin: _RenderState.PointSizeMin = (float)_Values[_nIndex]; break;
case RSVar.PointSpriteEnable: _RenderState.PointSpriteEnable = (bool)_Values[_nIndex]; break;
case RSVar.RangeFogEnable: _RenderState.RangeFogEnable = (bool)_Values[_nIndex]; break;
case RSVar.ReferenceAlpha: _RenderState.ReferenceAlpha = (int)_Values[_nIndex]; break;
case RSVar.ReferenceStencil: _RenderState.ReferenceStencil = (int)_Values[_nIndex]; break;
case RSVar.ScissorTestEnable: _RenderState.ScissorTestEnable = (bool)_Values[_nIndex]; break;
case RSVar.SeparateAlphaBlendEnabled: _RenderState.SeparateAlphaBlendEnabled = (bool)_Values[_nIndex]; break;
case RSVar.SlopeScaleDepthBias: _RenderState.SlopeScaleDepthBias = (float)_Values[_nIndex]; break;
case RSVar.SourceBlend: _RenderState.SourceBlend = (Blend)_Values[_nIndex]; break;
case RSVar.StencilDepthBufferFail: _RenderState.StencilDepthBufferFail = (StencilOperation)_Values[_nIndex]; break;
case RSVar.StencilEnable: _RenderState.StencilEnable = (bool)_Values[_nIndex]; break;
case RSVar.StencilFail: _RenderState.StencilFail = (StencilOperation)_Values[_nIndex]; break;
case RSVar.StencilFunction: _RenderState.StencilFunction = (CompareFunction)_Values[_nIndex]; break;
case RSVar.StencilMask: _RenderState.StencilMask = (int)_Values[_nIndex]; break;
case RSVar.StencilPass: _RenderState.StencilPass = (StencilOperation)_Values[_nIndex]; break;
case RSVar.StencilWriteMask: _RenderState.StencilWriteMask = (int)_Values[_nIndex]; break;
case RSVar.TwoSidedStencilMode: _RenderState.TwoSidedStencilMode = (bool)_Values[_nIndex]; break;
default:
break;
}
}
#endregion // Private Methods
#region Public Methods
//////////////////////////////////////////////////////////////////////////
/// <summary>
/// Set the render state based on parameters passed in.
/// <para>NOTE: This function runs through _Variables from least to most</para>
/// <para>significant bit. In other words, _Variables must be in alphabetical</para>
/// <para>order for the function to work correctly.</para>
/// </summary>
/// <param name="_RenderState">The current render state to use.</param>
/// <param name="_Variables">Render state variables to set. (Must be in alphabetical order (Enumeration order)).</param>
/// <param name="_Values">Values used to set the variables. (Must be in the same sequence as the _Variables).</param>
//////////////////////////////////////////////////////////////////////////
public static void Set(RenderState _RenderState,
RSVar _Variables,
params object[] _Values)
{
//////////////////////////////////////////////////////////////////////////
// Local variables.
int nBitPos = 0;
int nIndex = 0;
bool bBreak = false;
bool bNoChange = true;
List
<ulong> UpdateList
= new List
<ulong>();
List
<RSData
> NewList
= new List
<RSData
>();
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Run through the list of renderstates to check if values have changed.
while (m_RSList.Count > 0 && UpdateList.Count < _Values.Length && NewList.Count < _Values.Length &&
nBitPos
< (sizeof(ulong) * 8))
{
//////////////////////////////////////////////////////////////////////////
// Shift to the next bit position and check if the bit is on.
ulong nShiftBitPos = (ulong)((ulong)1 << nBitPos);
if (IsBitOn((ulong)_Variables, nShiftBitPos))
{
//////////////////////////////////////////////////////////////////////////
// Run through the list of variables.
foreach (RSData data in m_RSList)
{
//////////////////////////////////////////////////////////////////////////
// Run through the list of values.
foreach (object value in _Values)
{
//////////////////////////////////////////////////////////////////////////
// Check if the render state has already been activated.
if (data.ShiftData == nShiftBitPos)
{
//////////////////////////////////////////////////////////////////////////
// Check the data type and value if they have changed.
if (data.ObjectType.GetType() == value.GetType() &&
data.ObjectType.ToString() != value.ToString())
UpdateList.Add(nShiftBitPos);
// Break out of the loop.
bBreak = true;
bNoChange = false;
break;
}
//
//////////////////////////////////////////////////////////////////////////
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Break out of the loop.
if (bBreak)
break;
//
//////////////////////////////////////////////////////////////////////////
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// There is a new render state.
if (!bBreak)
NewList.
Add(new RSData
(nIndex, nShiftBitPos, _Values
[nIndex
]));
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Reset break flag and increment the next index.
bBreak = false;
++nIndex;
//
//////////////////////////////////////////////////////////////////////////
}
//
//////////////////////////////////////////////////////////////////////////
// Increment to next bit position.
++nBitPos;
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Determine if there are new renderstates.
if (NewList.Count > 0)
{
nIndex = 0;
for (int i = NewList.Count - 1; i >= 0; --i)
{
SetRenderState(_RenderState, NewList[i].ShiftData, NewList[i].Index, _Values);
m_RSList.
Add(new RSData
(NewList
[i
].
Index, NewList
[i
].
ShiftData, _Values
[nIndex
++]));
}
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Determine if there has been a change to an already activated renderstate.
else if (UpdateList.Count > 0)
{
nIndex = 0;
foreach (ulong ulValue in UpdateList)
{
SetRenderState(_RenderState, ulValue, nIndex, _Values);
m_RSList.
Add(new RSData
(nIndex, ulValue, _Values
[nIndex
]));
//////////////////////////////////////////////////////////////////////////
// Run through the list, in reverse, to determine if this render state has
// been added and modified.
for (int i = m_RSList.Count - 2; i >= 0; --i)
{
// This means we found the same render state but it has been modified.
// So we will need to copy it and remove the last added one.
if (m_RSList[i].ShiftData == ulValue)
{
// Remove at current location, insert new data and remove the last added data.
m_RSList.RemoveAt(i);
m_RSList.
Insert(i,
new RSData
(nIndex, ulValue, _Values
[nIndex
]));
m_RSList.RemoveAt(m_RSList.Count - 1);
}
}
//
//////////////////////////////////////////////////////////////////////////
// Increment next index.
++nIndex;
}
}
//////////////////////////////////////////////////////////////////////////
// Check if there have been changes.
else if (bNoChange)
{
//////////////////////////////////////////////////////////////////////////
// See what states have changed.
ulong ulChanges = (ulong)_Variables ^ m_prevState;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Reset local variables.
nIndex = 0;
nBitPos = 0;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Run through and search which bit has been activated.
while ((ulChanges
!= 0
) && nBitPos
< (sizeof(ulong) * 8))
{
//////////////////////////////////////////////////////////////////////////
// Determine if the bit is on.
ulong nShiftBitPos = (ulong)(1 << nBitPos);
if (IsBitOn((ulong)_Variables, nShiftBitPos))
{
SetRenderState(_RenderState, nShiftBitPos, nIndex, _Values);
m_RSList.
Add(new RSData
(nIndex, nShiftBitPos, _Values
[nIndex
++]));
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Increment to the next bit position.
++nBitPos;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Clear this bit to shorten the loop.
ulChanges ^= (nShiftBitPos & (ulong)ulChanges);
//
//////////////////////////////////////////////////////////////////////////
}
//
//////////////////////////////////////////////////////////////////////////
// Store the pervious state.
m_prevState = (ulong)_Variables;
}
//
//////////////////////////////////////////////////////////////////////////
}
//////////////////////////////////////////////////////////////////////////
/// <summary>
/// Reset the current renderstate based on changes made.
/// </summary>
/// <param name="_currentRenderState">The current render state.</param>
//////////////////////////////////////////////////////////////////////////
public static void Reset(RenderState _currentRenderState)
{
//////////////////////////////////////////////////////////////////////////
// Check if there were any changes.
if (m_RSList.Count > 0)
{
//////////////////////////////////////////////////////////////////////////
// Run through the list of changes.
foreach (RSData data in m_RSList)
{
//////////////////////////////////////////////////////////////////////////
// Determine the index reference.
switch ((RSVar)data.Index)
{
case RSVar.AlphaBlendEnable: _currentRenderState.AlphaBlendEnable = false; break;
case RSVar.AlphaBlendOperation: _currentRenderState.AlphaBlendOperation = BlendFunction.Add; break;
case RSVar.AlphaDestinationBlend: _currentRenderState.AlphaDestinationBlend = Blend.One; break;
case RSVar.AlphaFunction: _currentRenderState.AlphaFunction = CompareFunction.Always; break;
case RSVar.AlphaSourceBlend: _currentRenderState.AlphaSourceBlend = Blend.One; break;
case RSVar.AlphaTestEnable: _currentRenderState.AlphaTestEnable = false; break;
case RSVar.BlendFactor: _currentRenderState.BlendFactor = Color.White; break;
case RSVar.BlendFunction: _currentRenderState.BlendFunction = BlendFunction.Add; break;
case RSVar.ColorWriteChannels: _currentRenderState.ColorWriteChannels = ColorWriteChannels.None; break;
case RSVar.ColorWriteChannels1: _currentRenderState.ColorWriteChannels1 = ColorWriteChannels.None; break;
case RSVar.ColorWriteChannels2: _currentRenderState.ColorWriteChannels2 = ColorWriteChannels.None; break;
case RSVar.ColorWriteChannels3: _currentRenderState.ColorWriteChannels3 = ColorWriteChannels.None; break;
case RSVar.CounterClockwiseStencilDepthBufferFail: _currentRenderState.CounterClockwiseStencilDepthBufferFail = StencilOperation.Keep; break;
case RSVar.CounterClockwiseStencilFail: _currentRenderState.CounterClockwiseStencilFail = StencilOperation.Keep; break;
case RSVar.CounterClockwiseStencilFunction: _currentRenderState.CounterClockwiseStencilFunction = CompareFunction.Always; break;
case RSVar.CounterClockwiseStencilPass: _currentRenderState.CounterClockwiseStencilPass = StencilOperation.Keep; break;
case RSVar.CullMode: _currentRenderState.CullMode = CullMode.CullCounterClockwiseFace; break;
case RSVar.DepthBias: _currentRenderState.DepthBias = 0f; break;
case RSVar.DepthBufferEnable: _currentRenderState.DepthBufferEnable = false; break;
case RSVar.DepthBufferFunction: _currentRenderState.DepthBufferFunction = CompareFunction.LessEqual; break;
case RSVar.DepthBufferWriteEnable: _currentRenderState.DepthBufferWriteEnable = true; break;
case RSVar.DestinationBlend: _currentRenderState.DestinationBlend = Blend.Zero; break;
case RSVar.FillMode: _currentRenderState.FillMode = FillMode.Solid; break;
case RSVar.FogColor: _currentRenderState.FogColor = Color.TransparentBlack; break;
case RSVar.FogDensity: _currentRenderState.FogDensity = 1f; break;
case RSVar.FogEnable: _currentRenderState.FogEnable = false; break;
case RSVar.FogEnd: _currentRenderState.FogEnd = 1f; break;
case RSVar.FogStart: _currentRenderState.FogStart = 0f; break;
case RSVar.FogTableMode: _currentRenderState.FogTableMode = FogMode.None; break;
case RSVar.FogVertexMode: _currentRenderState.FogVertexMode = FogMode.None; break;
case RSVar.MultiSampleAntiAlias: _currentRenderState.MultiSampleAntiAlias = true; break;
case RSVar.
MultiSampleMask: unchecked { _currentRenderState.
MultiSampleMask = (int)0xffffffff
; } break
;
case RSVar.PointSize: _currentRenderState.PointSize = 64f; break;
case RSVar.PointSizeMax: _currentRenderState.PointSizeMax = 64f; break;
case RSVar.PointSizeMin: _currentRenderState.PointSizeMin = 1f; break;
case RSVar.PointSpriteEnable: _currentRenderState.PointSpriteEnable = false; break;
case RSVar.RangeFogEnable: _currentRenderState.RangeFogEnable = false; break;
case RSVar.ReferenceAlpha: _currentRenderState.ReferenceAlpha = 0; break;
case RSVar.ReferenceStencil: _currentRenderState.ReferenceStencil = 0; break;
case RSVar.ScissorTestEnable: _currentRenderState.ScissorTestEnable = false; break;
case RSVar.SeparateAlphaBlendEnabled: _currentRenderState.SeparateAlphaBlendEnabled = false; break;
case RSVar.SlopeScaleDepthBias: _currentRenderState.SlopeScaleDepthBias = 0; break;
case RSVar.SourceBlend: _currentRenderState.SourceBlend = Blend.One; break;
case RSVar.StencilDepthBufferFail: _currentRenderState.StencilDepthBufferFail = StencilOperation.Keep; break;
case RSVar.StencilEnable: _currentRenderState.StencilEnable = false; break;
case RSVar.StencilFail: _currentRenderState.StencilFail = StencilOperation.Keep; break;
case RSVar.StencilFunction: _currentRenderState.StencilFunction = CompareFunction.Always; break;
case RSVar.StencilMask: _currentRenderState.StencilMask = Int32.MaxValue; break;
case RSVar.StencilPass: _currentRenderState.StencilPass = StencilOperation.Keep; break;
case RSVar.StencilWriteMask: _currentRenderState.StencilWriteMask = Int32.MaxValue; break;
case RSVar.TwoSidedStencilMode: _currentRenderState.TwoSidedStencilMode = false; break;
default:
break;
}
//
//////////////////////////////////////////////////////////////////////////
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Clear the list and trim excess.
m_RSList.Clear();
m_RSList.TrimExcess();
m_prevState = 0;
//
//////////////////////////////////////////////////////////////////////////
}
//
//////////////////////////////////////////////////////////////////////////
}
#endregion // Public Methods
}