示例#1
0
        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());
            }
        }
示例#3
0
        /// <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 Vector3)
              binding = new ConstParameterBinding<Vector3>(effect, parameter, (Vector3)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 Vector4)
              binding = new ConstParameterBinding<Vector4>(effect, parameter, (Vector4)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 Matrix)
              binding = new ConstParameterBinding<Matrix>(effect, parameter, (Matrix)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 Matrix)
              binding = new ConstParameterBinding<Matrix>(effect, parameter, (Matrix)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 Vector3[])
              binding = new ConstParameterArrayBinding<Vector3>(effect, parameter, (Vector3[])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 Vector4[])
              binding = new ConstParameterArrayBinding<Vector4>(effect, parameter, (Vector4[])value);
          }
        }
        else if (parameter.ParameterClass == EffectParameterClass.Matrix &&
                 parameter.ParameterType == EffectParameterType.Single)
        {
          //#if !XBOX
          // The type Matrix22F[], Matrix[], Matrix[] 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 Matrix[])
              binding = new ConstParameterArrayBinding<Matrix>(effect, parameter, (Matrix[])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 Matrix[])
                binding = new ConstParameterArrayBinding<Matrix>(effect, parameter, (Matrix[])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;
    }