#region License
#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<
string
, EffectParameter> samplerMap =
new
Dictionary<
string
, EffectParameter>();
private
MojoShader.MOJOSHADER_effectStateChanges stateChanges;
private
GCHandle stateChangesHandle;
#endregion
#region Private State Cache Hack Variables
private
BlendState[] blendCache =
new
BlendState[2]
{
new
BlendState(),
new
BlendState()
};
private
DepthStencilState[] depthStencilCache =
new
DepthStencilState[2]
{
new
DepthStencilState(),
new
DepthStencilState()
};
private
RasterizerState[] rasterizerCache =
new
RasterizerState[2]
{
new
RasterizerState(),
new
RasterizerState()
};
private
SamplerState[] samplerCache = GenerateSamplerCache();
private
static
SamplerState[] GenerateSamplerCache()
{
int
numSamplers = 60;
SamplerState[] result =
new
SamplerState[numSamplers];
for
(
int
i = 0; i < numSamplers; i += 1)
{
result[i] =
new
SamplerState();
}
return
result;
}
#endregion
#region Private Static Variables
private
static
readonly
EffectParameterType[] XNAType =
new
EffectParameterType[]
{
EffectParameterType.Void,
EffectParameterType.Bool,
EffectParameterType.Int32,
EffectParameterType.Single,
EffectParameterType.String,
EffectParameterType.Texture,
EffectParameterType.Texture1D,
EffectParameterType.Texture2D,
EffectParameterType.Texture3D,
EffectParameterType.TextureCube
};
private
static
readonly
EffectParameterClass[] XNAClass =
new
EffectParameterClass[]
{
EffectParameterClass.Scalar,
EffectParameterClass.Vector,
EffectParameterClass.Matrix,
EffectParameterClass.Matrix,
EffectParameterClass.Object,
EffectParameterClass.Struct
};
private
static
readonly
Blend[] XNABlend =
new
Blend[]
{
(Blend) (-1),
Blend.Zero,
Blend.One,
Blend.SourceColor,
Blend.InverseSourceColor,
Blend.SourceAlpha,
Blend.InverseSourceAlpha,
Blend.DestinationAlpha,
Blend.InverseDestinationAlpha,
Blend.DestinationColor,
Blend.InverseDestinationColor,
Blend.SourceAlphaSaturation,
(Blend) (-1),
(Blend) (-1),
Blend.BlendFactor,
Blend.InverseBlendFactor
};
private
static
readonly
BlendFunction[] XNABlendOp =
new
BlendFunction[]
{
(BlendFunction) (-1),
BlendFunction.Add,
BlendFunction.Subtract,
BlendFunction.ReverseSubtract,
BlendFunction.Min,
BlendFunction.Max
};
private
static
readonly
CompareFunction[] XNACompare =
new
CompareFunction[]
{
(CompareFunction) (-1),
CompareFunction.Never,
CompareFunction.Less,
CompareFunction.Equal,
CompareFunction.LessEqual,
CompareFunction.Greater,
CompareFunction.NotEqual,
CompareFunction.GreaterEqual,
CompareFunction.Always
};
private
static
readonly
StencilOperation[] XNAStencilOp =
new
StencilOperation[]
{
(StencilOperation) (-1),
StencilOperation.Keep,
StencilOperation.Zero,
StencilOperation.Replace,
StencilOperation.IncrementSaturation,
StencilOperation.DecrementSaturation,
StencilOperation.Invert,
StencilOperation.Increment,
StencilOperation.Decrement
};
private
static
readonly
TextureAddressMode[] XNAAddress =
new
TextureAddressMode[]
{
(TextureAddressMode) (-1),
TextureAddressMode.Wrap,
TextureAddressMode.Mirror,
TextureAddressMode.Clamp
};
private
static
readonly
MojoShader.MOJOSHADER_textureFilterType[] XNAMag =
new
MojoShader.MOJOSHADER_textureFilterType[]
{
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR
};
private
static
readonly
MojoShader.MOJOSHADER_textureFilterType[] XNAMin =
new
MojoShader.MOJOSHADER_textureFilterType[]
{
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT
};
private
static
readonly
MojoShader.MOJOSHADER_textureFilterType[] XNAMip =
new
MojoShader.MOJOSHADER_textureFilterType[]
{
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR,
MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT
};
#endregion
#region Public Constructor
public
Effect(GraphicsDevice graphicsDevice,
byte
[] effectCode)
{
GraphicsDevice = graphicsDevice;
glEffect = graphicsDevice.GLDevice.CreateEffect(effectCode);
INTERNAL_parseEffectStruct();
CurrentTechnique = Techniques[0];
stateChanges =
new
MojoShader.MOJOSHADER_effectStateChanges();
stateChanges.render_state_change_count = 0;
stateChanges.sampler_state_change_count = 0;
stateChanges.vertex_sampler_state_change_count = 0;
stateChangesHandle = GCHandle.Alloc(stateChanges, GCHandleType.Pinned);
}
#endregion
#region Protected Constructor
protected
Effect(Effect cloneSource)
{
GraphicsDevice = cloneSource.GraphicsDevice;
glEffect = GraphicsDevice.GLDevice.CloneEffect(
cloneSource.glEffect
);
INTERNAL_parseEffectStruct();
for
(
int
i = 0; i < cloneSource.Techniques.Count; i += 1)
{
if
(cloneSource.Techniques[i] == cloneSource.CurrentTechnique)
{
CurrentTechnique = Techniques[i];
}
}
stateChanges =
new
MojoShader.MOJOSHADER_effectStateChanges();
stateChanges.render_state_change_count = 0;
stateChanges.sampler_state_change_count = 0;
stateChanges.vertex_sampler_state_change_count = 0;
stateChangesHandle = GCHandle.Alloc(stateChanges, GCHandleType.Pinned);
}
#endregion
#region Public Methods
public
virtual
Effect Clone()
{
return
new
Effect(
this
);
}
#endregion
#region Protected Methods
protected
override
void
Dispose(
bool
disposing)
{
if
(!IsDisposed)
{
GraphicsDevice.GLDevice.AddDisposeEffect(glEffect);
stateChangesHandle.Free();
}
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,
ref
stateChanges
);
if
(stateChanges.render_state_change_count > 0)
{
bool
blendStateChanged =
false
;
bool
depthStencilStateChanged =
false
;
bool
rasterizerStateChanged =
false
;
BlendState oldBlendState = GraphicsDevice.BlendState;
DepthStencilState oldDepthStencilState = GraphicsDevice.DepthStencilState;
RasterizerState oldRasterizerState = GraphicsDevice.RasterizerState;
BlendFunction alphaBlendFunction = oldBlendState.AlphaBlendFunction;
Blend alphaDestinationBlend = oldBlendState.AlphaDestinationBlend;
Blend alphaSourceBlend = oldBlendState.AlphaSourceBlend;
BlendFunction colorBlendFunction = oldBlendState.ColorBlendFunction;
Blend colorDestinationBlend = oldBlendState.ColorDestinationBlend;
Blend colorSourceBlend = oldBlendState.ColorSourceBlend;
ColorWriteChannels colorWriteChannels = oldBlendState.ColorWriteChannels;
ColorWriteChannels colorWriteChannels1 = oldBlendState.ColorWriteChannels1;
ColorWriteChannels colorWriteChannels2 = oldBlendState.ColorWriteChannels2;
ColorWriteChannels colorWriteChannels3 = oldBlendState.ColorWriteChannels3;
Color blendFactor = oldBlendState.BlendFactor;
int
multiSampleMask = oldBlendState.MultiSampleMask;
bool
separateAlphaBlend = (
colorBlendFunction != alphaBlendFunction ||
colorDestinationBlend != alphaDestinationBlend
);
bool
depthBufferEnable = oldDepthStencilState.DepthBufferEnable;
bool
depthBufferWriteEnable = oldDepthStencilState.DepthBufferWriteEnable;
CompareFunction depthBufferFunction = oldDepthStencilState.DepthBufferFunction;
bool
stencilEnable = oldDepthStencilState.StencilEnable;
CompareFunction stencilFunction = oldDepthStencilState.StencilFunction;
StencilOperation stencilPass = oldDepthStencilState.StencilPass;
StencilOperation stencilFail = oldDepthStencilState.StencilFail;
StencilOperation stencilDepthBufferFail = oldDepthStencilState.StencilDepthBufferFail;
bool
twoSidedStencilMode = oldDepthStencilState.TwoSidedStencilMode;
CompareFunction ccwStencilFunction = oldDepthStencilState.CounterClockwiseStencilFunction;
StencilOperation ccwStencilFail = oldDepthStencilState.CounterClockwiseStencilFail;
StencilOperation ccwStencilPass = oldDepthStencilState.CounterClockwiseStencilPass;
StencilOperation ccwStencilDepthBufferFail = oldDepthStencilState.CounterClockwiseStencilDepthBufferFail;
int
stencilMask = oldDepthStencilState.StencilMask;
int
stencilWriteMask = oldDepthStencilState.StencilWriteMask;
int
referenceStencil = oldDepthStencilState.ReferenceStencil;
CullMode cullMode = oldRasterizerState.CullMode;
FillMode fillMode = oldRasterizerState.FillMode;
float
depthBias = oldRasterizerState.DepthBias;
bool
multiSampleAntiAlias = oldRasterizerState.MultiSampleAntiAlias;
bool
scissorTestEnable = oldRasterizerState.ScissorTestEnable;
float
slopeScaleDepthBias = oldRasterizerState.SlopeScaleDepthBias;
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 )
{
continue
;
}
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ZENABLE)
{
MojoShader.MOJOSHADER_zBufferType* val = (MojoShader.MOJOSHADER_zBufferType*) states[i].value.values;
depthBufferEnable =
(*val == MojoShader.MOJOSHADER_zBufferType.MOJOSHADER_ZB_TRUE) ?
true
:
false
;
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)
{
fillMode = FillMode.Solid;
}
else
if
(*val == MojoShader.MOJOSHADER_fillMode.MOJOSHADER_FILL_WIREFRAME)
{
fillMode = FillMode.WireFrame;
}
rasterizerStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ZWRITEENABLE)
{
int
* val = (
int
*) states[i].value.values;
depthBufferWriteEnable = (*val == 1) ?
true
:
false
;
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SRCBLEND)
{
MojoShader.MOJOSHADER_blendMode* val = (MojoShader.MOJOSHADER_blendMode*) states[i].value.values;
colorSourceBlend = XNABlend[(
int
) *val];
if
(!separateAlphaBlend)
{
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;
colorDestinationBlend = XNABlend[(
int
) *val];
if
(!separateAlphaBlend)
{
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)
{
cullMode = CullMode.None;
}
else
if
(*val == MojoShader.MOJOSHADER_cullMode.MOJOSHADER_CULL_CW)
{
cullMode = CullMode.CullClockwiseFace;
}
else
if
(*val == MojoShader.MOJOSHADER_cullMode.MOJOSHADER_CULL_CCW)
{
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;
depthBufferFunction = XNACompare[(
int
) *val];
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_ALPHABLENDENABLE)
{
int
* val = (
int
*) states[i].value.values;
if
(*val == 0)
{
colorSourceBlend = Blend.One;
colorDestinationBlend = Blend.Zero;
alphaSourceBlend = Blend.One;
alphaDestinationBlend = Blend.Zero;
blendStateChanged =
true
;
}
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILENABLE)
{
int
* val = (
int
*) states[i].value.values;
stencilEnable = (*val == 1) ?
true
:
false
;
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILFAIL)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
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;
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;
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;
stencilFunction = XNACompare[(
int
) *val];
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILREF)
{
int
* val = (
int
*) states[i].value.values;
referenceStencil = *val;
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILMASK)
{
int
* val = (
int
*) states[i].value.values;
stencilMask = *val;
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_STENCILWRITEMASK)
{
int
* val = (
int
*) states[i].value.values;
stencilWriteMask = *val;
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_MULTISAMPLEANTIALIAS)
{
int
* val = (
int
*) states[i].value.values;
multiSampleAntiAlias = (*val == 1) ?
true
:
false
;
rasterizerStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_MULTISAMPLEMASK)
{
int
* val = (
int
*) states[i].value.values;
multiSampleMask = *val;
blendStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE)
{
int
* val = (
int
*) states[i].value.values;
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;
colorBlendFunction = XNABlendOp[(
int
) *val];
blendStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SCISSORTESTENABLE)
{
int
* val = (
int
*) states[i].value.values;
scissorTestEnable = (*val == 1) ?
true
:
false
;
rasterizerStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SLOPESCALEDEPTHBIAS)
{
float
* val = (
float
*) states[i].value.values;
slopeScaleDepthBias = *val;
rasterizerStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_TWOSIDEDSTENCILMODE)
{
int
* val = (
int
*) states[i].value.values;
twoSidedStencilMode = (*val == 1) ?
true
:
false
;
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_CCW_STENCILFAIL)
{
MojoShader.MOJOSHADER_stencilOp* val = (MojoShader.MOJOSHADER_stencilOp*) states[i].value.values;
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;
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;
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;
ccwStencilFunction = XNACompare[(
int
) *val];
depthStencilStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE1)
{
int
* val = (
int
*) states[i].value.values;
colorWriteChannels1 = (ColorWriteChannels) (*val);
blendStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE2)
{
int
* val = (
int
*) states[i].value.values;
colorWriteChannels2 = (ColorWriteChannels) (*val);
blendStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_COLORWRITEENABLE3)
{
int
* val = (
int
*) states[i].value.values;
colorWriteChannels3 = (ColorWriteChannels) (*val);
blendStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_BLENDFACTOR)
{
int
* val = (
int
*) states[i].value.values;
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;
depthBias = *val;
rasterizerStateChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SEPARATEALPHABLENDENABLE)
{
int
* val = (
int
*) states[i].value.values;
separateAlphaBlend = (*val == 1);
}
else
if
(type == MojoShader.MOJOSHADER_renderStateType.MOJOSHADER_RS_SRCBLENDALPHA)
{
MojoShader.MOJOSHADER_blendMode* val = (MojoShader.MOJOSHADER_blendMode*) states[i].value.values;
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;
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;
alphaBlendFunction = XNABlendOp[(
int
) *val];
blendStateChanged =
true
;
}
else
{
throw
new
NotImplementedException(
"Unhandled render state!"
);
}
}
if
(blendStateChanged)
{
BlendState newBlend;
if
(GraphicsDevice.BlendState == blendCache[0])
{
newBlend = blendCache[1];
}
else
{
newBlend = blendCache[0];
}
newBlend.AlphaBlendFunction = alphaBlendFunction;
newBlend.AlphaDestinationBlend = alphaDestinationBlend;
newBlend.AlphaSourceBlend = alphaSourceBlend;
newBlend.ColorBlendFunction = colorBlendFunction;
newBlend.ColorDestinationBlend = colorDestinationBlend;
newBlend.ColorSourceBlend = colorSourceBlend;
newBlend.ColorWriteChannels = colorWriteChannels;
newBlend.ColorWriteChannels1 = colorWriteChannels1;
newBlend.ColorWriteChannels2 = colorWriteChannels2;
newBlend.ColorWriteChannels3 = colorWriteChannels3;
newBlend.BlendFactor = blendFactor;
newBlend.MultiSampleMask = multiSampleMask;
GraphicsDevice.BlendState = newBlend;
}
if
(depthStencilStateChanged)
{
DepthStencilState newDepthStencil;
if
(GraphicsDevice.DepthStencilState == depthStencilCache[0])
{
newDepthStencil = depthStencilCache[1];
}
else
{
newDepthStencil = depthStencilCache[0];
}
newDepthStencil.DepthBufferEnable = depthBufferEnable;
newDepthStencil.DepthBufferWriteEnable = depthBufferWriteEnable;
newDepthStencil.DepthBufferFunction = depthBufferFunction;
newDepthStencil.StencilEnable = stencilEnable;
newDepthStencil.StencilFunction = stencilFunction;
newDepthStencil.StencilPass = stencilPass;
newDepthStencil.StencilFail = stencilFail;
newDepthStencil.StencilDepthBufferFail = stencilDepthBufferFail;
newDepthStencil.TwoSidedStencilMode = twoSidedStencilMode;
newDepthStencil.CounterClockwiseStencilFunction = ccwStencilFunction;
newDepthStencil.CounterClockwiseStencilFail = ccwStencilFail;
newDepthStencil.CounterClockwiseStencilPass = ccwStencilPass;
newDepthStencil.CounterClockwiseStencilDepthBufferFail = ccwStencilDepthBufferFail;
newDepthStencil.StencilMask = stencilMask;
newDepthStencil.StencilWriteMask = stencilWriteMask;
newDepthStencil.ReferenceStencil = referenceStencil;
GraphicsDevice.DepthStencilState = newDepthStencil;
}
if
(rasterizerStateChanged)
{
RasterizerState newRasterizer;
if
(GraphicsDevice.RasterizerState == rasterizerCache[0])
{
newRasterizer = rasterizerCache[1];
}
else
{
newRasterizer = rasterizerCache[0];
}
newRasterizer.CullMode = cullMode;
newRasterizer.FillMode = fillMode;
newRasterizer.DepthBias = depthBias;
newRasterizer.MultiSampleAntiAlias = multiSampleAntiAlias;
newRasterizer.ScissorTestEnable = scissorTestEnable;
newRasterizer.SlopeScaleDepthBias = slopeScaleDepthBias;
GraphicsDevice.RasterizerState = newRasterizer;
}
}
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)
{
continue
;
}
int
register = (
int
) registers[i].sampler_register;
SamplerState oldSampler = samplers[register];
bool
samplerChanged =
false
;
bool
filterChanged =
false
;
TextureAddressMode addressU = oldSampler.AddressU;
TextureAddressMode addressV = oldSampler.AddressV;
TextureAddressMode addressW = oldSampler.AddressW;
int
maxAnisotropy = oldSampler.MaxAnisotropy;
int
maxMipLevel = oldSampler.MaxMipLevel;
float
mipMapLODBias = oldSampler.MipMapLevelOfDetailBias;
TextureFilter filter = oldSampler.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)
{
string
samplerName = Marshal.PtrToStringAnsi(
registers[i].sampler_name
);
if
(samplerMap.ContainsKey(samplerName))
{
Texture texture = samplerMap[samplerName].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;
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;
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;
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[i].value.values;
mipMapLODBias = *val;
samplerChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAXMIPLEVEL)
{
int
* val = (
int
*) states[i].value.values;
maxMipLevel = *val;
samplerChanged =
true
;
}
else
if
(type == MojoShader.MOJOSHADER_samplerStateType.MOJOSHADER_SAMP_MAXANISOTROPY)
{
int
* val = (
int
*) states[i].value.values;
maxAnisotropy = *val;
samplerChanged =
true
;
}
else
{
throw
new
NotImplementedException(
"Unhandled sampler state!"
);
}
}
if
(filterChanged)
{
if
( magFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ||
minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_ANISOTROPIC )
{
filter = TextureFilter.Anisotropic;
}
else
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 )
{
filter = TextureFilter.Point;
}
else
if
(mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
filter = TextureFilter.PointMipLinear;
}
else
{
throw
new
NotImplementedException(
"Unhandled mipfilter type!"
);
}
}
else
if
(minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
if
( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
filter = TextureFilter.MinLinearMagPointMipPoint;
}
else
if
(mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
filter = TextureFilter.MinLinearMagPointMipLinear;
}
else
{
throw
new
NotImplementedException(
"Unhandled mipfilter type!"
);
}
}
else
{
throw
new
NotImplementedException(
"Unhandled minfilter type!"
);
}
}
else
if
(magFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
if
(minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT)
{
if
( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
filter = TextureFilter.MinPointMagLinearMipPoint;
}
else
if
(mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
filter = TextureFilter.MinPointMagLinearMipLinear;
}
else
{
throw
new
NotImplementedException(
"Unhandled mipfilter type!"
);
}
}
else
if
(minFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
if
( mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_NONE ||
mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_POINT )
{
filter = TextureFilter.LinearMipPoint;
}
else
if
(mipFilter == MojoShader.MOJOSHADER_textureFilterType.MOJOSHADER_TEXTUREFILTER_LINEAR)
{
filter = TextureFilter.Linear;
}
else
{
throw
new
NotImplementedException(
"Unhandled mipfilter type!"
);
}
}
else
{
throw
new
NotImplementedException(
"Unhandled minfilter type!"
);
}
}
else
{
throw
new
NotImplementedException(
"Unhandled magfilter type!"
);
}
samplerChanged =
true
;
}
if
(samplerChanged)
{
SamplerState newSampler;
if
(samplers[register] == samplerCache[register])
{
newSampler = samplerCache[register + 30];
}
else
{
newSampler = samplerCache[register];
}
newSampler.Filter = filter;
newSampler.AddressU = addressU;
newSampler.AddressV = addressV;
newSampler.AddressW = addressW;
newSampler.MaxAnisotropy = maxAnisotropy;
newSampler.MaxMipLevel = maxMipLevel;
newSampler.MipMapLevelOfDetailBias = mipMapLODBias;
samplers[register] = newSampler;
}
}
}
#endregion
#region Private Methods
private
unsafe
void
INTERNAL_parseEffectStruct()
{
MojoShader.MOJOSHADER_effect* effectPtr = (MojoShader.MOJOSHADER_effect*) glEffect.EffectData;
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 )
{
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
;
}
}
for
(
int
j = 0; j < parameters.Count; j += 1)
{
if
(textureName.Equals(parameters[j].Name))
{
samplerMap[Marshal.PtrToStringAnsi(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)
{
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
) param.value.type.parameter_class],
XNAType[(
int
) param.value.type.parameter_type],
null
,
null
,
curOffset
));
uint
memSize = mem[j].info.rows + mem[j].info.columns;
if
(mem[j].info.elements > 0)
{
memSize *= mem[j].info.elements;
}
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
));
}
Parameters =
new
EffectParameterCollection(parameters);
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)
{
MojoShader.MOJOSHADER_effectTechnique tech = techPtr[i];
MojoShader.MOJOSHADER_effectPass* passPtr = (MojoShader.MOJOSHADER_effectPass*) tech.passes;
List<EffectPass> passes =
new
List<EffectPass>((
int
) tech.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
,
(
uint
) j
));
}
techniques.Add(
new
EffectTechnique(
Marshal.PtrToStringAnsi(tech.name),
(IntPtr) (techPtr + i),
new
EffectPassCollection(passes),
INTERNAL_readAnnotations(
tech.annotations,
tech.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.row_count,
(
int
) anno.column_count,
XNAClass[(
int
) anno.value_class],
XNAType[(
int
) anno.value_type],
anno.values
));
}
return
new
EffectAnnotationCollection(annotations);
}
#endregion
}
}