A game about forced loneliness, made by TACStudios
at master 347 lines 14 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Collections.ObjectModel; 4using System.Linq; 5using System.Reflection; 6 7namespace UnityEngine.Rendering 8{ 9 /// <summary> 10 /// This attribute allows you to add commands to the <b>Add Override</b> popup menu 11 /// on Volumes. 12 /// To filter VolumeComponentMenu based on current Render Pipeline, add SupportedOnRenderPipeline attribute to the class alongside with this attribute. 13 /// </summary> 14 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 15 public class VolumeComponentMenu : Attribute 16 { 17 /// <summary> 18 /// The name of the entry in the override list. You can use slashes to create sub-menus. 19 /// </summary> 20 public readonly string menu; 21 22 // TODO: Add support for component icons 23 24 /// <summary> 25 /// Creates a new <see cref="VolumeComponentMenu"/> instance. 26 /// </summary> 27 /// <param name="menu">The name of the entry in the override list. You can use slashes to 28 /// create sub-menus.</param> 29 public VolumeComponentMenu(string menu) 30 { 31 this.menu = menu; 32 } 33 } 34 35 /// <summary> 36 /// This attribute allows you to add commands to the <b>Add Override</b> popup menu 37 /// on Volumes and specify for which render pipelines will be supported 38 /// </summary> 39 [Obsolete(@"VolumeComponentMenuForRenderPipelineAttribute is deprecated. Use VolumeComponentMenu with SupportedOnCurrentPipeline instead. #from(2023.1)", false)] 40 public class VolumeComponentMenuForRenderPipeline : VolumeComponentMenu 41 { 42 /// <summary> 43 /// The list of pipeline types that the target class supports 44 /// </summary> 45 public Type[] pipelineTypes { get; } 46 47 /// <summary> 48 /// Creates a new <see cref="VolumeComponentMenuForRenderPipeline"/> instance. 49 /// </summary> 50 /// <param name="menu">The name of the entry in the override list. You can use slashes to 51 /// create sub-menus.</param> 52 /// <param name="pipelineTypes">The list of pipeline types that the target class supports</param> 53 public VolumeComponentMenuForRenderPipeline(string menu, params Type[] pipelineTypes) 54 : base(menu) 55 { 56 if (pipelineTypes == null) 57 throw new Exception("Specify a list of supported pipeline"); 58 59 // Make sure that we only allow the class types that inherit from the render pipeline 60 foreach (var t in pipelineTypes) 61 { 62 if (!typeof(RenderPipeline).IsAssignableFrom(t)) 63 throw new Exception( 64 $"You can only specify types that inherit from {typeof(RenderPipeline)}, please check {t}"); 65 } 66 67 this.pipelineTypes = pipelineTypes; 68 } 69 } 70 71 72 /// <summary> 73 /// An attribute to hide the volume component to be added through `Add Override` button on the volume component list 74 /// </summary> 75 [AttributeUsage(AttributeTargets.Class)] 76 [Obsolete("VolumeComponentDeprecated has been deprecated (UnityUpgradable) -> [UnityEngine] UnityEngine.HideInInspector", false)] 77 public sealed class VolumeComponentDeprecated : Attribute 78 { 79 } 80 81 /// <summary> 82 /// The base class for all the components that can be part of a <see cref="VolumeProfile"/>. 83 /// The Volume framework automatically handles and interpolates any <see cref="VolumeParameter"/> members found in this class. 84 /// </summary> 85 /// <example> 86 /// <code> 87 /// using UnityEngine.Rendering; 88 /// 89 /// [Serializable, VolumeComponentMenuForRenderPipeline("Custom/Example Component")] 90 /// public class ExampleComponent : VolumeComponent 91 /// { 92 /// public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f); 93 /// } 94 /// </code> 95 /// </example> 96 [Serializable] 97 public partial class VolumeComponent : ScriptableObject 98 { 99 /// <summary> 100 /// Local attribute for VolumeComponent fields only. 101 /// It handles relative indentation of a property for inspector. 102 /// </summary> 103 public sealed class Indent : PropertyAttribute 104 { 105 /// <summary> Relative indent amount registered in this attribute </summary> 106 public readonly int relativeAmount; 107 108 /// <summary> Constructor </summary> 109 /// <param name="relativeAmount">Relative indent change to use</param> 110 public Indent(int relativeAmount = 1) 111 => this.relativeAmount = relativeAmount; 112 } 113 114 /// <summary> 115 /// The active state of the set of parameters defined in this class. You can use this to 116 /// quickly turn on or off all the overrides at once. 117 /// </summary> 118 public bool active = true; 119 120 /// <summary> 121 /// The name displayed in the component header. If you do not set a name, Unity generates one from 122 /// the class name automatically. 123 /// </summary> 124 public string displayName { get; protected set; } = ""; 125 126 /// <summary> 127 /// The backing storage of <see cref="parameters"/>. Use this for performance-critical work. 128 /// </summary> 129 internal readonly List<VolumeParameter> parameterList = new(); 130 131 ReadOnlyCollection<VolumeParameter> m_ParameterReadOnlyCollection; 132 /// <summary> 133 /// A read-only collection of all the <see cref="VolumeParameter"/>s defined in this class. 134 /// </summary> 135 public ReadOnlyCollection<VolumeParameter> parameters 136 { 137 get 138 { 139 if (m_ParameterReadOnlyCollection == null) 140 m_ParameterReadOnlyCollection = parameterList.AsReadOnly(); 141 return m_ParameterReadOnlyCollection; 142 } 143 } 144 145 /// <summary> 146 /// Extracts all the <see cref="VolumeParameter"/>s defined in this class and nested classes. 147 /// </summary> 148 /// <param name="o">The object to find the parameters</param> 149 /// <param name="parameters">The list filled with the parameters.</param> 150 /// <param name="filter">If you want to filter the parameters</param> 151 internal static void FindParameters(object o, List<VolumeParameter> parameters, Func<FieldInfo, bool> filter = null) 152 { 153 if (o == null) 154 return; 155 156 var fields = o.GetType() 157 .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) 158 .OrderBy(t => t.MetadataToken); // Guaranteed order 159 160 foreach (var field in fields) 161 { 162 if (field.FieldType.IsSubclassOf(typeof(VolumeParameter))) 163 { 164 if (filter?.Invoke(field) ?? true) 165 { 166 VolumeParameter volumeParameter = (VolumeParameter)field.GetValue(o); 167 parameters.Add(volumeParameter); 168 } 169 } 170 else if (!field.FieldType.IsArray && field.FieldType.IsClass) 171 FindParameters(field.GetValue(o), parameters, filter); 172 } 173 } 174 175 /// <summary> 176 /// Unity calls this method when it loads the class. 177 /// </summary> 178 /// <remarks> 179 /// If you want to override this method, you must call <c>base.OnEnable()</c>. 180 /// </remarks> 181 protected virtual void OnEnable() 182 { 183 // Automatically grab all fields of type VolumeParameter for this instance 184 parameterList.Clear(); 185 FindParameters(this, parameterList); 186 187 foreach (var parameter in parameterList) 188 { 189 if (parameter != null) 190 parameter.OnEnable(); 191 else 192 Debug.LogWarning("Volume Component " + GetType().Name + " contains a null parameter; please make sure all parameters are initialized to a default value. Until this is fixed the null parameters will not be considered by the system."); 193 } 194 } 195 196 /// <summary> 197 /// Unity calls this method when the object goes out of scope. 198 /// </summary> 199 protected virtual void OnDisable() 200 { 201 foreach (var parameter in parameterList) 202 { 203 if (parameter != null) 204 parameter.OnDisable(); 205 } 206 } 207 208 /// <summary> 209 /// Interpolates a <see cref="VolumeComponent"/> with this component by an interpolation 210 /// factor and puts the result back into the given <see cref="VolumeComponent"/>. 211 /// </summary> 212 /// <remarks> 213 /// You can override this method to do your own blending. Either loop through the 214 /// <see cref="parameters"/> list or reference direct fields. You should only use 215 /// <see cref="VolumeParameter.SetValue"/> to set parameter values and not assign 216 /// directly to the state object. you should also manually check 217 /// <see cref="VolumeParameter.overrideState"/> before you set any values. 218 /// </remarks> 219 /// <param name="state">The internal component to interpolate from. You must store 220 /// the result of the interpolation in this same component.</param> 221 /// <param name="interpFactor">The interpolation factor in range [0,1].</param> 222 /// <example> 223 /// <para> Below is the default implementation for blending:</para> 224 /// <code> 225 /// public virtual void Override(VolumeComponent state, float interpFactor) 226 /// { 227 /// int count = parameters.Count; 228 /// 229 /// for (int i = 0; i &lt; count; i++) 230 /// { 231 /// var stateParam = state.parameters[i]; 232 /// var toParam = parameters[i]; 233 /// 234 /// if (toParam.overrideState) 235 /// { 236 /// // Keep track of the override state to ensure that state will be reset on next frame (and for debugging purpose) 237 /// stateParam.overrideState = toParam.overrideState; 238 /// stateParam.Interp(stateParam, toParam, interpFactor); 239 /// } 240 /// } 241 /// } 242 /// </code> 243 /// </example> 244 public virtual void Override(VolumeComponent state, float interpFactor) 245 { 246 int count = parameterList.Count; 247 248 for (int i = 0; i < count; i++) 249 { 250 var stateParam = state.parameterList[i]; 251 var toParam = parameterList[i]; 252 253 if (toParam.overrideState) 254 { 255 // Keep track of the override state to ensure that state will be reset on next frame (and for debugging purpose) 256 stateParam.overrideState = toParam.overrideState; 257 stateParam.Interp(stateParam, toParam, interpFactor); 258 } 259 } 260 } 261 262 /// <summary> 263 /// Sets the state of all the overrides on this component to a given value. 264 /// </summary> 265 /// <param name="state">The value to set the state of the overrides to.</param> 266 public void SetAllOverridesTo(bool state) 267 { 268 SetOverridesTo(parameterList, state); 269 } 270 271 /// <summary> 272 /// Sets the override state of the given parameters on this component to a given value. 273 /// </summary> 274 /// <param name="state">The value to set the state of the overrides to.</param> 275 internal void SetOverridesTo(IEnumerable<VolumeParameter> enumerable, bool state) 276 { 277 foreach (var prop in enumerable) 278 { 279 prop.overrideState = state; 280 var t = prop.GetType(); 281 282 if (VolumeParameter.IsObjectParameter(t)) 283 { 284 // This method won't be called a lot but this is sub-optimal, fix me 285 var innerParams = (ReadOnlyCollection<VolumeParameter>) 286 t.GetProperty("parameters", BindingFlags.NonPublic | BindingFlags.Instance) 287 .GetValue(prop, null); 288 289 if (innerParams != null) 290 SetOverridesTo(innerParams, state); 291 } 292 } 293 } 294 295 /// <summary> 296 /// A custom hashing function that Unity uses to compare the state of parameters. 297 /// </summary> 298 /// <returns>A computed hash code for the current instance.</returns> 299 public override int GetHashCode() 300 { 301 unchecked 302 { 303 //return parameters.Aggregate(17, (i, p) => i * 23 + p.GetHash()); 304 305 int hash = 17; 306 307 for (int i = 0; i < parameterList.Count; i++) 308 hash = hash * 23 + parameterList[i].GetHashCode(); 309 310 return hash; 311 } 312 } 313 314 /// <summary> 315 /// Returns true if any of the volume properites has been overridden. 316 /// </summary> 317 /// <returns>True if any of the volume properites has been overridden.</returns> 318 public bool AnyPropertiesIsOverridden() 319 { 320 for (int i = 0; i < parameterList.Count; ++i) 321 { 322 if (parameterList[i].overrideState) return true; 323 } 324 return false; 325 } 326 327 /// <summary> 328 /// Unity calls this method before the object is destroyed. 329 /// </summary> 330 protected virtual void OnDestroy() => Release(); 331 332 /// <summary> 333 /// Releases all the allocated resources. 334 /// </summary> 335 public void Release() 336 { 337 if (parameterList == null) 338 return; 339 340 for (int i = 0; i < parameterList.Count; i++) 341 { 342 if (parameterList[i] != null) 343 parameterList[i].Release(); 344 } 345 } 346 } 347}