using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Linq;
namespace UnityEngine.Rendering
{
///
/// This attribute allows you to add commands to the Add Override popup menu
/// on Volumes.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class VolumeComponentMenu : Attribute
{
///
/// The name of the entry in the override list. You can use slashes to create sub-menus.
///
public readonly string menu;
// TODO: Add support for component icons
///
/// Creates a new instance.
///
/// The name of the entry in the override list. You can use slashes to
/// create sub-menus.
public VolumeComponentMenu(string menu)
{
this.menu = menu;
}
}
///
/// An attribute set on deprecated volume components.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class VolumeComponentDeprecated : Attribute
{
}
///
/// The base class for all the components that can be part of a .
/// The Volume framework automatically handles and interpolates any members found in this class.
///
///
///
/// using UnityEngine.Rendering;
///
/// [Serializable, VolumeComponentMenu("Custom/Example Component")]
/// public class ExampleComponent : VolumeComponent
/// {
/// public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
/// }
///
///
[Serializable]
public class VolumeComponent : ScriptableObject
{
///
/// The active state of the set of parameters defined in this class. You can use this to
/// quickly turn on or off all the overrides at once.
///
public bool active = true;
///
/// The name displayed in the component header. If you do not set a name, Unity generates one from
/// the class name automatically.
///
public string displayName { get; protected set; } = "";
///
/// A read-only collection of all the s defined in this class.
///
public ReadOnlyCollection parameters { get; private set; }
#pragma warning disable 414
[SerializeField]
bool m_AdvancedMode = false; // Editor-only
#pragma warning restore 414
///
/// Unity calls this method when it loads the class.
///
///
/// If you want to override this method, you must call base.OnEnable().
///
protected virtual void OnEnable()
{
// Automatically grab all fields of type VolumeParameter for this instance
parameters = this.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(t => t.FieldType.IsSubclassOf(typeof(VolumeParameter)))
.OrderBy(t => t.MetadataToken) // Guaranteed order
.Select(t => (VolumeParameter)t.GetValue(this))
.ToList()
.AsReadOnly();
foreach (var parameter in parameters)
parameter.OnEnable();
}
///
/// Unity calls this method when the object goes out of scope.
///
protected virtual void OnDisable()
{
if (parameters == null)
return;
foreach (var parameter in parameters)
parameter.OnDisable();
}
///
/// Interpolates a with this component by an interpolation
/// factor and puts the result back into the given .
///
///
/// You can override this method to do your own blending. Either loop through the
/// list or reference direct fields. You should only use
/// to set parameter values and not assign
/// directly to the state object. you should also manually check
/// before you set any values.
///
/// The internal component to interpolate from. You must store
/// the result of the interpolation in this same component.
/// The interpolation factor in range [0,1].
///
/// Below is the default implementation for blending:
///
/// public virtual void Override(VolumeComponent state, float interpFactor)
/// {
/// int count = parameters.Count;
///
/// for (int i = 0; i < count; i++)
/// {
/// var stateParam = state.parameters[i];
/// var toParam = parameters[i];
///
/// // Keep track of the override state for debugging purpose
/// stateParam.overrideState = toParam.overrideState;
///
/// if (toParam.overrideState)
/// stateParam.Interp(stateParam, toParam, interpFactor);
/// }
/// }
///
///
public virtual void Override(VolumeComponent state, float interpFactor)
{
int count = parameters.Count;
for (int i = 0; i < count; i++)
{
var stateParam = state.parameters[i];
var toParam = parameters[i];
// Keep track of the override state for debugging purpose
stateParam.overrideState = toParam.overrideState;
if (toParam.overrideState)
stateParam.Interp(stateParam, toParam, interpFactor);
}
}
///
/// Sets the state of all the overrides on this component to a given value.
///
/// The value to set the state of the overrides to.
public void SetAllOverridesTo(bool state)
{
SetAllOverridesTo(parameters, state);
}
void SetAllOverridesTo(IEnumerable enumerable, bool state)
{
foreach (var prop in enumerable)
{
prop.overrideState = state;
var t = prop.GetType();
if (VolumeParameter.IsObjectParameter(t))
{
// This method won't be called a lot but this is sub-optimal, fix me
var innerParams = (ReadOnlyCollection)
t.GetProperty("parameters", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(prop, null);
if (innerParams != null)
SetAllOverridesTo(innerParams, state);
}
}
}
///
/// A custom hashing function that Unity uses to compare the state of parameters.
///
/// A computed hash code for the current instance.
public override int GetHashCode()
{
unchecked
{
//return parameters.Aggregate(17, (i, p) => i * 23 + p.GetHash());
int hash = 17;
for (int i = 0; i < parameters.Count; i++)
hash = hash * 23 + parameters[i].GetHashCode();
return hash;
}
}
}
}