public EffectBinding(IGraphicsService graphicsService, Effect effect, IDictionary <string, object> opaqueData, EffectParameterHint hints) { if (graphicsService == null) { throw new ArgumentNullException("graphicsService"); } if (effect == null) { throw new ArgumentNullException("effect"); } if (effect is AlphaTestEffect && !(effect is WrappedAlphaTestEffect) || effect is BasicEffect && !(effect is WrappedBasicEffect) || effect is DualTextureEffect && !(effect is WrappedDualTextureEffect) || effect is EnvironmentMapEffect && !(effect is WrappedEnvironmentMapEffect) || effect is SkinnedEffect && !(effect is WrappedSkinnedEffect)) { throw new ArgumentException("The EffectBinding class cannot be used with XNA stock effects (e.g. BasicEffect). Use a derived effect binding instead (e.g. BasicEffectBinding)."); } // Initialize additional information, if not already initialized. EffectEx = EffectEx.From(effect, graphicsService); if (KeepOpaqueData) { OpaqueData = opaqueData; } // Initialize effect bindings. ParameterBindings = new EffectParameterBindingCollection(hints); InitializeBindings(graphicsService, opaqueData); }
protected virtual void CloneCore(EffectBinding source) { EffectEx = source.EffectEx; MaterialBinding = source.MaterialBinding; // Note: MorphWeights need to be set by MeshNode. TechniqueBinding = source.TechniqueBinding.Clone(); OpaqueData = source.OpaqueData; UserData = source.UserData; // Clone parameter bindings (deep copy). ParameterBindings = new EffectParameterBindingCollection(source.Hints); foreach (var binding in source.ParameterBindings) { ParameterBindings.Add(binding.Clone()); } }
/// <summary> /// Initializes the <see cref="EffectEx"/>. /// </summary> /// <param name="graphicsService">The graphics service.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="graphicsService"/> is <see langword="null"/>. /// </exception> protected override void Initialize(IGraphicsService graphicsService) { if (graphicsService == null) { throw new ArgumentNullException("graphicsService"); } var effect = Resource; // When an Effect is used the original values of the effect parameters, as // specified in the .fx file, are lost. --> Store values in dictionary. OriginalParameterValues = EffectHelper.GetParameterValues(effect); TechniqueDescriptions = new EffectTechniqueDescriptionCollection(graphicsService, effect); TechniqueBinding = EffectHelper.CreateTechniqueBinding(graphicsService, effect); ParameterDescriptions = new EffectParameterDescriptionCollection(graphicsService, effect); ParameterBindings = new EffectParameterBindingCollection(EffectParameterHint.Any); EffectHelper.InitializeParameterBindings(graphicsService, this, null, ParameterBindings); }
private static void SetBinding(IGraphicsService graphicsService, EffectEx effectEx, IDictionary <string, object> opaqueData, EffectParameterBindingCollection bindings, EffectParameter parameter) { // Skip this parameter if we already have a binding. (Could be created in // derived classes that override OnInitializeBindings()). if (bindings.Contains(parameter)) { return; } // Get description. EffectParameterDescription description; effectEx.ParameterDescriptions.TryGet(parameter, out description); if (description != null) { // Check if parameter needs to be added to the bindings collection. if ((description.Hint & bindings.Hints) == 0) { return; } var effect = effectEx.Resource; // Try to get binding using the effect parameter binders. bool bindingCreated = SetAutomaticBinding(effect, parameter, graphicsService.EffectBinders, opaqueData, bindings); if (bindingCreated) { return; } // Look up effect parameter in opaque data. bindingCreated = SetOpaqueDataBinding(effect, parameter, opaqueData, bindings); if (bindingCreated) { return; } // Default: Use default value stored in .fx file. SetDefaultBinding(graphicsService, effectEx, parameter, description, bindings); } else { // Parameter has no description? This happens for structs and arrays of // structs. We bind the struct members directly. if (parameter.ParameterClass == EffectParameterClass.Struct) { if (parameter.Elements.Count > 0) { // Effect parameter is an array of structs. foreach (EffectParameter element in parameter.Elements) { foreach (EffectParameter member in element.StructureMembers) { SetBinding(graphicsService, effectEx, opaqueData, bindings, member); } } } else { // Effect parameter is a struct. foreach (EffectParameter member in parameter.StructureMembers) { SetBinding(graphicsService, effectEx, opaqueData, bindings, member); } } } } }
/// <summary> /// Initializes the bindings of the effect by calling the <see cref="IEffectBinder"/>s. /// </summary> /// <param name="graphicsService">The graphics service.</param> /// <param name="effectEx">The effect wrapper.</param> /// <param name="opaqueData">The opaque data.</param> /// <param name="bindings"> /// The collection that stores the resulting effect parameter bindings. /// </param> /// <remarks> /// If the <see cref="IEffectBinder"/>s do not return a binding, then this method creates /// default bindings using opaque data or the default values from the effect. /// </remarks> internal static void InitializeParameterBindings(IGraphicsService graphicsService, EffectEx effectEx, IDictionary <string, object> opaqueData, EffectParameterBindingCollection bindings) { foreach (var parameter in effectEx.Resource.Parameters) { SetBinding(graphicsService, effectEx, opaqueData, bindings, parameter); } }
private static void SetDefaultBinding(IGraphicsService graphicsService, EffectEx effectEx, EffectParameter parameter, EffectParameterDescription usage, EffectParameterBindingCollection bindings) { Debug.Assert(!bindings.Contains(parameter), "Effect binding already contains a binding for the given effect parameter."); if (parameter.ParameterClass == EffectParameterClass.Struct) { if (parameter.Elements.Count > 0) { // ----- Effect parameter is an array of structs. --> Recursively process elements of array. foreach (EffectParameter element in parameter.Elements) { SetDefaultBinding(graphicsService, effectEx, element, usage, bindings); } } else { // ----- Effect parameter is a struct. --> Recursively process members of struct. foreach (EffectParameter member in parameter.StructureMembers) { SetDefaultBinding(graphicsService, effectEx, member, usage, bindings); } } return; } // Set ConstParameterBinding using the default value stored in .fx file. var effect = effectEx.Resource; object originalValue; effectEx.OriginalParameterValues.TryGetValue(parameter, out originalValue); EffectParameterBinding binding = null; if (parameter.Elements.Count == 0) { // ----- Parameter is not an array. if (parameter.ParameterClass == EffectParameterClass.Scalar) { // Scalar values. if (parameter.ParameterType == EffectParameterType.Bool) { binding = new ConstParameterBinding <bool>(effect, parameter, (bool)originalValue); } else if (parameter.ParameterType == EffectParameterType.Int32) { binding = new ConstParameterBinding <int>(effect, parameter, (int)originalValue); } else if (parameter.ParameterType == EffectParameterType.Single) { binding = new ConstParameterBinding <float>(effect, parameter, (float)originalValue); } } else if (parameter.ParameterClass == EffectParameterClass.Vector && parameter.ParameterType == EffectParameterType.Single) { // Vector values. if (parameter.ColumnCount == 2 || parameter.RowCount == 2) { binding = new ConstParameterBinding <Vector2>(effect, parameter, (Vector2)originalValue); } else if (parameter.ColumnCount == 3 || parameter.RowCount == 3) { binding = new ConstParameterBinding <Vector3>(effect, parameter, (Vector3)originalValue); } else if (parameter.ColumnCount == 4 || parameter.RowCount == 4) { binding = new ConstParameterBinding <Vector4>(effect, parameter, (Vector4)originalValue); } } else if (parameter.ParameterClass == EffectParameterClass.Matrix && parameter.ParameterType == EffectParameterType.Single) { // Matrix value. binding = new ConstParameterBinding <Matrix>(effect, parameter, (Matrix)originalValue); } else if (parameter.ParameterClass == EffectParameterClass.Object) { // Object values. if (parameter.ParameterType == EffectParameterType.String) { binding = new ConstParameterBinding <string>(effect, parameter, (string)originalValue); } else if (parameter.ParameterType == EffectParameterType.Texture) { // A texture type but we are not sure which exact type. --> Try different types. try { binding = new ConstParameterBinding <Texture2D>(effect, parameter, graphicsService.GetDefaultTexture2DWhite()); } catch (Exception) { try { binding = new ConstParameterBinding <Texture3D>(effect, parameter, graphicsService.GetDefaultTexture3DWhite()); } catch (Exception) { try { binding = new ConstParameterBinding <TextureCube>(effect, parameter, graphicsService.GetDefaultTextureCubeWhite()); } catch (Exception) { // Default value for a parameter of type Texture could not be read from Effect. } } } } else if (parameter.ParameterType == EffectParameterType.Texture1D) { // NOTE: 1D textures are not supported in XNA. } else if (parameter.ParameterType == EffectParameterType.Texture2D) { binding = new ConstParameterBinding <Texture2D>(effect, parameter, graphicsService.GetDefaultTexture2DWhite()); } else if (parameter.ParameterType == EffectParameterType.Texture3D) { binding = new ConstParameterBinding <Texture3D>(effect, parameter, graphicsService.GetDefaultTexture3DWhite()); } else if (parameter.ParameterType == EffectParameterType.TextureCube) { binding = new ConstParameterBinding <TextureCube>(effect, parameter, graphicsService.GetDefaultTextureCubeWhite()); } } } else { // ----- Parameter is array. int length = parameter.Elements.Count; Debug.Assert(length > 0, "Effect parameter should be an array."); // Note: In XNA originalValue is valid. In MonoGame originalValue is null and we have to // create a new array! if (parameter.ParameterClass == EffectParameterClass.Scalar) { // Scalar value bindings. if (parameter.ParameterType == EffectParameterType.Bool) { binding = new ConstParameterArrayBinding <bool>(effect, parameter, (bool[])originalValue ?? new bool[parameter.Elements.Count]); } else if (parameter.ParameterType == EffectParameterType.Int32) { binding = new ConstParameterArrayBinding <int>(effect, parameter, (int[])originalValue ?? new int[parameter.Elements.Count]); } else if (parameter.ParameterType == EffectParameterType.Single) { binding = new ConstParameterArrayBinding <float>(effect, parameter, (float[])originalValue ?? new float[parameter.Elements.Count]); } } else if (parameter.ParameterClass == EffectParameterClass.Vector && parameter.ParameterType == EffectParameterType.Single) { if (parameter.ColumnCount == 2 || parameter.RowCount == 2) { binding = new ConstParameterArrayBinding <Vector2>(effect, parameter, (Vector2[])originalValue ?? new Vector2[parameter.Elements.Count]); } else if (parameter.ColumnCount == 3 || parameter.RowCount == 3) { binding = new ConstParameterArrayBinding <Vector3>(effect, parameter, (Vector3[])originalValue ?? new Vector3[parameter.Elements.Count]); } else if (parameter.ColumnCount == 4 || parameter.RowCount == 4) { binding = new ConstParameterArrayBinding <Vector4>(effect, parameter, (Vector4[])originalValue ?? new Vector4[parameter.Elements.Count]); } } else if (parameter.ParameterClass == EffectParameterClass.Matrix && parameter.ParameterType == EffectParameterType.Single) { binding = new ConstParameterArrayBinding <Matrix>(effect, parameter, (Matrix[])originalValue ?? new Matrix[parameter.Elements.Count]); } else if (parameter.ParameterClass == EffectParameterClass.Object) { // Note: Arrays of strings or textures are not supported in XNA. } } if (binding != null) { bindings.Add(binding); } }
private static bool SetOpaqueDataBinding(Effect effect, EffectParameter parameter, IDictionary <string, object> opaqueData, EffectParameterBindingCollection bindings) { Debug.Assert(!bindings.Contains(parameter), "Effect binding already contains a binding for the given effect parameter."); if (opaqueData == null || opaqueData.Count == 0) { // No opaque data. return(false); } if (parameter.ParameterClass == EffectParameterClass.Struct) { // Structs cannot be set from opaque data. return(false); } // Get value from opaque data. object value; bool valueFound = opaqueData.TryGetValue(parameter.Name, out value); if (!valueFound) { return(false); } EffectParameterBinding binding = null; if (parameter.Elements.Count == 0) { // ----- Parameter is not an array. if (parameter.ParameterClass == EffectParameterClass.Scalar) { // Scalar value bindings. if (parameter.ParameterType == EffectParameterType.Bool && ObjectHelper.IsConvertible(value)) { binding = new ConstParameterBinding <bool>(effect, parameter, ObjectHelper.ConvertTo <bool>(value, CultureInfo.InvariantCulture)); } else if (parameter.ParameterType == EffectParameterType.Int32 && ObjectHelper.IsConvertible(value)) { binding = new ConstParameterBinding <int>(effect, parameter, ObjectHelper.ConvertTo <int>(value, CultureInfo.InvariantCulture)); } else if (parameter.ParameterType == EffectParameterType.Single && ObjectHelper.IsConvertible(value)) { binding = new ConstParameterBinding <float>(effect, parameter, ObjectHelper.ConvertTo <float>(value, CultureInfo.InvariantCulture)); } } else if (parameter.ParameterClass == EffectParameterClass.Vector && parameter.ParameterType == EffectParameterType.Single) { if (parameter.ColumnCount == 2 || parameter.RowCount == 2) { if (value is Vector2) { binding = new ConstParameterBinding <Vector2>(effect, parameter, (Vector2)value); } else if (value is Vector2F) { binding = new ConstParameterBinding <Vector2F>(effect, parameter, (Vector2F)value); } } else if (parameter.ColumnCount == 3 || parameter.RowCount == 3) { if (value is Vector3) { binding = new ConstParameterBinding <Vector3>(effect, parameter, (Vector3)value); } else if (value is Vector3F) { binding = new ConstParameterBinding <Vector3F>(effect, parameter, (Vector3F)value); } } else if (parameter.ColumnCount == 4 || parameter.RowCount == 4) { if (value is Vector4) { binding = new ConstParameterBinding <Vector4>(effect, parameter, (Vector4)value); } else if (value is Vector4F) { binding = new ConstParameterBinding <Vector4F>(effect, parameter, (Vector4F)value); } } } else if (parameter.ParameterClass == EffectParameterClass.Matrix && parameter.ParameterType == EffectParameterType.Single) { if (parameter.ColumnCount == 2 && parameter.RowCount == 2) { if (value is Matrix22F) { binding = new ConstParameterBinding <Matrix22F>(effect, parameter, (Matrix22F)value); } } else if (parameter.ColumnCount == 3 && parameter.RowCount == 3) { if (value is Matrix33F) { binding = new ConstParameterBinding <Matrix33F>(effect, parameter, (Matrix33F)value); } } else if (parameter.ColumnCount == 4 || parameter.RowCount == 4) { if (value is Matrix) { binding = new ConstParameterBinding <Matrix>(effect, parameter, (Matrix)value); } else if (value is Matrix44F) { binding = new ConstParameterBinding <Matrix44F>(effect, parameter, (Matrix44F)value); } } } else if (parameter.ParameterClass == EffectParameterClass.Object) { if (parameter.ParameterType == EffectParameterType.String && value is string) { binding = new ConstParameterBinding <string>(effect, parameter, (string)value); } else if (parameter.ParameterType == EffectParameterType.Texture && value is Texture) { binding = new ConstParameterBinding <Texture>(effect, parameter, (Texture)value); } else if (parameter.ParameterType == EffectParameterType.Texture1D && value is Texture) { binding = null; // 1D textures are not supported in XNA. } else if (parameter.ParameterType == EffectParameterType.Texture2D && value is Texture2D) { binding = new ConstParameterBinding <Texture2D>(effect, parameter, (Texture2D)value); } else if (parameter.ParameterType == EffectParameterType.Texture3D && value is Texture3D) { binding = new ConstParameterBinding <Texture3D>(effect, parameter, (Texture3D)value); } else if (parameter.ParameterType == EffectParameterType.TextureCube && value is TextureCube) { binding = new ConstParameterBinding <TextureCube>(effect, parameter, (TextureCube)value); } } } else { // ----- Parameter is array. // TODO: We could also check whether the length of the arrays match. if (parameter.ParameterClass == EffectParameterClass.Scalar) { // Scalar value bindings. if (parameter.ParameterType == EffectParameterType.Bool && IsArray <bool>(value)) { binding = new ConstParameterArrayBinding <bool>(effect, parameter, ToBooleanArray(value)); } else if (parameter.ParameterType == EffectParameterType.Int32 && IsArray <int>(value)) { binding = new ConstParameterArrayBinding <int>(effect, parameter, ToInt32Array(value)); } else if (parameter.ParameterType == EffectParameterType.Single && IsArray <float>(value)) { binding = new ConstParameterArrayBinding <float>(effect, parameter, ToSingleArray(value)); } } else if (parameter.ParameterClass == EffectParameterClass.Vector && parameter.ParameterType == EffectParameterType.Single) { if (parameter.ColumnCount == 2 || parameter.RowCount == 2) { if (value is Vector2[]) { binding = new ConstParameterArrayBinding <Vector2>(effect, parameter, (Vector2[])value); } else if (value is Vector2F[]) { binding = new ConstParameterArrayBinding <Vector2F>(effect, parameter, (Vector2F[])value); } } else if (parameter.ColumnCount == 3 || parameter.RowCount == 3) { if (value is Vector3[]) { binding = new ConstParameterArrayBinding <Vector3>(effect, parameter, (Vector3[])value); } else if (value is Vector3F[]) { binding = new ConstParameterArrayBinding <Vector3F>(effect, parameter, (Vector3F[])value); } } else if (parameter.ColumnCount == 4 || parameter.RowCount == 4) { if (value is Vector4[]) { binding = new ConstParameterArrayBinding <Vector4>(effect, parameter, (Vector4[])value); } else if (value is Vector4F[]) { binding = new ConstParameterArrayBinding <Vector4F>(effect, parameter, (Vector4F[])value); } } } else if (parameter.ParameterClass == EffectParameterClass.Matrix && parameter.ParameterType == EffectParameterType.Single) { //#if !XBOX // The type Matrix22F[], Matrix33F[], Matrix44F[] caused a MissingMethodException at runtime on Xbox 360 in XNA 3.1. // See also: EffectParameterBinding<T>.SetValueMethods! if (parameter.ColumnCount == 2 && parameter.RowCount == 2) { if (value is Matrix22F[]) { binding = new ConstParameterArrayBinding <Matrix22F>(effect, parameter, (Matrix22F[])value); } } else if (parameter.ColumnCount == 3 && parameter.RowCount == 3) { if (value is Matrix33F[]) { binding = new ConstParameterArrayBinding <Matrix33F>(effect, parameter, (Matrix33F[])value); } } else //#endif if (parameter.ColumnCount == 4 || parameter.RowCount == 4) { if (value is Matrix[]) { binding = new ConstParameterArrayBinding <Matrix>(effect, parameter, (Matrix[])value); } //#if !XBOX else if (value is Matrix44F[]) { binding = new ConstParameterArrayBinding <Matrix44F>(effect, parameter, (Matrix44F[])value); } //#endif } } else if (parameter.ParameterClass == EffectParameterClass.Object) { if (parameter.ParameterType == EffectParameterType.String && value is string[]) { binding = new ConstParameterArrayBinding <string>(effect, parameter, (string[])value); } // Note: Arrays of textures are not supported in DirectX 9. } } if (binding != null) { bindings.Add(binding); return(true); } return(false); }
private static bool SetAutomaticBinding(Effect effect, EffectParameter parameter, IList <IEffectBinder> binders, IDictionary <string, object> opaqueData, EffectParameterBindingCollection bindings) { Debug.Assert(!bindings.Contains(parameter), "Effect binding already contains a binding for the given effect parameter."); // Loop through all IEffectParameterBinders and try to setup a valid binding. int numberOfBinders = binders.Count; for (int i = 0; i < numberOfBinders; i++) { EffectParameterBinding binding = binders[i].GetBinding(effect, parameter, opaqueData); if (binding != null) { bindings.Add(binding); return(true); } } return(false); }