/// <summary> /// Extracts all the <see cref="VolumeParameter"/>s defined in this class and nested classes. /// </summary> /// <param name="o">The object to find the parameters</param> /// <param name="parameters">The list filled with the parameters.</param> /// <param name="filter">If you want to filter the parameters</param> internal static void FindParameters(object o, List <VolumeParameter> parameters, Func <FieldInfo, bool> filter = null) { if (o == null) { return; } var fields = o.GetType() .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .OrderBy(t => t.MetadataToken); // Guaranteed order foreach (var field in fields) { if (field.FieldType.IsSubclassOf(typeof(VolumeParameter))) { if (filter?.Invoke(field) ?? true) { VolumeParameter volumeParameter = (VolumeParameter)field.GetValue(o); parameters.Add(volumeParameter); } } else if (!field.FieldType.IsArray && field.FieldType.IsClass) { FindParameters(field.GetValue(o), parameters, filter); } } }
internal override void Interp(VolumeParameter from, VolumeParameter to, float t) { if (m_Value == null) { return; } var paramOrigin = parameters; var paramFrom = ((ObjectParameter <T>)from).parameters; var paramTo = ((ObjectParameter <T>)to).parameters; for (int i = 0; i < paramFrom.Count; i++) { if (paramOrigin[i].overrideState) { paramOrigin[i].Interp(paramFrom[i], paramTo[i], t); } } }
void SetAllOverridesTo(IEnumerable <VolumeParameter> 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 <VolumeParameter>) t.GetProperty("parameters", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(prop, null); if (innerParams != null) { SetAllOverridesTo(innerParams, state); } } } }
internal abstract void SetValue(VolumeParameter parameter);
internal abstract void Interp(VolumeParameter from, VolumeParameter to, float t);
public static DebugUI.Table CreateVolumeTable(DebugDisplaySettingsVolume data) { var table = new DebugUI.Table() { displayName = Strings.parameter, isReadOnly = true }; Type selectedType = data.volumeDebugSettings.selectedComponentType; if (selectedType == null) { return(table); } var stack = data.volumeDebugSettings.selectedCameraVolumeStack ?? VolumeManager.instance.stack; var stackComponent = stack.GetComponent(selectedType); if (stackComponent == null) { return(table); } var volumes = data.volumeDebugSettings.GetVolumes(); var inst = (VolumeComponent)ScriptableObject.CreateInstance(selectedType); // First row for volume info float timer = 0.0f, refreshRate = 0.2f; var row = new DebugUI.Table.Row() { displayName = Strings.volumeInfo, opened = true, // Open by default for the in-game view children = { new DebugUI.Value() { displayName = Strings.interpolatedValue, getter = () => { // This getter is called first at each render // It is used to update the volumes if (Time.time - timer < refreshRate) { return(string.Empty); } timer = Time.deltaTime; if (data.volumeDebugSettings.selectedCamera != null) { var newVolumes = data.volumeDebugSettings.GetVolumes(); if (!data.volumeDebugSettings.RefreshVolumes(newVolumes)) { for (int i = 0; i < newVolumes.Length; i++) { var visible = data.volumeDebugSettings.VolumeHasInfluence(newVolumes[i]); table.SetColumnVisibility(i + 1, visible); } return(string.Empty); } } DebugManager.instance.ReDrawOnScreenDebug(); return(string.Empty); } } } }; // Second row, links to volume gameobjects var row2 = new DebugUI.Table.Row() { displayName = "GameObject", children = { new DebugUI.Value() { getter = () => string.Empty } } }; foreach (var volume in volumes) { var profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile; row.children.Add(new DebugUI.Value() { displayName = profile.name, getter = () => { var scope = volume.isGlobal ? Strings.global : Strings.local; var weight = data.volumeDebugSettings.GetVolumeWeight(volume); return(scope + " (" + (weight * 100f) + "%)"); } }); row2.children.Add(new DebugUI.ObjectField() { displayName = profile.name, getter = () => volume, }); } row.children.Add(new DebugUI.Value() { displayName = Strings.defaultValue, getter = () => string.Empty }); table.children.Add(row); row2.children.Add(new DebugUI.Value() { getter = () => string.Empty }); table.children.Add(row2); // Build rows - recursively handles nested parameters var rows = new List <DebugUI.Table.Row>(); void AddParameterRows(Type type, string baseName = null) { void AddRow(FieldInfo f, string prefix) { var fieldName = prefix + f.Name; var attr = (DisplayInfoAttribute[])f.GetCustomAttributes(typeof(DisplayInfoAttribute), true); if (attr.Length != 0) { fieldName = prefix + attr[0].name; } #if UNITY_EDITOR // Would be nice to have the equivalent for the runtime debug. else { fieldName = UnityEditor.ObjectNames.NicifyVariableName(fieldName); } #endif int currentParam = rows.Count; row = new DebugUI.Table.Row() { displayName = fieldName, children = { CreateVolumeParameterWidget(Strings.interpolatedValue, stackComponent.parameters[currentParam]) }, }; foreach (var volume in volumes) { VolumeParameter param = null; var profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile; if (profile.TryGet(selectedType, out VolumeComponent component)) { param = component.parameters[currentParam]; } row.children.Add(CreateVolumeParameterWidget(volume.name + " (" + profile.name + ")", param, () => !component.parameters[currentParam].overrideState)); } row.children.Add(CreateVolumeParameterWidget(Strings.defaultValue, inst.parameters[currentParam])); rows.Add(row); } var fields = type .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .OrderBy(t => t.MetadataToken); foreach (var field in fields) { if (field.GetCustomAttributes(typeof(ObsoleteAttribute), false).Length != 0) { continue; } var fieldType = field.FieldType; if (fieldType.IsSubclassOf(typeof(VolumeParameter))) { AddRow(field, baseName ?? string.Empty); } else if (!fieldType.IsArray && fieldType.IsClass) { AddParameterRows(fieldType, baseName ?? (field.Name + " ")); } } } AddParameterRows(selectedType); foreach (var r in rows.OrderBy(t => t.displayName)) { table.children.Add(r); } data.volumeDebugSettings.RefreshVolumes(volumes); for (int i = 0; i < volumes.Length; i++) { table.SetColumnVisibility(i + 1, data.volumeDebugSettings.VolumeHasInfluence(volumes[i])); } return(table); }
static DebugUI.Widget CreateVolumeParameterWidget(string name, VolumeParameter param, Func <bool> isHiddenCallback = null) { if (param == null) { return new DebugUI.Value() { displayName = name, getter = () => "-" } } ; var parameterType = param.GetType(); // Special overrides if (parameterType == typeof(ColorParameter)) { var p = (ColorParameter)param; return(new DebugUI.ColorField() { displayName = name, hdr = p.hdr, showAlpha = p.showAlpha, getter = () => p.value, setter = value => p.value = value, isHiddenCallback = isHiddenCallback }); } else if (parameterType == typeof(BoolParameter)) { var p = (BoolParameter)param; return(new DebugUI.BoolField() { displayName = name, getter = () => p.value, setter = value => p.value = value, isHiddenCallback = isHiddenCallback }); } else { var typeInfo = parameterType.GetTypeInfo(); var genericArguments = typeInfo.BaseType.GenericTypeArguments; if (genericArguments.Length > 0 && genericArguments[0].IsArray) { return(new DebugUI.ObjectListField() { displayName = name, getter = () => (Object[])parameterType.GetProperty("value").GetValue(param, null), type = parameterType }); } } // For parameters that do not override `ToString` var property = param.GetType().GetProperty("value"); var toString = property.PropertyType.GetMethod("ToString", Type.EmptyTypes); if ((toString == null) || (toString.DeclaringType == typeof(object)) || (toString.DeclaringType == typeof(UnityEngine.Object))) { // Check if the parameter has a name var nameProp = property.PropertyType.GetProperty("name"); if (nameProp == null) { return new DebugUI.Value() { displayName = name, getter = () => Strings.debugViewNotSupported } } ; // Return the parameter name return(new DebugUI.Value() { displayName = name, getter = () => { var value = property.GetValue(param); if (value == null || value.Equals(null)) { return Strings.none; } var valueString = nameProp.GetValue(value); return valueString ?? Strings.none; }, isHiddenCallback = isHiddenCallback }); } // Call the ToString method return(new DebugUI.Value() { displayName = name, getter = () => { var value = property.GetValue(param); return value == null ? Strings.none : value.ToString(); }, isHiddenCallback = isHiddenCallback }); }