private void GetCurrentCompatibilityBinding(out CompatibilitySetter compatibilityBinding) { lock (Lock) { if (CurrentCompatibilityBinding == null) { IsDirty = true; CreateCompatibilityBinding(out CurrentCompatibilityBinding); } compatibilityBinding = CurrentCompatibilityBinding; } }
// We use LCG to create a single throwaway delegate that is responsible for filling // all the relevant effect parameters with the value(s) of each field of the struct. private void CreateCompatibilityBinding(out CompatibilitySetter result) { var t = typeof(T); var tp = typeof(EffectParameter); var uniformParameter = Effect.Parameters[Name]; if (uniformParameter == null) { throw new Exception("Shader has no uniform named '" + Name + "'"); } if (uniformParameter.ParameterClass != EffectParameterClass.Struct) { throw new Exception("Shader uniform is not a struct"); } var pValue = Expression.Parameter(t.MakeByRefType(), "value"); var body = new List <Expression>(); foreach (var p in uniformParameter.StructureMembers) { var field = t.GetField(p.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new Exception(string.Format("No field named '{0}' found when binding type {1}", p.Name, t.Name)); } var setMethod = tp.GetMethod("SetValue", new[] { field.FieldType }); if (setMethod == null) { throw new Exception(string.Format("No setter for effect parameter type {0}", field.FieldType.Name)); } var vParameter = Expression.Constant(p, tp); var fieldValue = Expression.Field(pValue, field); body.Add(Expression.Call(vParameter, setMethod, fieldValue)); } var bodyBlock = Expression.Block(body); var expr = Expression.Lambda <CompatibilitySetter>(bodyBlock, pValue); result = expr.Compile(); }