using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aiwaz.Contracts; using Aiwaz.Core; using Aiwaz.Common; using System.Collections.ObjectModel; namespace Aiwaz.Resources { public class ShaderNotSetException : Exception {} public class UnsupportedShaderParameterTypeException : Exception {} [AiwazResource("Shader parameter set", "A set of parameters for one or more shaders.")] public class ShaderParameterSet : CommandUser, IShaderParameterSet { #region IShaderParameterSet Members const byte setShaderParameterCollectionCommandType = 0; const byte setFollowingShaderParameterCollectionCommandType = 1; private bool isPreconditionForFollowingShaders; private byte basePriority; protected BaseShaderParameterSet baseShaderParameterSet = new BaseShaderParameterSet(); public ShaderParameterSet() : this(4) { } protected ShaderParameterSet(byte basePriority) { this.basePriority = basePriority; this.IsPreconditionForFollowingShaders = false; } public bool IsPreconditionForFollowingShaders { get { return isPreconditionForFollowingShaders; } set { if (Commands.Count > 0 && value == isPreconditionForFollowingShaders) return; isPreconditionForFollowingShaders = value; Commands.Clear(); if (isPreconditionForFollowingShaders) Commands.Add(new Command(this, CommandFlags.EndChain | CommandFlags.FlushChain, setFollowingShaderParameterCollectionCommandType, 0, 0)); else Commands.Add(new Command(this, CommandFlags.None, setShaderParameterCollectionCommandType, basePriority, 0)); this.MarkCommandsAsDirty(); } } public void SetParameter(string parameterName, IShaderParameter parameter) { baseShaderParameterSet.SetShaderParameter(parameterName, parameter); } public void SetParameter(string parameterName, ITexture argParameter, ParameterBindType argParamNameType) { this.SetParameter(parameterName, new Reference(argParameter), argParamNameType); } public void SetParameter(string parameterName, float argParameter, ParameterBindType argParamNameType) { this.SetParameter(parameterName, new Reference(argParameter), argParamNameType); } public void SetParameter(string parameterName, SlimDX.Vector3 argParameter, ParameterBindType argParamNameType) { this.SetParameter(parameterName, new Reference(argParameter), argParamNameType); } public void SetParameter(string parameterName, SlimDX.Vector4 argParameter, ParameterBindType argParamNameType) { this.SetParameter(parameterName, new Reference(argParameter), argParamNameType); } public void SetParameter(string parameterName, SlimDX.Matrix argParameter, ParameterBindType argParamNameType) { this.SetParameter(parameterName, new Reference(argParameter), argParamNameType); } public void SetParameter(string parameterName, bool argParameter, ParameterBindType argParamNameType) { this.SetParameter(parameterName, new Reference(argParameter), argParamNameType); } public void SetParameter(string parameterName, Reference argParameter, ParameterBindType argParamNameType) { baseShaderParameterSet.SetShaderParameter(parameterName, new ShaderParameter(argParamNameType, argParameter)); } public void RemoveParameter(string name) { baseShaderParameterSet.RemoveShaderParameter(name); } #endregion public override CommandExecuteResult ExecuteCommand(byte commandType, CommandBuffer currentBuffer, int currentPositon) { if (commandType == setShaderParameterCollectionCommandType) { if (Engine.EngineStates.LastShader == null) throw new ShaderNotSetException(); baseShaderParameterSet.UseParametersOnShader(Engine.EngineStates.LastShader); } else if (commandType == setFollowingShaderParameterCollectionCommandType) { var shaders = currentBuffer.BufferedCommands.Where(c => c.Owner is IShader && c.Type == 0).Select(c => c.Owner as IShader); foreach (var shader in shaders) baseShaderParameterSet.UseParametersOnShader(shader); } return CommandExecuteResult.None; } #region IDisposable Members public override void Dispose() { base.Dispose(); } #endregion public override ICreationParams CreationParams { get { return null; } } public override ObservableCollection Children { get { return null; } } } public class BaseShaderParameterSet { Dictionary parameterMap = new Dictionary(); Dictionary>> shaderToParameterMap = new Dictionary>>(); public void UseParametersOnShader(IShader shader) { if (parameterMap.Count == 0) return; List> shaderParams = null; var searchedShaderPair = shaderToParameterMap.FirstOrDefault(a => a.Key.IsAlive && a.Key.Target == shader); if (searchedShaderPair.Key != null) shaderParams = searchedShaderPair.Value; if (shaderParams == null) { shaderParams = new List>(); // (re)create shader entries foreach (var parameter in parameterMap) if (parameter.Value != null) { SlimDX.Direct3D10.EffectVariable effectvar = null; if (parameter.Value.ParameterNameType == ParameterBindType.BindByVariable) effectvar = shader.Effect.GetVariableByName(parameter.Key); else if (parameter.Value.ParameterNameType == ParameterBindType.BindBySemantic) effectvar = shader.Effect.GetVariableBySemantic(parameter.Key); if (effectvar != null && effectvar.IsValid) shaderParams.Add(new Pair(parameter.Value, effectvar)); } if (shaderParams.Count == 0) return; shaderToParameterMap[new WeakReference(shader)] = shaderParams; } foreach (var parameter in shaderParams) parameter.First.ApplyValue(parameter.Second); } public void SetShaderParameter(string name, IShaderParameter parameter) { this.RemoveShaderParameter(name); parameterMap[name] = parameter; } public void RemoveShaderParameter(string name) { shaderToParameterMap.Clear(); parameterMap.Remove(name); } public void RemoveAllShaderParameters() { parameterMap.Clear(); shaderToParameterMap.Clear(); } } public class ShaderParameter : IShaderParameter { private enum ObjectType { Int, IntArray, Float, FloatArray, Bool, BoolArray, Vector2, Vector3, Vector4, Vector4Array, Matrix, MatrixArray, Texture } private Reference valueObject; private ObjectType type; public ShaderParameter(ParameterBindType parameterNameType, Reference valueObject) { this.ParameterNameType = parameterNameType; this.valueObject = valueObject; if (valueObject.RawValue is bool) this.type = ObjectType.Bool; else if (valueObject.RawValue is bool[]) this.type = ObjectType.BoolArray; else if (valueObject.RawValue is int) this.type = ObjectType.Int; else if (valueObject.RawValue is int[]) this.type = ObjectType.IntArray; else if (valueObject.RawValue is float) this.type = ObjectType.Float; else if (valueObject.RawValue is float[]) this.type = ObjectType.FloatArray; else if (valueObject.RawValue is SlimDX.Matrix) this.type = ObjectType.Matrix; else if (valueObject.RawValue is SlimDX.Matrix[]) this.type = ObjectType.MatrixArray; else if (valueObject.RawValue is SlimDX.Vector2) this.type = ObjectType.Vector2; else if (valueObject.RawValue is SlimDX.Vector3) this.type = ObjectType.Vector3; else if (valueObject.RawValue is SlimDX.Vector4) this.type = ObjectType.Vector4; else if (valueObject.RawValue is SlimDX.Vector4[]) this.type = ObjectType.Vector4Array; else if (valueObject.RawValue is ITexture) this.type = ObjectType.Texture; else throw new UnsupportedShaderParameterTypeException(); } #region IShaderParameter Members public ParameterBindType ParameterNameType { get; protected set; } public void ApplyValue(SlimDX.Direct3D10.EffectVariable variable) { switch (this.type) { case ObjectType.Bool: variable.AsScalar().Set((bool)valueObject.RawValue); break; case ObjectType.BoolArray: variable.AsScalar().Set((bool[])valueObject.RawValue); break; case ObjectType.Int: variable.AsScalar().Set((int)valueObject.RawValue); break; case ObjectType.IntArray: variable.AsScalar().Set((int[])valueObject.RawValue); break; case ObjectType.Float: variable.AsScalar().Set((float)valueObject.RawValue); break; case ObjectType.FloatArray: variable.AsScalar().Set((float[])valueObject.RawValue); break; case ObjectType.Vector2: variable.AsVector().Set((SlimDX.Vector2)valueObject.RawValue); break; case ObjectType.Vector3: variable.AsVector().Set((SlimDX.Vector3)valueObject.RawValue); break; case ObjectType.Vector4: variable.AsVector().Set((SlimDX.Vector4)valueObject.RawValue); break; case ObjectType.Vector4Array: variable.AsVector().Set((SlimDX.Vector4[])valueObject.RawValue); break; case ObjectType.Matrix: variable.AsMatrix().SetMatrix((SlimDX.Matrix)valueObject.RawValue); break; case ObjectType.MatrixArray: variable.AsMatrix().SetMatrix((SlimDX.Matrix[])valueObject.RawValue); break; case ObjectType.Texture: variable.AsResource().SetResource(((ITexture)valueObject.RawValue).ResourceView); break; } } #endregion } }