#region License /* FNA - XNA4 Reimplementation for Desktop Platforms * Copyright 2009-2022 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 { FNA3D.FNA3D_SetEffectTechnique( GraphicsDevice.GLDevice, glEffect, value.TechniquePointer ); INTERNAL_currentTechnique = value; } } public EffectParameterCollection Parameters { get; private set; } public EffectTechniqueCollection Techniques { get; private set; } #endregion #region Internal FNA3D Variables internal IntPtr glEffect; #endregion #region Private Variables private Dictionary samplerMap = new Dictionary(new IntPtrBoxlessComparer()); private class IntPtrBoxlessComparer : IEqualityComparer { 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_textureFilterType[] XNAMag = new MOJOSHADER_textureFilterType[] { MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.Linear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.Point MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, // TextureFilter.Anisotropic MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.LinearMipPoint MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.PointMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinLinearMagPointMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinLinearMagPointMipPoint MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinPointMagLinearMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR // TextureFilter.MinPointMagLinearMipPoint }; private static readonly MOJOSHADER_textureFilterType[] XNAMin = new MOJOSHADER_textureFilterType[] { MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.Linear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.Point MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, // TextureFilter.Anisotropic MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.LinearMipPoint MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.PointMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinLinearMagPointMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinLinearMagPointMipPoint MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinPointMagLinearMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT // TextureFilter.MinPointMagLinearMipPoint }; private static readonly MOJOSHADER_textureFilterType[] XNAMip = new MOJOSHADER_textureFilterType[] { MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.Linear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.Point MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, // TextureFilter.Anisotropic MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.LinearMipPoint MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.PointMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinLinearMagPointMipLinear MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT, // TextureFilter.MinLinearMagPointMipPoint MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR, // TextureFilter.MinPointMagLinearMipLinear 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 IntPtr effectData; FNA3D.FNA3D_CreateEffect( graphicsDevice.GLDevice, effectCode, effectCode.Length, out glEffect, out effectData ); // This is where it gets ugly... INTERNAL_parseEffectStruct(effectData); // 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_effectStateChanges) ); MOJOSHADER_effectStateChanges *stateChanges = (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 IntPtr effectData; FNA3D.FNA3D_CloneEffect( GraphicsDevice.GLDevice, cloneSource.glEffect, out glEffect, out effectData ); // Double the ugly, double the fun! INTERNAL_parseEffectStruct(effectData); // 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_effectStateChanges) ); MOJOSHADER_effectStateChanges *stateChanges = (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 != IntPtr.Zero) { FNA3D.FNA3D_AddDisposeEffect( GraphicsDevice.GLDevice, 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) { FNA3D.FNA3D_ApplyEffect( GraphicsDevice.GLDevice, glEffect, pass, stateChangesPtr ); MOJOSHADER_effectStateChanges *stateChanges = (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_effectState* states = (MOJOSHADER_effectState*) stateChanges->render_state_changes; for (int i = 0; i < stateChanges->render_state_change_count; i += 1) { MOJOSHADER_renderStateType type = states[i].type; if ( type == MOJOSHADER_renderStateType.MOJOSHADER_RS_VERTEXSHADER || type == MOJOSHADER_renderStateType.MOJOSHADER_RS_PIXELSHADER ) { // Skip shader states continue; } if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_ZENABLE) { MOJOSHADER_zBufferType* val = (MOJOSHADER_zBufferType*) states[i].value.values; pipelineCache.DepthBufferEnable = (*val == MOJOSHADER_zBufferType.MOJOSHADER_ZB_TRUE); depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_FILLMODE) { MOJOSHADER_fillMode* val = (MOJOSHADER_fillMode*) states[i].value.values; if (*val == MOJOSHADER_fillMode.MOJOSHADER_FILL_SOLID) { pipelineCache.FillMode = FillMode.Solid; } else if (*val == MOJOSHADER_fillMode.MOJOSHADER_FILL_WIREFRAME) { pipelineCache.FillMode = FillMode.WireFrame; } rasterizerStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_ZWRITEENABLE) { int* val = (int*) states[i].value.values; pipelineCache.DepthBufferWriteEnable = (*val == 1); depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_SRCBLEND) { MOJOSHADER_blendMode* val = (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_renderStateType.MOJOSHADER_RS_DESTBLEND) { MOJOSHADER_blendMode* val = (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_renderStateType.MOJOSHADER_RS_CULLMODE) { MOJOSHADER_cullMode* val = (MOJOSHADER_cullMode*) states[i].value.values; if (*val == MOJOSHADER_cullMode.MOJOSHADER_CULL_NONE) { pipelineCache.CullMode = CullMode.None; } else if (*val == MOJOSHADER_cullMode.MOJOSHADER_CULL_CW) { pipelineCache.CullMode = CullMode.CullClockwiseFace; } else if (*val == MOJOSHADER_cullMode.MOJOSHADER_CULL_CCW) { pipelineCache.CullMode = CullMode.CullCounterClockwiseFace; } rasterizerStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_ZFUNC) { MOJOSHADER_compareFunc* val = (MOJOSHADER_compareFunc*) states[i].value.values; pipelineCache.DepthBufferFunction = XNACompare[(int) *val]; depthStencilStateChanged = true; } else if (type == 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_renderStateType.MOJOSHADER_RS_STENCILENABLE) { int* val = (int*) states[i].value.values; pipelineCache.StencilEnable = (*val == 1); depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILFAIL) { MOJOSHADER_stencilOp* val = (MOJOSHADER_stencilOp*) states[i].value.values; pipelineCache.StencilFail = XNAStencilOp[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILZFAIL) { MOJOSHADER_stencilOp* val = (MOJOSHADER_stencilOp*) states[i].value.values; pipelineCache.StencilDepthBufferFail = XNAStencilOp[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILPASS) { MOJOSHADER_stencilOp* val = (MOJOSHADER_stencilOp*) states[i].value.values; pipelineCache.StencilPass = XNAStencilOp[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILFUNC) { MOJOSHADER_compareFunc* val = (MOJOSHADER_compareFunc*) states[i].value.values; pipelineCache.StencilFunction = XNACompare[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILREF) { int* val = (int*) states[i].value.values; pipelineCache.ReferenceStencil = *val; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILMASK) { int* val = (int*) states[i].value.values; pipelineCache.StencilMask = *val; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILWRITEMASK) { int* val = (int*) states[i].value.values; pipelineCache.StencilWriteMask = *val; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_MULTISAMPLEANTIALIAS) { int* val = (int*) states[i].value.values; pipelineCache.MultiSampleAntiAlias = (*val == 1); rasterizerStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_MULTISAMPLEMASK) { int* val = (int*) states[i].value.values; pipelineCache.MultiSampleMask = *val; blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE) { int* val = (int*) states[i].value.values; pipelineCache.ColorWriteChannels = (ColorWriteChannels) (*val); blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_BLENDOP) { MOJOSHADER_blendOp* val = (MOJOSHADER_blendOp*) states[i].value.values; pipelineCache.ColorBlendFunction = XNABlendOp[(int) *val]; blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_SCISSORTESTENABLE) { int* val = (int*) states[i].value.values; pipelineCache.ScissorTestEnable = (*val == 1); rasterizerStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_SLOPESCALEDEPTHBIAS) { float* val = (float*) states[i].value.values; pipelineCache.SlopeScaleDepthBias = *val; rasterizerStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_TWOSIDEDSTENCILMODE) { int* val = (int*) states[i].value.values; pipelineCache.TwoSidedStencilMode = (*val == 1); depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILFAIL) { MOJOSHADER_stencilOp* val = (MOJOSHADER_stencilOp*) states[i].value.values; pipelineCache.CCWStencilFail = XNAStencilOp[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILZFAIL) { MOJOSHADER_stencilOp* val = (MOJOSHADER_stencilOp*) states[i].value.values; pipelineCache.CCWStencilDepthBufferFail = XNAStencilOp[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILPASS) { MOJOSHADER_stencilOp* val = (MOJOSHADER_stencilOp*) states[i].value.values; pipelineCache.CCWStencilPass = XNAStencilOp[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILFUNC) { MOJOSHADER_compareFunc* val = (MOJOSHADER_compareFunc*) states[i].value.values; pipelineCache.CCWStencilFunction = XNACompare[(int) *val]; depthStencilStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE1) { int* val = (int*) states[i].value.values; pipelineCache.ColorWriteChannels1 = (ColorWriteChannels) (*val); blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE2) { int* val = (int*) states[i].value.values; pipelineCache.ColorWriteChannels2 = (ColorWriteChannels) (*val); blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE3) { int* val = (int*) states[i].value.values; pipelineCache.ColorWriteChannels3 = (ColorWriteChannels) (*val); blendStateChanged = true; } else if (type == 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_renderStateType.MOJOSHADER_RS_DEPTHBIAS) { float* val = (float*) states[i].value.values; pipelineCache.DepthBias = *val; rasterizerStateChanged = true; } else if (type == 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_renderStateType.MOJOSHADER_RS_SRCBLENDALPHA) { MOJOSHADER_blendMode* val = (MOJOSHADER_blendMode*) states[i].value.values; pipelineCache.AlphaSourceBlend = XNABlend[(int) *val]; blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_DESTBLENDALPHA) { MOJOSHADER_blendMode* val = (MOJOSHADER_blendMode*) states[i].value.values; pipelineCache.AlphaDestinationBlend = XNABlend[(int) *val]; blendStateChanged = true; } else if (type == MOJOSHADER_renderStateType.MOJOSHADER_RS_BLENDOPALPHA) { MOJOSHADER_blendOp* val = (MOJOSHADER_blendOp*) states[i].value.values; pipelineCache.AlphaBlendFunction = XNABlendOp[(int) *val]; blendStateChanged = true; } else if (type == (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_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_samplerStateRegister*) stateChanges->vertex_sampler_state_changes, GraphicsDevice.VertexTextures, GraphicsDevice.VertexSamplerStates ); } } private unsafe void INTERNAL_updateSamplers( uint changeCount, 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_textureFilterType magFilter = XNAMag[(int) filter]; MOJOSHADER_textureFilterType minFilter = XNAMin[(int) filter]; MOJOSHADER_textureFilterType mipFilter = XNAMip[(int) filter]; MOJOSHADER_effectSamplerState* states = (MOJOSHADER_effectSamplerState*) registers[i].sampler_states; for (int j = 0; j < registers[i].sampler_state_count; j += 1) { MOJOSHADER_samplerStateType type = states[j].type; if (type == 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_samplerStateType.MOJOSHADER_SAMP_ADDRESSU) { MOJOSHADER_textureAddress* val = (MOJOSHADER_textureAddress*) states[j].value.values; pipelineCache.AddressU = XNAAddress[(int) *val]; samplerChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_ADDRESSV) { MOJOSHADER_textureAddress* val = (MOJOSHADER_textureAddress*) states[j].value.values; pipelineCache.AddressV = XNAAddress[(int) *val]; samplerChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_ADDRESSW) { MOJOSHADER_textureAddress* val = (MOJOSHADER_textureAddress*) states[j].value.values; pipelineCache.AddressW = XNAAddress[(int) *val]; samplerChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAGFILTER) { MOJOSHADER_textureFilterType* val = (MOJOSHADER_textureFilterType*) states[j].value.values; magFilter = *val; filterChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MINFILTER) { MOJOSHADER_textureFilterType* val = (MOJOSHADER_textureFilterType*) states[j].value.values; minFilter = *val; filterChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MIPFILTER) { MOJOSHADER_textureFilterType* val = (MOJOSHADER_textureFilterType*) states[j].value.values; mipFilter = *val; filterChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MIPMAPLODBIAS) { float* val = (float*) states[j].value.values; pipelineCache.MipMapLODBias = *val; samplerChanged = true; } else if (type == MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAXMIPLEVEL) { int* val = (int*) states[j].value.values; pipelineCache.MaxMipLevel = *val; samplerChanged = true; } else if (type == 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_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT) { if (minFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT) { if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE || mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT ) { pipelineCache.Filter = TextureFilter.Point; } else if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ) { pipelineCache.Filter = TextureFilter.PointMipLinear; } else { throw new NotImplementedException("Unhandled mipfilter type! " + mipFilter); } } else if ( minFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || minFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ) { if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE || mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT ) { pipelineCache.Filter = TextureFilter.MinLinearMagPointMipPoint; } else if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || mipFilter == 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_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || magFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ) { if (minFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT) { if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE || mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT ) { pipelineCache.Filter = TextureFilter.MinPointMagLinearMipPoint; } else if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ) { pipelineCache.Filter = TextureFilter.MinPointMagLinearMipLinear; } else { throw new NotImplementedException("Unhandled mipfilter type! " + mipFilter); } } else if ( minFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || minFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ) { if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE || mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT ) { pipelineCache.Filter = TextureFilter.LinearMipPoint; } else if ( mipFilter == MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR || mipFilter == 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(IntPtr effectData) { MOJOSHADER_effect* effectPtr = (MOJOSHADER_effect*) effectData; // Set up Parameters MOJOSHADER_effectParam* paramPtr = (MOJOSHADER_effectParam*) effectPtr->parameters; List parameters = new List(); for (int i = 0; i < effectPtr->param_count; i += 1) { MOJOSHADER_effectParam param = paramPtr[i]; if ( param.value.type.parameter_type == MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_VERTEXSHADER || param.value.type.parameter_type == MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_PIXELSHADER ) { // Skip shader objects... continue; } else if ( param.value.type.parameter_type >= MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_SAMPLER && param.value.type.parameter_type <= MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_SAMPLERCUBE ) { string textureName = String.Empty; MOJOSHADER_effectSamplerState* states = (MOJOSHADER_effectSamplerState*) param.value.values; for (int j = 0; j < param.value.value_count; j += 1) { if ( states[j].value.type.parameter_type >= MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_TEXTURE && states[j].value.type.parameter_type <= MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_TEXTURECUBE ) { MOJOSHADER_effectObject *objectPtr = (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 memList = new List(); unsafe { MOJOSHADER_symbolStructMember* mem = (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_effectTechnique* techPtr = (MOJOSHADER_effectTechnique*) effectPtr->techniques; List techniques = new List(effectPtr->technique_count); for (int i = 0; i < techniques.Capacity; i += 1, techPtr += 1) { // Set up Passes MOJOSHADER_effectPass* passPtr = (MOJOSHADER_effectPass*) techPtr->passes; List passes = new List((int) techPtr->pass_count); for (int j = 0; j < passes.Capacity; j += 1) { 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_effectAnnotation* annoPtr = (MOJOSHADER_effectAnnotation*) rawAnnotations; List annotations = new List((int) numAnnotations); for (int i = 0; i < numAnnotations; i += 1) { 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 #region MojoShader Interop /* Shader Parse Interface */ private enum MOJOSHADER_symbolClass { MOJOSHADER_SYMCLASS_SCALAR = 0, MOJOSHADER_SYMCLASS_VECTOR, MOJOSHADER_SYMCLASS_MATRIX_ROWS, MOJOSHADER_SYMCLASS_MATRIX_COLUMNS, MOJOSHADER_SYMCLASS_OBJECT, MOJOSHADER_SYMCLASS_STRUCT, MOJOSHADER_SYMCLASS_TOTAL } private enum MOJOSHADER_symbolType { MOJOSHADER_SYMTYPE_VOID = 0, MOJOSHADER_SYMTYPE_BOOL, MOJOSHADER_SYMTYPE_INT, MOJOSHADER_SYMTYPE_FLOAT, MOJOSHADER_SYMTYPE_STRING, MOJOSHADER_SYMTYPE_TEXTURE, MOJOSHADER_SYMTYPE_TEXTURE1D, MOJOSHADER_SYMTYPE_TEXTURE2D, MOJOSHADER_SYMTYPE_TEXTURE3D, MOJOSHADER_SYMTYPE_TEXTURECUBE, MOJOSHADER_SYMTYPE_SAMPLER, MOJOSHADER_SYMTYPE_SAMPLER1D, MOJOSHADER_SYMTYPE_SAMPLER2D, MOJOSHADER_SYMTYPE_SAMPLER3D, MOJOSHADER_SYMTYPE_SAMPLERCUBE, MOJOSHADER_SYMTYPE_PIXELSHADER, MOJOSHADER_SYMTYPE_VERTEXSHADER, MOJOSHADER_SYMTYPE_PIXELFRAGMENT, MOJOSHADER_SYMTYPE_VERTEXFRAGMENT, MOJOSHADER_SYMTYPE_UNSUPPORTED, MOJOSHADER_SYMTYPE_TOTAL } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_symbolTypeInfo { public MOJOSHADER_symbolClass parameter_class; public MOJOSHADER_symbolType parameter_type; public uint rows; public uint columns; public uint elements; public uint member_count; public IntPtr members; // MOJOSHADER_symbolStructMember* } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_symbolStructMember { public IntPtr name; //const char* public MOJOSHADER_symbolTypeInfo info; } /* MOJOSHADER_effectState types... */ private enum MOJOSHADER_renderStateType { MOJOSHADER_RS_ZENABLE, MOJOSHADER_RS_FILLMODE, MOJOSHADER_RS_SHADEMODE, MOJOSHADER_RS_ZWRITEENABLE, MOJOSHADER_RS_ALPHATESTENABLE, MOJOSHADER_RS_LASTPIXEL, MOJOSHADER_RS_SRCBLEND, MOJOSHADER_RS_DESTBLEND, MOJOSHADER_RS_CULLMODE, MOJOSHADER_RS_ZFUNC, MOJOSHADER_RS_ALPHAREF, MOJOSHADER_RS_ALPHAFUNC, MOJOSHADER_RS_DITHERENABLE, MOJOSHADER_RS_ALPHABLENDENABLE, MOJOSHADER_RS_FOGENABLE, MOJOSHADER_RS_SPECULARENABLE, MOJOSHADER_RS_FOGCOLOR, MOJOSHADER_RS_FOGTABLEMODE, MOJOSHADER_RS_FOGSTART, MOJOSHADER_RS_FOGEND, MOJOSHADER_RS_FOGDENSITY, MOJOSHADER_RS_RANGEFOGENABLE, MOJOSHADER_RS_STENCILENABLE, MOJOSHADER_RS_STENCILFAIL, MOJOSHADER_RS_STENCILZFAIL, MOJOSHADER_RS_STENCILPASS, MOJOSHADER_RS_STENCILFUNC, MOJOSHADER_RS_STENCILREF, MOJOSHADER_RS_STENCILMASK, MOJOSHADER_RS_STENCILWRITEMASK, MOJOSHADER_RS_TEXTUREFACTOR, MOJOSHADER_RS_WRAP0, MOJOSHADER_RS_WRAP1, MOJOSHADER_RS_WRAP2, MOJOSHADER_RS_WRAP3, MOJOSHADER_RS_WRAP4, MOJOSHADER_RS_WRAP5, MOJOSHADER_RS_WRAP6, MOJOSHADER_RS_WRAP7, MOJOSHADER_RS_WRAP8, MOJOSHADER_RS_WRAP9, MOJOSHADER_RS_WRAP10, MOJOSHADER_RS_WRAP11, MOJOSHADER_RS_WRAP12, MOJOSHADER_RS_WRAP13, MOJOSHADER_RS_WRAP14, MOJOSHADER_RS_WRAP15, MOJOSHADER_RS_CLIPPING, MOJOSHADER_RS_LIGHTING, MOJOSHADER_RS_AMBIENT, MOJOSHADER_RS_FOGVERTEXMODE, MOJOSHADER_RS_COLORVERTEX, MOJOSHADER_RS_LOCALVIEWER, MOJOSHADER_RS_NORMALIZENORMALS, MOJOSHADER_RS_DIFFUSEMATERIALSOURCE, MOJOSHADER_RS_SPECULARMATERIALSOURCE, MOJOSHADER_RS_AMBIENTMATERIALSOURCE, MOJOSHADER_RS_EMISSIVEMATERIALSOURCE, MOJOSHADER_RS_VERTEXBLEND, MOJOSHADER_RS_CLIPPLANEENABLE, MOJOSHADER_RS_POINTSIZE, MOJOSHADER_RS_POINTSIZE_MIN, MOJOSHADER_RS_POINTSPRITEENABLE, MOJOSHADER_RS_POINTSCALEENABLE, MOJOSHADER_RS_POINTSCALE_A, MOJOSHADER_RS_POINTSCALE_B, MOJOSHADER_RS_POINTSCALE_C, MOJOSHADER_RS_MULTISAMPLEANTIALIAS, MOJOSHADER_RS_MULTISAMPLEMASK, MOJOSHADER_RS_PATCHEDGESTYLE, MOJOSHADER_RS_DEBUGMONITORTOKEN, MOJOSHADER_RS_POINTSIZE_MAX, MOJOSHADER_RS_INDEXEDVERTEXBLENDENABLE, MOJOSHADER_RS_COLORWRITEENABLE, MOJOSHADER_RS_TWEENFACTOR, MOJOSHADER_RS_BLENDOP, MOJOSHADER_RS_POSITIONDEGREE, MOJOSHADER_RS_NORMALDEGREE, MOJOSHADER_RS_SCISSORTESTENABLE, MOJOSHADER_RS_SLOPESCALEDEPTHBIAS, MOJOSHADER_RS_ANTIALIASEDLINEENABLE, MOJOSHADER_RS_MINTESSELLATIONLEVEL, MOJOSHADER_RS_MAXTESSELLATIONLEVEL, MOJOSHADER_RS_ADAPTIVETESS_X, MOJOSHADER_RS_ADAPTIVETESS_Y, MOJOSHADER_RS_ADAPTIVETESS_Z, MOJOSHADER_RS_ADAPTIVETESS_W, MOJOSHADER_RS_ENABLEADAPTIVETESSELLATION, MOJOSHADER_RS_TWOSIDEDSTENCILMODE, MOJOSHADER_RS_CCW_STENCILFAIL, MOJOSHADER_RS_CCW_STENCILZFAIL, MOJOSHADER_RS_CCW_STENCILPASS, MOJOSHADER_RS_CCW_STENCILFUNC, MOJOSHADER_RS_COLORWRITEENABLE1, MOJOSHADER_RS_COLORWRITEENABLE2, MOJOSHADER_RS_COLORWRITEENABLE3, MOJOSHADER_RS_BLENDFACTOR, MOJOSHADER_RS_SRGBWRITEENABLE, MOJOSHADER_RS_DEPTHBIAS, MOJOSHADER_RS_SEPARATEALPHABLENDENABLE, MOJOSHADER_RS_SRCBLENDALPHA, MOJOSHADER_RS_DESTBLENDALPHA, MOJOSHADER_RS_BLENDOPALPHA, MOJOSHADER_RS_VERTEXSHADER = 146, MOJOSHADER_RS_PIXELSHADER = 147 } private enum MOJOSHADER_zBufferType { MOJOSHADER_ZB_FALSE, MOJOSHADER_ZB_TRUE, MOJOSHADER_ZB_USEW } private enum MOJOSHADER_fillMode { MOJOSHADER_FILL_POINT = 1, MOJOSHADER_FILL_WIREFRAME = 2, MOJOSHADER_FILL_SOLID = 3 } private enum MOJOSHADER_blendMode { MOJOSHADER_BLEND_ZERO = 1, MOJOSHADER_BLEND_ONE = 2, MOJOSHADER_BLEND_SRCCOLOR = 3, MOJOSHADER_BLEND_INVSRCCOLOR = 4, MOJOSHADER_BLEND_SRCALPHA = 5, MOJOSHADER_BLEND_INVSRCALPHA = 6, MOJOSHADER_BLEND_DESTALPHA = 7, MOJOSHADER_BLEND_INVDESTALPHA = 8, MOJOSHADER_BLEND_DESTCOLOR = 9, MOJOSHADER_BLEND_INVDESTCOLOR = 10, MOJOSHADER_BLEND_SRCALPHASAT = 11, MOJOSHADER_BLEND_BOTHSRCALPHA = 12, MOJOSHADER_BLEND_BOTHINVSRCALPHA = 13, MOJOSHADER_BLEND_BLENDFACTOR = 14, MOJOSHADER_BLEND_INVBLENDFACTOR = 15, MOJOSHADER_BLEND_SRCCOLOR2 = 16, MOJOSHADER_BLEND_INVSRCCOLOR2 = 17 } private enum MOJOSHADER_cullMode { MOJOSHADER_CULL_NONE = 1, MOJOSHADER_CULL_CW = 2, MOJOSHADER_CULL_CCW = 3 } private enum MOJOSHADER_compareFunc { MOJOSHADER_CMP_NEVER = 1, MOJOSHADER_CMP_LESS = 2, MOJOSHADER_CMP_EQUAL = 3, MOJOSHADER_CMP_LESSEQUAL = 4, MOJOSHADER_CMP_GREATER = 5, MOJOSHADER_CMP_NOTEQUAL = 6, MOJOSHADER_CMP_GREATEREQUAL = 7, MOJOSHADER_CMP_ALWAYS = 8 } private enum MOJOSHADER_stencilOp { MOJOSHADER_STENCILOP_KEEP = 1, MOJOSHADER_STENCILOP_ZERO = 2, MOJOSHADER_STENCILOP_REPLACE = 3, MOJOSHADER_STENCILOP_INCRSAT = 4, MOJOSHADER_STENCILOP_DECRSAT = 5, MOJOSHADER_STENCILOP_INVERT = 6, MOJOSHADER_STENCILOP_INCR = 7, MOJOSHADER_STENCILOP_DECR = 8 } private enum MOJOSHADER_blendOp { MOJOSHADER_BLENDOP_ADD = 1, MOJOSHADER_BLENDOP_SUBTRACT = 2, MOJOSHADER_BLENDOP_REVSUBTRACT = 3, MOJOSHADER_BLENDOP_MIN = 4, MOJOSHADER_BLENDOP_MAX = 5 } /* MOJOSHADER_effectSamplerState types... */ private enum MOJOSHADER_samplerStateType { MOJOSHADER_SAMP_UNKNOWN0 = 0, MOJOSHADER_SAMP_UNKNOWN1 = 1, MOJOSHADER_SAMP_UNKNOWN2 = 2, MOJOSHADER_SAMP_UNKNOWN3 = 3, MOJOSHADER_SAMP_TEXTURE = 4, MOJOSHADER_SAMP_ADDRESSU = 5, MOJOSHADER_SAMP_ADDRESSV = 6, MOJOSHADER_SAMP_ADDRESSW = 7, MOJOSHADER_SAMP_BORDERCOLOR = 8, MOJOSHADER_SAMP_MAGFILTER = 9, MOJOSHADER_SAMP_MINFILTER = 10, MOJOSHADER_SAMP_MIPFILTER = 11, MOJOSHADER_SAMP_MIPMAPLODBIAS = 12, MOJOSHADER_SAMP_MAXMIPLEVEL = 13, MOJOSHADER_SAMP_MAXANISOTROPY = 14, MOJOSHADER_SAMP_SRGBTEXTURE = 15, MOJOSHADER_SAMP_ELEMENTINDEX = 16, MOJOSHADER_SAMP_DMAPOFFSET = 17 } private enum MOJOSHADER_textureAddress { MOJOSHADER_TADDRESS_WRAP = 1, MOJOSHADER_TADDRESS_MIRROR = 2, MOJOSHADER_TADDRESS_CLAMP = 3, MOJOSHADER_TADDRESS_BORDER = 4, MOJOSHADER_TADDRESS_MIRRORONCE = 5 } private enum MOJOSHADER_textureFilterType { MOJOSHADER_TEXTUREFILTER_NONE, MOJOSHADER_TEXTUREFILTER_POINT, MOJOSHADER_TEXTUREFILTER_LINEAR, MOJOSHADER_TEXTUREFILTER_ANISOTROPIC, MOJOSHADER_TEXTUREFILTER_PYRAMIDALQUAD, MOJOSHADER_TEXTUREFILTER_GAUSSIANQUAD, MOJOSHADER_TEXTUREFILTER_CONVOLUTIONMONO } /* Effect value types... */ [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectValue { public IntPtr name; // const char* public IntPtr semantic; // const char* public MOJOSHADER_symbolTypeInfo type; public uint value_count; public IntPtr values; // You know what, just look at the C header... } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectState { public MOJOSHADER_renderStateType type; public MOJOSHADER_effectValue value; } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectSamplerState { public MOJOSHADER_samplerStateType type; public MOJOSHADER_effectValue value; } /* typedef MOJOSHADER_effectValue MOJOSHADER_effectAnnotation; */ [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectAnnotation { public IntPtr name; // const char* public IntPtr semantic; // const char* public MOJOSHADER_symbolTypeInfo type; public uint value_count; public IntPtr values; // You know what, just look at the C header... } /* Effect interface structures... */ [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectParam { public MOJOSHADER_effectValue value; public uint annotation_count; public IntPtr annotations; // MOJOSHADER_effectAnnotations* } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectPass { public IntPtr name; // const char* public uint state_count; public IntPtr states; // MOJOSHADER_effectState* public uint annotation_count; public IntPtr annotations; // MOJOSHADER_effectAnnotations* } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectTechnique { public IntPtr name; // const char* public uint pass_count; public IntPtr passes; // MOJOSHADER_effectPass* public uint annotation_count; public IntPtr annotations; // MOJOSHADER_effectAnnotations* } /* Effect "objects"... */ [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectShader { public MOJOSHADER_symbolType type; public uint technique; public uint pass; public uint is_preshader; public uint preshader_param_count; public IntPtr preshader_params; // unsigned int* public uint param_count; public IntPtr parameters; // unsigned int* public uint sampler_count; public IntPtr samplers; // MOJOSHADER_samplerStateRegister* public IntPtr shader; // *shader/*preshader union } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectSamplerMap { public MOJOSHADER_symbolType type; public IntPtr name; // const char* } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectString { public MOJOSHADER_symbolType type; public IntPtr stringvalue; // const char* } [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effectTexture { public MOJOSHADER_symbolType type; } [StructLayout(LayoutKind.Explicit)] private struct MOJOSHADER_effectObject { [FieldOffset(0)] public MOJOSHADER_symbolType type; [FieldOffset(0)] public MOJOSHADER_effectShader shader; [FieldOffset(0)] public MOJOSHADER_effectSamplerMap mapping; [FieldOffset(0)] public MOJOSHADER_effectString stringvalue; [FieldOffset(0)] public MOJOSHADER_effectTexture texture; } /* Effect state change types... */ [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_samplerStateRegister { public IntPtr sampler_name; // const char* public uint sampler_register; public uint sampler_state_count; public IntPtr sampler_states; // const MOJOSHADER_effectSamplerState* } // Needed by VideoPlayer... [StructLayout(LayoutKind.Sequential)] internal struct MOJOSHADER_effectStateChanges { public uint render_state_change_count; public IntPtr render_state_changes; // const MOJOSHADER_effectState* public uint sampler_state_change_count; public IntPtr sampler_state_changes; // const MOJOSHADER_samplerStateRegister* public uint vertex_sampler_state_change_count; public IntPtr vertex_sampler_state_changes; // const MOJOSHADER_samplerStateRegister* } /* Effect parsing interface... this is a partial struct! */ [StructLayout(LayoutKind.Sequential)] private struct MOJOSHADER_effect { public int error_count; public IntPtr errors; // MOJOSHADER_error* public int param_count; public IntPtr parameters; // MOJOSHADER_effectParam* params, lolC# public int technique_count; public IntPtr techniques; // MOJOSHADER_effectTechnique* public int object_count; public IntPtr objects; // MOJOSHADER_effectObject* } #endregion } }