using System; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; namespace Foo { public class ManagedRenderState { const int MaxSamplers = 16; readonly List singleChangeSet = new List(), booleanChangeSet = new List(), integerChangeSet = new List(); readonly List queuedSingleStates = new List(), queuedBooleanStates = new List(), queuedIntegerStates = new List(); readonly float[] singleStates = new float[9]; readonly bool[] booleanStates = new bool[12]; readonly uint[] integerStates = new uint[47]; public readonly ManagedSamplerState[] SamplerStates = new ManagedSamplerState[MaxSamplers]; public ManagedRenderState() { for (int i = 0; i < MaxSamplers; i++) SamplerStates[i] = new ManagedSamplerState(); } internal void Refresh(ManagedRenderState rs) { if (singleChangeSet.Count > 0) foreach (byte state in singleChangeSet) TryQueueState(queuedSingleStates, state, singleStates, rs.singleStates[state]); if (booleanChangeSet.Count > 0) foreach (byte state in booleanChangeSet) TryQueueState(queuedBooleanStates, state, booleanStates, rs.booleanStates[state]); if (integerChangeSet.Count > 0) foreach (byte state in integerChangeSet) TryQueueState(queuedIntegerStates, state, integerStates, rs.integerStates[state]); for (int i = 0; i < MaxSamplers; i++) SamplerStates[i].Refresh(rs.SamplerStates[i]); } internal void Reset(ManagedRenderState rs) { for (int i = 0; i < MaxSamplers; i++) SamplerStates[i].Reset(rs.SamplerStates[i]); Array.Copy(rs.booleanStates, 0, booleanStates, 0, 12); Array.Copy(rs.singleStates, 0, singleStates, 0, 8); Array.Copy(rs.integerStates, 0, integerStates, 0, 47); queuedSingleStates.Clear(); if (rs.queuedSingleStates.Count > 0) queuedSingleStates.AddRange(rs.queuedSingleStates); queuedBooleanStates.Clear(); if (rs.queuedBooleanStates.Count > 0) queuedBooleanStates.AddRange(rs.queuedBooleanStates); queuedIntegerStates.Clear(); if (rs.queuedIntegerStates.Count > 0) queuedIntegerStates.AddRange(rs.queuedIntegerStates); singleChangeSet.Clear(); booleanChangeSet.Clear(); integerChangeSet.Clear(); } internal void Reset(GraphicsDevice device) { var rs = device.RenderState; AlphaBlendEnable = rs.AlphaBlendEnable; AlphaBlendOperation = rs.AlphaBlendOperation; AlphaDestinationBlend = rs.AlphaDestinationBlend; AlphaFunction = rs.AlphaFunction; AlphaSourceBlend = rs.AlphaSourceBlend; AlphaTestEnable = rs.AlphaTestEnable; BlendFactor = rs.BlendFactor; BlendFunction = rs.BlendFunction; ColorWriteChannels = rs.ColorWriteChannels; ColorWriteChannels1 = rs.ColorWriteChannels1; ColorWriteChannels2 = rs.ColorWriteChannels2; ColorWriteChannels3 = rs.ColorWriteChannels3; CounterClockwiseStencilDepthBufferFail = rs.CounterClockwiseStencilDepthBufferFail; CounterClockwiseStencilFail = rs.CounterClockwiseStencilFail; CounterClockwiseStencilFunction = rs.CounterClockwiseStencilFunction; CounterClockwiseStencilPass = rs.CounterClockwiseStencilPass; CullMode = rs.CullMode; DepthBias = rs.DepthBias; DepthBufferEnable = rs.DepthBufferEnable; DepthBufferFunction = rs.DepthBufferFunction; DepthBufferWriteEnable = rs.DepthBufferWriteEnable; DestinationBlend = rs.DestinationBlend; FillMode = rs.FillMode; FogColor = rs.FogColor; FogDensity = rs.FogDensity; FogEnable = rs.FogEnable; FogEnd = rs.FogEnd; FogStart = rs.FogStart; FogTableMode = rs.FogTableMode; FogVertexMode = rs.FogVertexMode; MultiSampleAntiAlias = rs.MultiSampleAntiAlias; MultiSampleMask = rs.MultiSampleMask; PointSize = rs.PointSize; PointSizeMax = rs.PointSizeMax; PointSizeMin = rs.PointSizeMin; PointSpriteEnable = rs.PointSpriteEnable; RangeFogEnable = rs.RangeFogEnable; ReferenceAlpha = rs.ReferenceAlpha; ReferenceStencil = rs.ReferenceStencil; ScissorTestEnable = rs.ScissorTestEnable; SeparateAlphaBlendEnabled = rs.SeparateAlphaBlendEnabled; SlopeScaleDepthBias = rs.SlopeScaleDepthBias; SourceBlend = rs.SourceBlend; StencilDepthBufferFail = rs.StencilDepthBufferFail; StencilEnable = rs.StencilEnable; StencilFail = rs.StencilFail; StencilFunction = rs.StencilFunction; StencilMask = rs.StencilMask; StencilPass = rs.StencilPass; StencilWriteMask = rs.StencilWriteMask; TwoSidedStencilMode = rs.TwoSidedStencilMode; Wrap0 = rs.Wrap0; Wrap1 = rs.Wrap1; Wrap2 = rs.Wrap2; Wrap3 = rs.Wrap3; Wrap4 = rs.Wrap4; Wrap5 = rs.Wrap5; Wrap6 = rs.Wrap6; Wrap7 = rs.Wrap7; Wrap8 = rs.Wrap8; Wrap9 = rs.Wrap9; Wrap10 = rs.Wrap10; Wrap11 = rs.Wrap11; Wrap12 = rs.Wrap12; Wrap13 = rs.Wrap13; Wrap14 = rs.Wrap14; Wrap15 = rs.Wrap15; queuedSingleStates.Clear(); queuedBooleanStates.Clear(); queuedIntegerStates.Clear(); singleChangeSet.Clear(); booleanChangeSet.Clear(); integerChangeSet.Clear(); for (int i = 0; i < MaxSamplers; i++) SamplerStates[i].Reset(device.SamplerStates[i]); } internal void Commit(GraphicsDevice device) { var rs = device.RenderState; //var rsCount = queuedSingleStates.Count + queuedBooleanStates.Count + queuedIntegerStates.Count; //if (rsCount != 0) // Console.WriteLine("Commiting " + rsCount + " render state(s)"); if (queuedSingleStates.Count > 0) { foreach (var stateType in queuedSingleStates) { var stateValue = singleStates[stateType]; switch (stateType) { case 0: rs.DepthBias = stateValue; break; case 1: rs.FogDensity = stateValue; break; case 2: rs.FogEnd = stateValue; break; case 3: rs.FogStart = stateValue; break; case 4: rs.PointSize = stateValue; break; case 5: rs.PointSizeMax = stateValue; break; case 6: rs.PointSizeMin = stateValue; break; case 7: rs.SlopeScaleDepthBias = stateValue; break; } } singleChangeSet.AddRange(queuedSingleStates); queuedSingleStates.Clear(); } if (queuedBooleanStates.Count > 0) { foreach (var stateType in queuedBooleanStates) { var stateValue = booleanStates[stateType]; switch (stateType) { case 0: rs.AlphaBlendEnable = stateValue; break; case 1: rs.AlphaTestEnable = stateValue; break; case 2: rs.DepthBufferEnable = stateValue; break; case 3: rs.DepthBufferWriteEnable = stateValue; break; case 4: rs.FogEnable = stateValue; break; case 5: rs.MultiSampleAntiAlias = stateValue; break; case 6: rs.PointSpriteEnable = stateValue; break; case 7: rs.RangeFogEnable = stateValue; break; case 8: rs.ScissorTestEnable = stateValue; break; case 9: rs.SeparateAlphaBlendEnabled = stateValue; break; case 10: rs.StencilEnable = stateValue; break; case 11: rs.TwoSidedStencilMode = stateValue; break; } } booleanChangeSet.AddRange(queuedBooleanStates); queuedBooleanStates.Clear(); } if (queuedIntegerStates.Count > 0) { foreach (var stateType in queuedIntegerStates) { var stateValue = integerStates[stateType]; switch (stateType) { case 0: rs.AlphaBlendOperation = (BlendFunction)stateValue; break; case 1: rs.AlphaDestinationBlend = (Blend)stateValue; break; case 2: rs.AlphaFunction = (CompareFunction)stateValue; break; case 3: rs.AlphaSourceBlend = (Blend)stateValue; break; case 4: rs.BlendFactor = MathHelperEx.UnpackColor(stateValue); break; case 5: rs.BlendFunction = (BlendFunction)stateValue; break; case 6: rs.ColorWriteChannels = (ColorWriteChannels)stateValue; break; case 7: rs.ColorWriteChannels1 = (ColorWriteChannels)stateValue; break; case 8: rs.ColorWriteChannels2 = (ColorWriteChannels)stateValue; break; case 9: rs.ColorWriteChannels3 = (ColorWriteChannels)stateValue; break; case 10: rs.CounterClockwiseStencilDepthBufferFail = (StencilOperation)stateValue; break; case 11: rs.CounterClockwiseStencilFail = (StencilOperation)stateValue; break; case 12: rs.CounterClockwiseStencilFunction = (CompareFunction)stateValue; break; case 13: rs.CounterClockwiseStencilPass = (StencilOperation)stateValue; break; case 14: rs.CullMode = (CullMode)stateValue; break; case 15: rs.DepthBufferFunction = (CompareFunction)stateValue; break; case 16: rs.DestinationBlend = (Blend)stateValue; break; case 17: rs.FillMode = (FillMode)stateValue; break; case 18: rs.FogColor = MathHelperEx.UnpackColor(stateValue); break; case 19: rs.FogTableMode = (FogMode)stateValue; break; case 20: rs.FogVertexMode = (FogMode)stateValue; break; case 21: rs.MultiSampleMask = (int)stateValue; break; case 22: rs.ReferenceAlpha = (int)stateValue; break; case 23: rs.ReferenceStencil = (int)stateValue; break; case 24: rs.SourceBlend = (Blend)stateValue; break; case 25: rs.StencilDepthBufferFail = (StencilOperation)stateValue; break; case 26: rs.StencilFail = (StencilOperation)stateValue; break; case 27: rs.StencilFunction = (CompareFunction)stateValue; break; case 28: rs.StencilMask = (int)stateValue; break; case 29: rs.StencilPass = (StencilOperation)stateValue; break; case 30: rs.StencilWriteMask = (int)stateValue; break; case 31: rs.Wrap0 = (TextureWrapCoordinates)stateValue; break; case 32: rs.Wrap1 = (TextureWrapCoordinates)stateValue; break; case 33: rs.Wrap10 = (TextureWrapCoordinates)stateValue; break; case 34: rs.Wrap11 = (TextureWrapCoordinates)stateValue; break; case 35: rs.Wrap12 = (TextureWrapCoordinates)stateValue; break; case 36: rs.Wrap13 = (TextureWrapCoordinates)stateValue; break; case 37: rs.Wrap14 = (TextureWrapCoordinates)stateValue; break; case 38: rs.Wrap15 = (TextureWrapCoordinates)stateValue; break; case 39: rs.Wrap2 = (TextureWrapCoordinates)stateValue; break; case 40: rs.Wrap3 = (TextureWrapCoordinates)stateValue; break; case 41: rs.Wrap4 = (TextureWrapCoordinates)stateValue; break; case 42: rs.Wrap5 = (TextureWrapCoordinates)stateValue; break; case 43: rs.Wrap6 = (TextureWrapCoordinates)stateValue; break; case 44: rs.Wrap7 = (TextureWrapCoordinates)stateValue; break; case 45: rs.Wrap8 = (TextureWrapCoordinates)stateValue; break; case 46: rs.Wrap9 = (TextureWrapCoordinates)stateValue; break; } } integerChangeSet.AddRange(queuedIntegerStates); queuedIntegerStates.Clear(); } for (int i = 0; i < MaxSamplers; i++) SamplerStates[i].Commit(device.SamplerStates[i]); } public bool AlphaBlendEnable { get { return booleanStates[0]; } set { TryQueueState(queuedBooleanStates, 0, booleanStates, value); } } public bool AlphaTestEnable { get { return booleanStates[1]; } set { TryQueueState(queuedBooleanStates, 1, booleanStates, value); } } public bool DepthBufferEnable { get { return booleanStates[2]; } set { TryQueueState(queuedBooleanStates, 2, booleanStates, value); } } public bool DepthBufferWriteEnable { get { return booleanStates[3]; } set { TryQueueState(queuedBooleanStates, 3, booleanStates, value); } } public bool FogEnable { get { return booleanStates[4]; } set { TryQueueState(queuedBooleanStates, 4, booleanStates, value); } } public bool MultiSampleAntiAlias { get { return booleanStates[5]; } set { TryQueueState(queuedBooleanStates, 5, booleanStates, value); } } public bool PointSpriteEnable { get { return booleanStates[6]; } set { TryQueueState(queuedBooleanStates, 6, booleanStates, value); } } public bool RangeFogEnable { get { return booleanStates[7]; } set { TryQueueState(queuedBooleanStates, 7, booleanStates, value); } } public bool ScissorTestEnable { get { return booleanStates[8]; } set { TryQueueState(queuedBooleanStates, 8, booleanStates, value); } } public bool SeparateAlphaBlendEnabled { get { return booleanStates[9]; } set { TryQueueState(queuedBooleanStates, 9, booleanStates, value); } } public bool StencilEnable { get { return booleanStates[10]; } set { TryQueueState(queuedBooleanStates, 10, booleanStates, value); } } public bool TwoSidedStencilMode { get { return booleanStates[11]; } set { TryQueueState(queuedBooleanStates, 11, booleanStates, value); } } public float DepthBias { get { return singleStates[0]; } set { TryQueueState(queuedSingleStates, 0, singleStates, value); } } public float FogDensity { get { return singleStates[1]; } set { TryQueueState(queuedSingleStates, 1, singleStates, value); } } public float FogEnd { get { return singleStates[2]; } set { TryQueueState(queuedSingleStates, 2, singleStates, value); } } public float FogStart { get { return singleStates[3]; } set { TryQueueState(queuedSingleStates, 3, singleStates, value); } } public float PointSize { get { return singleStates[4]; } set { TryQueueState(queuedSingleStates, 4, singleStates, value); } } public float PointSizeMax { get { return singleStates[5]; } set { TryQueueState(queuedSingleStates, 5, singleStates, value); } } public float PointSizeMin { get { return singleStates[6]; } set { TryQueueState(queuedSingleStates, 6, singleStates, value); } } public float SlopeScaleDepthBias { get { return singleStates[7]; } set { TryQueueState(queuedSingleStates, 7, singleStates, value); } } public BlendFunction AlphaBlendOperation { get { return (BlendFunction)integerStates[0]; } set { TryQueueState(queuedIntegerStates, 0, integerStates, (uint)value); } } public Blend AlphaDestinationBlend { get { return (Blend)integerStates[1]; } set { TryQueueState(queuedIntegerStates, 1, integerStates, (uint)value); } } public CompareFunction AlphaFunction { get { return (CompareFunction)integerStates[2]; } set { TryQueueState(queuedIntegerStates, 2, integerStates, (uint)value); } } public Blend AlphaSourceBlend { get { return (Blend)integerStates[3]; } set { TryQueueState(queuedIntegerStates, 3, integerStates, (uint)value); } } public Color BlendFactor { get { return MathHelperEx.UnpackColor(integerStates[4]); } set { TryQueueState(queuedIntegerStates, 4, integerStates, value.PackedValue); } } public BlendFunction BlendFunction { get { return (BlendFunction)integerStates[5]; } set { TryQueueState(queuedIntegerStates, 5, integerStates, (uint)value); } } public ColorWriteChannels ColorWriteChannels { get { return (ColorWriteChannels)integerStates[6]; } set { TryQueueState(queuedIntegerStates, 6, integerStates, (uint)value); } } public ColorWriteChannels ColorWriteChannels1 { get { return (ColorWriteChannels)integerStates[7]; } set { TryQueueState(queuedIntegerStates, 7, integerStates, (uint)value); } } public ColorWriteChannels ColorWriteChannels2 { get { return (ColorWriteChannels)integerStates[8]; } set { TryQueueState(queuedIntegerStates, 8, integerStates, (uint)value); } } public ColorWriteChannels ColorWriteChannels3 { get { return (ColorWriteChannels)integerStates[9]; } set { TryQueueState(queuedIntegerStates, 9, integerStates, (uint)value); } } public StencilOperation CounterClockwiseStencilDepthBufferFail { get { return (StencilOperation)integerStates[10]; } set { TryQueueState(queuedIntegerStates, 10, integerStates, (uint)value); } } public StencilOperation CounterClockwiseStencilFail { get { return (StencilOperation)integerStates[11]; } set { TryQueueState(queuedIntegerStates, 11, integerStates, (uint)value); } } public CompareFunction CounterClockwiseStencilFunction { get { return (CompareFunction)integerStates[12]; } set { TryQueueState(queuedIntegerStates, 12, integerStates, (uint)value); } } public StencilOperation CounterClockwiseStencilPass { get { return (StencilOperation)integerStates[13]; } set { TryQueueState(queuedIntegerStates, 13, integerStates, (uint)value); } } public CullMode CullMode { get { return (CullMode)integerStates[14]; } set { TryQueueState(queuedIntegerStates, 14, integerStates, (uint)value); } } public CompareFunction DepthBufferFunction { get { return (CompareFunction)integerStates[15]; } set { TryQueueState(queuedIntegerStates, 15, integerStates, (uint)value); } } public Blend DestinationBlend { get { return (Blend)integerStates[16]; } set { TryQueueState(queuedIntegerStates, 16, integerStates, (uint)value); } } public FillMode FillMode { get { return (FillMode)integerStates[17]; } set { TryQueueState(queuedIntegerStates, 17, integerStates, (uint)value); } } public Color FogColor { get { return MathHelperEx.UnpackColor(integerStates[18]); } set { TryQueueState(queuedIntegerStates, 18, integerStates, value.PackedValue); } } public FogMode FogTableMode { get { return (FogMode)integerStates[19]; } set { TryQueueState(queuedIntegerStates, 19, integerStates, (uint)value); } } public FogMode FogVertexMode { get { return (FogMode)integerStates[20]; } set { TryQueueState(queuedIntegerStates, 20, integerStates, (uint)value); } } public int MultiSampleMask { get { return (int)integerStates[21]; } set { TryQueueState(queuedIntegerStates, 21, integerStates, (uint)value); } } public int ReferenceAlpha { get { return (int)integerStates[22]; } set { TryQueueState(queuedIntegerStates, 22, integerStates, (uint)value); } } public int ReferenceStencil { get { return (int)integerStates[23]; } set { TryQueueState(queuedIntegerStates, 23, integerStates, (uint)value); } } public Blend SourceBlend { get { return (Blend)integerStates[24]; } set { TryQueueState(queuedIntegerStates, 24, integerStates, (uint)value); } } public StencilOperation StencilDepthBufferFail { get { return (StencilOperation)integerStates[25]; } set { TryQueueState(queuedIntegerStates, 25, integerStates, (uint)value); } } public StencilOperation StencilFail { get { return (StencilOperation)integerStates[26]; } set { TryQueueState(queuedIntegerStates, 26, integerStates, (uint)value); } } public CompareFunction StencilFunction { get { return (CompareFunction)integerStates[27]; } set { TryQueueState(queuedIntegerStates, 27, integerStates, (uint)value); } } public int StencilMask { get { return (int)integerStates[28]; } set { TryQueueState(queuedIntegerStates, 28, integerStates, (uint)value); } } public StencilOperation StencilPass { get { return (StencilOperation)integerStates[29]; } set { TryQueueState(queuedIntegerStates, 29, integerStates, (uint)value); } } public int StencilWriteMask { get { return (int)integerStates[30]; } set { TryQueueState(queuedIntegerStates, 30, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap0 { get { return (TextureWrapCoordinates)integerStates[31]; } set { TryQueueState(queuedIntegerStates, 31, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap1 { get { return (TextureWrapCoordinates)integerStates[32]; } set { TryQueueState(queuedIntegerStates, 32, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap10 { get { return (TextureWrapCoordinates)integerStates[33]; } set { TryQueueState(queuedIntegerStates, 33, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap11 { get { return (TextureWrapCoordinates)integerStates[34]; } set { TryQueueState(queuedIntegerStates, 34, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap12 { get { return (TextureWrapCoordinates)integerStates[35]; } set { TryQueueState(queuedIntegerStates, 35, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap13 { get { return (TextureWrapCoordinates)integerStates[36]; } set { TryQueueState(queuedIntegerStates, 36, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap14 { get { return (TextureWrapCoordinates)integerStates[37]; } set { TryQueueState(queuedIntegerStates, 37, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap15 { get { return (TextureWrapCoordinates)integerStates[38]; } set { TryQueueState(queuedIntegerStates, 38, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap2 { get { return (TextureWrapCoordinates)integerStates[39]; } set { TryQueueState(queuedIntegerStates, 39, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap3 { get { return (TextureWrapCoordinates)integerStates[40]; } set { TryQueueState(queuedIntegerStates, 40, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap4 { get { return (TextureWrapCoordinates)integerStates[41]; } set { TryQueueState(queuedIntegerStates, 41, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap5 { get { return (TextureWrapCoordinates)integerStates[42]; } set { TryQueueState(queuedIntegerStates, 42, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap6 { get { return (TextureWrapCoordinates)integerStates[43]; } set { TryQueueState(queuedIntegerStates, 43, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap7 { get { return (TextureWrapCoordinates)integerStates[44]; } set { TryQueueState(queuedIntegerStates, 44, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap8 { get { return (TextureWrapCoordinates)integerStates[45]; } set { TryQueueState(queuedIntegerStates, 45, integerStates, (uint)value); } } public TextureWrapCoordinates Wrap9 { get { return (TextureWrapCoordinates)integerStates[46]; } set { TryQueueState(queuedIntegerStates, 46, integerStates, (uint)value); } } static void TryQueueState(ICollection queue, byte state, T[] states, T value) where T : IEquatable { if (states[state].Equals(value)) return; states[state] = value; if (!queue.Contains(state)) queue.Add(state); } public void SetBlendingMode(BlendingMode blendingMode) { switch (blendingMode) { case BlendingMode.Additive: AlphaBlendEnable = true; AlphaTestEnable = false; BlendFunction = BlendFunction.Add; SourceBlend = Blend.One; DestinationBlend = Blend.One; break; case BlendingMode.Screen: AlphaBlendEnable = true; AlphaTestEnable = false; BlendFunction = BlendFunction.Add; SourceBlend = Blend.InverseDestinationColor; DestinationBlend = Blend.One; break; case BlendingMode.Multiply: AlphaBlendEnable = true; AlphaTestEnable = false; BlendFunction = BlendFunction.Add; SourceBlend = Blend.DestinationColor; DestinationBlend = Blend.Zero; break; case BlendingMode.Multiply2X: AlphaBlendEnable = true; AlphaTestEnable = false; BlendFunction = BlendFunction.Add; SourceBlend = Blend.DestinationColor; DestinationBlend = Blend.SourceColor; break; case BlendingMode.Alphablending: AlphaBlendEnable = true; AlphaTestEnable = true; BlendFunction = BlendFunction.Add; SourceBlend = Blend.SourceAlpha; DestinationBlend = Blend.InverseSourceAlpha; break; case BlendingMode.Maximum: AlphaBlendEnable = true; AlphaTestEnable = false; BlendFunction = BlendFunction.Max; SourceBlend = Blend.One; DestinationBlend = Blend.One; break; case BlendingMode.None: AlphaBlendEnable = false; AlphaTestEnable = false; BlendFunction = BlendFunction.Add; SourceBlend = Blend.One; DestinationBlend = Blend.Zero; break; } } } public enum BlendingMode { Additive, Screen, Multiply, Alphablending, Multiply2X, Maximum, None } }