Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
File last commit:
Show/Diff file:
Action:
FNA/src/Graphics/Effect/Effect.cs
1026 lines | 38.5 KiB | text/x-csharp | CSharpLexer
#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
* Copyright 2009-2020 Ethan Lee and the MonoGame Team
*
* Released under the Microsoft Public License.
* See LICENSE for details.
*/
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
#endregion
namespace Microsoft.Xna.Framework.Graphics
{
public class Effect : GraphicsResource
{
#region Public Properties
private EffectTechnique INTERNAL_currentTechnique;
public EffectTechnique CurrentTechnique
{
get
{
return INTERNAL_currentTechnique;
}
set
{
MojoShader.MOJOSHADER_effectSetTechnique(
glEffect.EffectData,
value.TechniquePointer
);
INTERNAL_currentTechnique = value;
}
}
public EffectParameterCollection Parameters
{
get;
private set;
}
public EffectTechniqueCollection Techniques
{
get;
private set;
}
#endregion
#region Internal Variables
internal IGLEffect glEffect;
#endregion
#region Private Variables
private Dictionary<IntPtr, EffectParameter> samplerMap = new Dictionary<IntPtr, EffectParameter>(new IntPtrBoxlessComparer());
private class IntPtrBoxlessComparer : IEqualityComparer<IntPtr>
{
public bool Equals(IntPtr x, IntPtr y)
{
return x == y;
}
public int GetHashCode(IntPtr obj)
{
return obj.GetHashCode();
}
}
private IntPtr stateChangesPtr;
#endregion
#region Private Static Variables
private static readonly EffectParameterType[] XNAType = new EffectParameterType[]
{
EffectParameterType.Void, // MOJOSHADER_SYMTYPE_VOID
EffectParameterType.Bool, // MOJOSHADER_SYMTYPE_BOOL
EffectParameterType.Int32, // MOJOSHADER_SYMTYPE_INT
EffectParameterType.Single, // MOJOSHADER_SYMTYPE_FLOAT
EffectParameterType.String, // MOJOSHADER_SYMTYPE_STRING
EffectParameterType.Texture, // MOJOSHADER_SYMTYPE_TEXTURE
EffectParameterType.Texture1D, // MOJOSHADER_SYMTYPE_TEXTURE1D
EffectParameterType.Texture2D, // MOJOSHADER_SYMTYPE_TEXTURE2D
EffectParameterType.Texture3D, // MOJOSHADER_SYMTYPE_TEXTURE3D
EffectParameterType.TextureCube // MOJOSHADER_SYMTYPE_TEXTURECUBE
};
private static readonly EffectParameterClass[] XNAClass = new EffectParameterClass[]
{
EffectParameterClass.Scalar, // MOJOSHADER_SYMCLASS_SCALAR
EffectParameterClass.Vector, // MOJOSHADER_SYMCLASS_VECTOR
EffectParameterClass.Matrix, // MOJOSHADER_SYMCLASS_MATRIX_ROWS
EffectParameterClass.Matrix, // MOJOSHADER_SYMCLASS_MATRIX_COLUMNS
EffectParameterClass.Object, // MOJOSHADER_SYMCLASS_OBJECT
EffectParameterClass.Struct // MOJOSHADER_SYMCLASS_STRUCT
};
private static readonly Blend[] XNABlend = new Blend[]
{
(Blend) (-1), // NOPE
Blend.Zero, // MOJOSHADER_BLEND_ZERO
Blend.One, // MOJOSHADER_BLEND_ONE
Blend.SourceColor, // MOJOSHADER_BLEND_SRCCOLOR
Blend.InverseSourceColor, // MOJOSHADER_BLEND_INVSRCCOLOR
Blend.SourceAlpha, // MOJOSHADER_BLEND_SRCALPHA
Blend.InverseSourceAlpha, // MOJOSHADER_BLEND_INVSRCALPHA
Blend.DestinationAlpha, // MOJOSHADER_BLEND_DESTALPHA
Blend.InverseDestinationAlpha, // MOJOSHADER_BLEND_INVDESTALPHA
Blend.DestinationColor, // MOJOSHADER_BLEND_DESTCOLOR
Blend.InverseDestinationColor, // MOJOSHADER_BLEND_INVDESTCOLOR
Blend.SourceAlphaSaturation, // MOJOSHADER_BLEND_SRCALPHASAT
(Blend) (-1), // NOPE
(Blend) (-1), // NOPE
Blend.BlendFactor, // MOJOSHADER_BLEND_BLENDFACTOR
Blend.InverseBlendFactor // MOJOSHADER_BLEND_INVBLENDFACTOR
};
private static readonly BlendFunction[] XNABlendOp = new BlendFunction[]
{
(BlendFunction) (-1), // NOPE
BlendFunction.Add, // MOJOSHADER_BLENDOP_ADD
BlendFunction.Subtract, // MOJOSHADER_BLENDOP_SUBTRACT
BlendFunction.ReverseSubtract, // MOJOSHADER_BLENDOP_REVSUBTRACT
BlendFunction.Min, // MOJOSHADER_BLENDOP_MIN
BlendFunction.Max // MOJOSHADER_BLENDOP_MAX
};
private static readonly CompareFunction[] XNACompare = new CompareFunction[]
{
(CompareFunction) (-1), // NOPE
CompareFunction.Never, // MOJOSHADER_CMP_NEVER
CompareFunction.Less, // MOJOSHADER_CMP_LESS
CompareFunction.Equal, // MOJOSHADER_CMP_EQUAL
CompareFunction.LessEqual, // MOJOSHADER_CMP_LESSEQUAL
CompareFunction.Greater, // MOJOSHADER_CMP_GREATER
CompareFunction.NotEqual, // MOJOSHADER_CMP_NOTEQUAL
CompareFunction.GreaterEqual, // MOJOSHADER_CMP_GREATEREQUAL
CompareFunction.Always // MOJOSHADER_CMP_ALWAYS
};
private static readonly StencilOperation[] XNAStencilOp = new StencilOperation[]
{
(StencilOperation) (-1), // NOPE
StencilOperation.Keep, // MOJOSHADER_STENCILOP_KEEP
StencilOperation.Zero, // MOJOSHADER_STENCILOP_ZERO
StencilOperation.Replace, // MOJOSHADER_STENCILOP_REPLACE
StencilOperation.IncrementSaturation, // MOJOSHADER_STENCILOP_INCRSAT
StencilOperation.DecrementSaturation, // MOJOSHADER_STENCILOP_DECRSAT
StencilOperation.Invert, // MOJOSHADER_STENCILOP_INVERT
StencilOperation.Increment, // MOJOSHADER_STENCILOP_INCR
StencilOperation.Decrement // MOJOSHADER_STENCILOP_DECR
};
private static readonly TextureAddressMode[] XNAAddress = new TextureAddressMode[]
{
(TextureAddressMode) (-1), // NOPE
TextureAddressMode.Wrap, // MOJOSHADER_TADDRESS_WRAP
TextureAddressMode.Mirror, // MOJOSHADER_TADDRESS_MIRROR
TextureAddressMode.Clamp // MOJOSHADER_TADDRESS_CLAMP
};
private static readonly MojoShader.MOJOSHADER_textureFilterType[] XNAMag =
new MojoShader.MOJOSHADER_textureFilterType[]
{
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.Linear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.Point
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, // TextureFilter.Anisotropic
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.LinearMipPoint
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.PointMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinLinearMagPointMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinLinearMagPointMipPoint
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinPointMagLinearMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR // TextureFilter.MinPointMagLinearMipPoint
};
private static readonly MojoShader.MOJOSHADER_textureFilterType[] XNAMin =
new MojoShader.MOJOSHADER_textureFilterType[]
{
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.Linear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.Point
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, // TextureFilter.Anisotropic
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.LinearMipPoint
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.PointMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinLinearMagPointMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinLinearMagPointMipPoint
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinPointMagLinearMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT // TextureFilter.MinPointMagLinearMipPoint
};
private static readonly MojoShader.MOJOSHADER_textureFilterType[] XNAMip =
new MojoShader.MOJOSHADER_textureFilterType[]
{
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.Linear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.Point
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, // TextureFilter.Anisotropic
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.LinearMipPoint
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.PointMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinLinearMagPointMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinLinearMagPointMipPoint
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinPointMagLinearMipLinear
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT // TextureFilter.MinPointMagLinearMipPoint
};
#endregion
#region Public Constructor
public Effect(GraphicsDevice graphicsDevice, byte[] effectCode)
{
GraphicsDevice = graphicsDevice;
// Send the blob to the GLDevice to be parsed/compiled
glEffect = graphicsDevice.GLDevice.CreateEffect(effectCode);
// This is where it gets ugly...
INTERNAL_parseEffectStruct();
// The default technique is the first technique.
CurrentTechnique = Techniques[0];
// Use native memory for changes, .NET loves moving this around
unsafe
{
stateChangesPtr = Marshal.AllocHGlobal(
sizeof(MojoShader.MOJOSHADER_effectStateChanges)
);
MojoShader.MOJOSHADER_effectStateChanges *stateChanges =
(MojoShader.MOJOSHADER_effectStateChanges*) stateChangesPtr;
stateChanges->render_state_change_count = 0;
stateChanges->sampler_state_change_count = 0;
stateChanges->vertex_sampler_state_change_count = 0;
}
}
#endregion
#region Protected Constructor
protected Effect(Effect cloneSource)
{
GraphicsDevice = cloneSource.GraphicsDevice;
// Send the parsed data to be cloned and recompiled by MojoShader
glEffect = GraphicsDevice.GLDevice.CloneEffect(
cloneSource.glEffect
);
// Double the ugly, double the fun!
INTERNAL_parseEffectStruct();
// Copy texture parameters, if applicable
for (int i = 0; i < cloneSource.Parameters.Count; i += 1)
{
Parameters[i].texture = cloneSource.Parameters[i].texture;
}
// The default technique is whatever the current technique was.
for (int i = 0; i < cloneSource.Techniques.Count; i += 1)
{
if (cloneSource.Techniques[i] == cloneSource.CurrentTechnique)
{
CurrentTechnique = Techniques[i];
}
}
// Use native memory for changes, .NET loves moving this around
unsafe
{
stateChangesPtr = Marshal.AllocHGlobal(
sizeof(MojoShader.MOJOSHADER_effectStateChanges)
);
MojoShader.MOJOSHADER_effectStateChanges *stateChanges =
(MojoShader.MOJOSHADER_effectStateChanges*) stateChangesPtr;
stateChanges->render_state_change_count = 0;
stateChanges->sampler_state_change_count = 0;
stateChanges->vertex_sampler_state_change_count = 0;
}
}
#endregion
#region Public Methods
public virtual Effect Clone()
{
return new Effect(this);
}
#endregion
#region Protected Methods
protected override void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (glEffect != null)
{
GraphicsDevice.GLDevice.AddDisposeEffect(glEffect);
}
if (stateChangesPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(stateChangesPtr);
stateChangesPtr = IntPtr.Zero;
}
}
base.Dispose(disposing);
}
protected internal virtual void OnApply()
{
}
#endregion
#region Internal Methods
internal unsafe void INTERNAL_applyEffect(uint pass)
{
GraphicsDevice.GLDevice.ApplyEffect(
glEffect,
CurrentTechnique.TechniquePointer,
pass,
stateChangesPtr
);
MojoShader.MOJOSHADER_effectStateChanges *stateChanges =
(MojoShader.MOJOSHADER_effectStateChanges*) stateChangesPtr;
if (stateChanges->render_state_change_count > 0)
{
PipelineCache pipelineCache = GraphicsDevice.PipelineCache;
pipelineCache.BeginApplyBlend();
pipelineCache.BeginApplyDepthStencil();
pipelineCache.BeginApplyRasterizer();
// Used to avoid redundant device state application
bool blendStateChanged = false;
bool depthStencilStateChanged = false;
bool rasterizerStateChanged = false;
MojoShader.MOJOSHADER_effectState* states = (MojoShader.MOJOSHADER_effectState*) stateChanges->render_state_changes;
for (int i = 0; i < stateChanges->render_state_change_count; i += 1)
{
MojoShader.MOJOSHADER_renderStateType type = states[i].type;
if ( type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_VERTEXSHADER ||
type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_PIXELSHADER )
{
// Skip shader states
continue;
}
if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ZENABLE)
{
MojoShader.MOJOSHADER_zBufferType* val = (MojoShader.MOJOSHADER_zBufferType*) states[i].value.values;
pipelineCache.DepthBufferEnable =
(*val == MojoShader.MOJOSHADER_zBufferType.MOJOSHADER_ZB_TRUE);
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_FILLMODE)
{
MojoShader.MOJOSHADER_fillMode* val = (MojoShader.MOJOSHADER_fillMode*) states[i].value.values;
if (*val == MojoShader.MOJOSHADER_fillMode.MOJOSHADER_FILL_SOLID)
{
pipelineCache.FillMode = FillMode.Solid;
}
else if (*val == MojoShader.MOJOSHADER_fillMode.MOJOSHADER_FILL_WIREFRAME)
{
pipelineCache.FillMode = FillMode.WireFrame;
}
rasterizerStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ZWRITEENABLE)
{
int* val = (int*) states[i].value.values;
pipelineCache.DepthBufferWriteEnable = (*val == 1);
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SRCBLEND)
{
MojoShader.MOJOSHADER_blendMode* val = (MojoShader.MOJOSHADER_blendMode*) states[i].value.values;
pipelineCache.ColorSourceBlend = XNABlend[(int) *val];
if (!pipelineCache.SeparateAlphaBlend)
{
pipelineCache.AlphaSourceBlend = XNABlend[(int) *val];
}
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_DESTBLEND)
{
MojoShader.MOJOSHADER_blendMode* val = (MojoShader.MOJOSHADER_blendMode*) states[i].value.values;
pipelineCache.ColorDestinationBlend = XNABlend[(int) *val];
if (!pipelineCache.SeparateAlphaBlend)
{
pipelineCache.AlphaDestinationBlend = XNABlend[(int) *val];
}
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_CULLMODE)
{
MojoShader.MOJOSHADER_cullMode* val = (MojoShader.MOJOSHADER_cullMode*) states[i].value.values;
if (*val == MojoShader.MOJOSHADER_cullMode.MOJOSHADER_CULL_NONE)
{
pipelineCache.CullMode = CullMode.None;
}
else if (*val == MojoShader.MOJOSHADER_cullMode.MOJOSHADER_CULL_CW)
{
pipelineCache.CullMode = CullMode.CullClockwiseFace;
}
else if (*val == MojoShader.MOJOSHADER_cullMode.MOJOSHADER_CULL_CCW)
{
pipelineCache.CullMode = CullMode.CullCounterClockwiseFace;
}
rasterizerStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ZFUNC)
{
MojoShader.MOJOSHADER_compareFunc* val = (MojoShader.MOJOSHADER_compareFunc*) states[i].value.values;
pipelineCache.DepthBufferFunction = XNACompare[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ALPHABLENDENABLE)
{
// FIXME: Assuming no other blend calls are made in the effect! -flibit
int* val = (int*) states[i].value.values;
if (*val == 0)
{
pipelineCache.ColorSourceBlend = Blend.One;
pipelineCache.ColorDestinationBlend = Blend.Zero;
pipelineCache.AlphaSourceBlend = Blend.One;
pipelineCache.AlphaDestinationBlend = Blend.Zero;
blendStateChanged = true;
}
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILENABLE)
{
int* val = (int*) states[i].value.values;
pipelineCache.StencilEnable = (*val == 1);
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILFAIL)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
pipelineCache.StencilFail = XNAStencilOp[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILZFAIL)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
pipelineCache.StencilDepthBufferFail = XNAStencilOp[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILPASS)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
pipelineCache.StencilPass = XNAStencilOp[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILFUNC)
{
MojoShader.MOJOSHADER_compareFunc* val = (MojoShader.MOJOSHADER_compareFunc*) states[i].value.values;
pipelineCache.StencilFunction = XNACompare[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILREF)
{
int* val = (int*) states[i].value.values;
pipelineCache.ReferenceStencil = *val;
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILMASK)
{
int* val = (int*) states[i].value.values;
pipelineCache.StencilMask = *val;
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILWRITEMASK)
{
int* val = (int*) states[i].value.values;
pipelineCache.StencilWriteMask = *val;
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_MULTISAMPLEANTIALIAS)
{
int* val = (int*) states[i].value.values;
pipelineCache.MultiSampleAntiAlias = (*val == 1);
rasterizerStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_MULTISAMPLEMASK)
{
int* val = (int*) states[i].value.values;
pipelineCache.MultiSampleMask = *val;
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE)
{
int* val = (int*) states[i].value.values;
pipelineCache.ColorWriteChannels = (ColorWriteChannels) (*val);
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_BLENDOP)
{
MojoShader.MOJOSHADER_blendOp* val = (MojoShader.MOJOSHADER_blendOp*) states[i].value.values;
pipelineCache.ColorBlendFunction = XNABlendOp[(int) *val];
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SCISSORTESTENABLE)
{
int* val = (int*) states[i].value.values;
pipelineCache.ScissorTestEnable = (*val == 1);
rasterizerStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SLOPESCALEDEPTHBIAS)
{
float* val = (float*) states[i].value.values;
pipelineCache.SlopeScaleDepthBias = *val;
rasterizerStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_TWOSIDEDSTENCILMODE)
{
int* val = (int*) states[i].value.values;
pipelineCache.TwoSidedStencilMode = (*val == 1);
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILFAIL)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
pipelineCache.CCWStencilFail = XNAStencilOp[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILZFAIL)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
pipelineCache.CCWStencilDepthBufferFail = XNAStencilOp[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILPASS)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
pipelineCache.CCWStencilPass = XNAStencilOp[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILFUNC)
{
MojoShader.MOJOSHADER_compareFunc* val = (MojoShader.MOJOSHADER_compareFunc*) states[i].value.values;
pipelineCache.CCWStencilFunction = XNACompare[(int) *val];
depthStencilStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE1)
{
int* val = (int*) states[i].value.values;
pipelineCache.ColorWriteChannels1 = (ColorWriteChannels) (*val);
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE2)
{
int* val = (int*) states[i].value.values;
pipelineCache.ColorWriteChannels2 = (ColorWriteChannels) (*val);
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE3)
{
int* val = (int*) states[i].value.values;
pipelineCache.ColorWriteChannels3 = (ColorWriteChannels) (*val);
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_BLENDFACTOR)
{
// FIXME: RGBA? -flibit
int* val = (int*) states[i].value.values;
pipelineCache.BlendFactor = new Color(
(*val >> 24) & 0xFF,
(*val >> 16) & 0xFF,
(*val >> 8) & 0xFF,
*val & 0xFF
);
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_DEPTHBIAS)
{
float* val = (float*) states[i].value.values;
pipelineCache.DepthBias = *val;
rasterizerStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SEPARATEALPHABLENDENABLE)
{
int* val = (int*) states[i].value.values;
pipelineCache.SeparateAlphaBlend = (*val == 1);
// FIXME: Do we want to update the state for this...? -flibit
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SRCBLENDALPHA)
{
MojoShader.MOJOSHADER_blendMode* val = (MojoShader.MOJOSHADER_blendMode*) states[i].value.values;
pipelineCache.AlphaSourceBlend = XNABlend[(int) *val];
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_DESTBLENDALPHA)
{
MojoShader.MOJOSHADER_blendMode* val = (MojoShader.MOJOSHADER_blendMode*) states[i].value.values;
pipelineCache.AlphaDestinationBlend = XNABlend[(int) *val];
blendStateChanged = true;
}
else if (type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_BLENDOPALPHA)
{
MojoShader.MOJOSHADER_blendOp* val = (MojoShader.MOJOSHADER_blendOp*) states[i].value.values;
pipelineCache.AlphaBlendFunction = XNABlendOp[(int) *val];
blendStateChanged = true;
}
else if (type == (MojoShader.MOJOSHADER_renderStateType) 178)
{
/* Apparently this is "SetSampler"? */
}
else
{
throw new NotImplementedException("Unhandled render state! " + type);
}
}
if (blendStateChanged)
{
pipelineCache.EndApplyBlend();
}
if (depthStencilStateChanged)
{
pipelineCache.EndApplyDepthStencil();
}
if (rasterizerStateChanged)
{
pipelineCache.EndApplyRasterizer();
}
}
if (stateChanges->sampler_state_change_count > 0)
{
INTERNAL_updateSamplers(
stateChanges->sampler_state_change_count,
(MojoShader.MOJOSHADER_samplerStateRegister*) stateChanges->sampler_state_changes,
GraphicsDevice.Textures,
GraphicsDevice.SamplerStates
);
}
if (stateChanges->vertex_sampler_state_change_count > 0)
{
INTERNAL_updateSamplers(
stateChanges->vertex_sampler_state_change_count,
(MojoShader.MOJOSHADER_samplerStateRegister*) stateChanges->vertex_sampler_state_changes,
GraphicsDevice.VertexTextures,
GraphicsDevice.VertexSamplerStates
);
}
}
private unsafe void INTERNAL_updateSamplers(
uint changeCount,
MojoShader.MOJOSHADER_samplerStateRegister* registers,
TextureCollection textures,
SamplerStateCollection samplers
) {
for (int i = 0; i < changeCount; i += 1)
{
if (registers[i].sampler_state_count == 0)
{
// Nothing to do
continue;
}
int register = (int) registers[i].sampler_register;
PipelineCache pipelineCache = GraphicsDevice.PipelineCache;
pipelineCache.BeginApplySampler(samplers, register);
// Used to prevent redundant sampler changes
bool samplerChanged = false;
bool filterChanged = false;
// Current sampler filter
TextureFilter filter = pipelineCache.Filter;
MojoShader.MOJOSHADER_textureFilterType magFilter = XNAMag[(int) filter];
MojoShader.MOJOSHADER_textureFilterType minFilter = XNAMin[(int) filter];
MojoShader.MOJOSHADER_textureFilterType mipFilter = XNAMip[(int) filter];
MojoShader.MOJOSHADER_effectSamplerState* states = (MojoShader.MOJOSHADER_effectSamplerState*) registers[i].sampler_states;
for (int j = 0; j < registers[i].sampler_state_count; j += 1)
{
MojoShader.MOJOSHADER_samplerStateType type = states[j].type;
if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_TEXTURE)
{
EffectParameter texParam;
if (samplerMap.TryGetValue(registers[i].sampler_name, out texParam))
{
Texture texture = texParam.texture;
if (texture != null)
{
textures[register] = texture;
}
}
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_ADDRESSU)
{
MojoShader.MOJOSHADER_textureAddress* val = (MojoShader.MOJOSHADER_textureAddress*) states[j].value.values;
pipelineCache.AddressU = XNAAddress[(int) *val];
samplerChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_ADDRESSV)
{
MojoShader.MOJOSHADER_textureAddress* val = (MojoShader.MOJOSHADER_textureAddress*) states[j].value.values;
pipelineCache.AddressV = XNAAddress[(int) *val];
samplerChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_ADDRESSW)
{
MojoShader.MOJOSHADER_textureAddress* val = (MojoShader.MOJOSHADER_textureAddress*) states[j].value.values;
pipelineCache.AddressW = XNAAddress[(int) *val];
samplerChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAGFILTER)
{
MojoShader.MOJOSHADER_textureFilterType* val = (MojoShader.MOJOSHADER_textureFilterType*) states[j].value.values;
magFilter = *val;
filterChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MINFILTER)
{
MojoShader.MOJOSHADER_textureFilterType* val = (MojoShader.MOJOSHADER_textureFilterType*) states[j].value.values;
minFilter = *val;
filterChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MIPFILTER)
{
MojoShader.MOJOSHADER_textureFilterType* val = (MojoShader.MOJOSHADER_textureFilterType*) states[j].value.values;
mipFilter = *val;
filterChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MIPMAPLODBIAS)
{
float* val = (float*) states[j].value.values;
pipelineCache.MipMapLODBias = *val;
samplerChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAXMIPLEVEL)
{
int* val = (int*) states[j].value.values;
pipelineCache.MaxMipLevel = *val;
samplerChanged = true;
}
else if (type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAXANISOTROPY)
{
int* val = (int*) states[j].value.values;
pipelineCache.MaxAnisotropy = *val;
samplerChanged = true;
}
else
{
throw new NotImplementedException("Unhandled sampler state! " + type);
}
}
if (filterChanged)
{
if (magFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT)
{
if (minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT)
{
if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
pipelineCache.Filter = TextureFilter.Point;
}
else if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
pipelineCache.Filter = TextureFilter.PointMipLinear;
}
else
{
throw new NotImplementedException("Unhandled mipfilter type! " + mipFilter);
}
}
else if ( minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
pipelineCache.Filter = TextureFilter.MinLinearMagPointMipPoint;
}
else if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
pipelineCache.Filter = TextureFilter.MinLinearMagPointMipLinear;
}
else
{
throw new NotImplementedException("Unhandled mipfilter type! " + mipFilter);
}
}
else
{
throw new NotImplementedException("Unhandled minfilter type! " + minFilter);
}
}
else if ( magFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
magFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
if (minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT)
{
if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
pipelineCache.Filter = TextureFilter.MinPointMagLinearMipPoint;
}
else if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
pipelineCache.Filter = TextureFilter.MinPointMagLinearMipLinear;
}
else
{
throw new NotImplementedException("Unhandled mipfilter type! " + mipFilter);
}
}
else if ( minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
pipelineCache.Filter = TextureFilter.LinearMipPoint;
}
else if ( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
pipelineCache.Filter = TextureFilter.Linear;
}
else
{
throw new NotImplementedException("Unhandled mipfilter type! " + mipFilter);
}
}
else
{
throw new NotImplementedException("Unhandled minfilter type! " + minFilter);
}
}
else
{
throw new NotImplementedException("Unhandled magfilter type! " + magFilter);
}
samplerChanged = true;
}
if (samplerChanged)
{
pipelineCache.EndApplySampler(samplers, register);
}
}
}
#endregion
#region Private Methods
private unsafe void INTERNAL_parseEffectStruct()
{
MojoShader.MOJOSHADER_effect* effectPtr = (MojoShader.MOJOSHADER_effect*) glEffect.EffectData;
// Set up Parameters
MojoShader.MOJOSHADER_effectParam* paramPtr = (MojoShader.MOJOSHADER_effectParam*) effectPtr->parameters;
List<EffectParameter> parameters = new List<EffectParameter>();
for (int i = 0; i < effectPtr->param_count; i += 1)
{
MojoShader.MOJOSHADER_effectParam param = paramPtr[i];
if ( param.value.type.parameter_type == MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_VERTEXSHADER ||
param.value.type.parameter_type == MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_PIXELSHADER )
{
// Skip shader objects...
continue;
}
else if ( param.value.type.parameter_type >= MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_SAMPLER &&
param.value.type.parameter_type <= MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_SAMPLERCUBE )
{
string textureName = String.Empty;
MojoShader.MOJOSHADER_effectSamplerState* states = (MojoShader.MOJOSHADER_effectSamplerState*) param.value.values;
for (int j = 0; j < param.value.value_count; j += 1)
{
if ( states[j].value.type.parameter_type >= MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_TEXTURE &&
states[j].value.type.parameter_type <= MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_TEXTURECUBE )
{
MojoShader.MOJOSHADER_effectObject *objectPtr = (MojoShader.MOJOSHADER_effectObject*) effectPtr->objects;
int* index = (int*) states[j].value.values;
textureName = Marshal.PtrToStringAnsi(objectPtr[*index].mapping.name);
break;
}
}
/* Because textures have to be declared before the sampler,
* we can assume that it will always be in the list by the
* time we get to this point.
* -flibit
*/
for (int j = 0; j < parameters.Count; j += 1)
{
if (textureName.Equals(parameters[j].Name))
{
samplerMap[param.value.name] = parameters[j];
break;
}
}
continue;
}
EffectParameterCollection structMembers = null;
if (param.value.type.member_count > 0)
{
List<EffectParameter> memList = new List<EffectParameter>();
unsafe
{
MojoShader.MOJOSHADER_symbolStructMember* mem = (MojoShader.MOJOSHADER_symbolStructMember*) param.value.type.members;
IntPtr curOffset = IntPtr.Zero;
for (int j = 0; j < param.value.type.member_count; j += 1)
{
uint memSize = mem[j].info.rows * mem[j].info.columns;
if (mem[j].info.elements > 0)
{
memSize *= mem[j].info.elements;
}
memList.Add(new EffectParameter(
Marshal.PtrToStringAnsi(mem[j].name),
null,
(int) mem[j].info.rows,
(int) mem[j].info.columns,
(int) mem[j].info.elements,
XNAClass[(int) mem[j].info.parameter_class],
XNAType[(int) mem[j].info.parameter_type],
null, // FIXME: Nested structs! -flibit
null,
param.value.values + curOffset.ToInt32(),
memSize * 4
));
curOffset += (int) memSize * 4;
}
}
structMembers = new EffectParameterCollection(memList);
}
parameters.Add(new EffectParameter(
Marshal.PtrToStringAnsi(param.value.name),
Marshal.PtrToStringAnsi(param.value.semantic),
(int) param.value.type.rows,
(int) param.value.type.columns,
(int) param.value.type.elements,
XNAClass[(int) param.value.type.parameter_class],
XNAType[(int) param.value.type.parameter_type],
structMembers,
INTERNAL_readAnnotations(
param.annotations,
param.annotation_count
),
param.value.values,
param.value.value_count * sizeof(float)
));
}
Parameters = new EffectParameterCollection(parameters);
// Set up Techniques
MojoShader.MOJOSHADER_effectTechnique* techPtr = (MojoShader.MOJOSHADER_effectTechnique*) effectPtr->techniques;
List<EffectTechnique> techniques = new List<EffectTechnique>(effectPtr->technique_count);
for (int i = 0; i < techniques.Capacity; i += 1, techPtr += 1)
{
// Set up Passes
MojoShader.MOJOSHADER_effectPass* passPtr = (MojoShader.MOJOSHADER_effectPass*) techPtr->passes;
List<EffectPass> passes = new List<EffectPass>((int) techPtr->pass_count);
for (int j = 0; j < passes.Capacity; j += 1)
{
MojoShader.MOJOSHADER_effectPass pass = passPtr[j];
passes.Add(new EffectPass(
Marshal.PtrToStringAnsi(pass.name),
INTERNAL_readAnnotations(
pass.annotations,
pass.annotation_count
),
this,
(IntPtr) techPtr,
(uint) j
));
}
techniques.Add(new EffectTechnique(
Marshal.PtrToStringAnsi(techPtr->name),
(IntPtr) techPtr,
new EffectPassCollection(passes),
INTERNAL_readAnnotations(
techPtr->annotations,
techPtr->annotation_count
)
));
}
Techniques = new EffectTechniqueCollection(techniques);
}
private unsafe EffectAnnotationCollection INTERNAL_readAnnotations(
IntPtr rawAnnotations,
uint numAnnotations
) {
MojoShader.MOJOSHADER_effectAnnotation* annoPtr = (MojoShader.MOJOSHADER_effectAnnotation*) rawAnnotations;
List<EffectAnnotation> annotations = new List<EffectAnnotation>((int) numAnnotations);
for (int i = 0; i < numAnnotations; i += 1)
{
MojoShader.MOJOSHADER_effectAnnotation anno = annoPtr[i];
annotations.Add(new EffectAnnotation(
Marshal.PtrToStringAnsi(anno.name),
Marshal.PtrToStringAnsi(anno.semantic),
(int) anno.type.rows,
(int) anno.type.columns,
XNAClass[(int) anno.type.parameter_class],
XNAType[(int) anno.type.parameter_type],
anno.values
));
}
return new EffectAnnotationCollection(annotations);
}
#endregion
}
}