669 lines
28 KiB
C#
669 lines
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition
|
|
{
|
|
/// <summary>
|
|
/// Formats the provided descriptor into a linear slider with contextual slider markers, tooltips, and icons.
|
|
/// </summary>
|
|
class LightUnitSlider
|
|
{
|
|
protected SerializedObject m_SerializedObject;
|
|
|
|
static class SliderConfig
|
|
{
|
|
public const float k_IconSeparator = 0;
|
|
public const float k_MarkerWidth = 2;
|
|
public const float k_MarkerHeight = 2;
|
|
public const float k_MarkerTooltipScale = 4;
|
|
public const float k_ThumbTooltipSize = 10;
|
|
public const float k_KnobSize = 10;
|
|
}
|
|
|
|
protected static class SliderStyles
|
|
{
|
|
public static GUIStyle k_IconButton = new GUIStyle("IconButton");
|
|
public static GUIStyle k_TemperatureBorder = new GUIStyle("ColorPickerSliderBackground");
|
|
public static GUIStyle k_TemperatureThumb = new GUIStyle("ColorPickerHorizThumb");
|
|
}
|
|
|
|
protected readonly LightUnitSliderUIDescriptor m_Descriptor;
|
|
|
|
public LightUnitSlider(LightUnitSliderUIDescriptor descriptor)
|
|
{
|
|
m_Descriptor = descriptor;
|
|
}
|
|
|
|
public void SetSerializedObject(SerializedObject serialized)
|
|
{
|
|
m_SerializedObject = serialized;
|
|
}
|
|
|
|
public virtual void Draw(Rect rect, SerializedProperty value, ref float floatValue)
|
|
{
|
|
BuildRects(rect, out var sliderRect, out var iconRect);
|
|
|
|
if (m_Descriptor.clampValue)
|
|
ClampValue(ref floatValue, m_Descriptor.sliderRange);
|
|
|
|
var level = CurrentRange(floatValue);
|
|
|
|
DoSlider(sliderRect, ref floatValue, m_Descriptor.sliderRange, level.value);
|
|
|
|
if (m_Descriptor.hasMarkers)
|
|
{
|
|
foreach (var r in m_Descriptor.valueRanges)
|
|
{
|
|
var markerValue = r.value.y;
|
|
var markerPosition = GetPositionOnSlider(markerValue, r.value);
|
|
var markerTooltip = r.content.tooltip;
|
|
DoSliderMarker(sliderRect, markerPosition, markerValue, markerTooltip);
|
|
}
|
|
}
|
|
|
|
var levelIconContent = level.content;
|
|
var levelRange = level.value;
|
|
DoIcon(iconRect, levelIconContent, value, floatValue, levelRange.y);
|
|
|
|
var thumbValue = floatValue;
|
|
var thumbPosition = GetPositionOnSlider(thumbValue, level.value);
|
|
var thumbTooltip = levelIconContent.tooltip;
|
|
DoThumbTooltip(sliderRect, thumbPosition, thumbValue, thumbTooltip);
|
|
}
|
|
|
|
LightUnitSliderUIRange CurrentRange(float value)
|
|
{
|
|
foreach (var l in m_Descriptor.valueRanges)
|
|
{
|
|
if (value >= l.value.x && value <= l.value.y)
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
|
|
var cautionValue = value < m_Descriptor.sliderRange.x ? m_Descriptor.sliderRange.x : m_Descriptor.sliderRange.y;
|
|
var cautionTooltip = value < m_Descriptor.sliderRange.x ? m_Descriptor.belowRangeTooltip : m_Descriptor.aboveRangeTooltip;
|
|
return LightUnitSliderUIRange.CautionRange(cautionTooltip, cautionValue);
|
|
}
|
|
|
|
void BuildRects(Rect baseRect, out Rect sliderRect, out Rect iconRect)
|
|
{
|
|
sliderRect = baseRect;
|
|
sliderRect.width -= EditorGUIUtility.singleLineHeight + SliderConfig.k_IconSeparator;
|
|
|
|
iconRect = baseRect;
|
|
iconRect.x += sliderRect.width + SliderConfig.k_IconSeparator;
|
|
iconRect.width = EditorGUIUtility.singleLineHeight;
|
|
}
|
|
|
|
void ClampValue(ref float value, Vector2 range) =>
|
|
value = Mathf.Clamp(value, range.x, range.y);
|
|
|
|
private static Color k_DarkThemeColor = new Color32(153, 153, 153, 255);
|
|
private static Color k_LiteThemeColor = new Color32(97, 97, 97, 255);
|
|
static Color GetMarkerColor() => EditorGUIUtility.isProSkin ? k_DarkThemeColor : k_LiteThemeColor;
|
|
|
|
void DoSliderMarker(Rect rect, float position, float value, string tooltip)
|
|
{
|
|
const float width = SliderConfig.k_MarkerWidth;
|
|
const float height = SliderConfig.k_MarkerHeight;
|
|
|
|
var markerRect = rect;
|
|
markerRect.width = width;
|
|
markerRect.height = height;
|
|
|
|
// Vertically align with slider.
|
|
markerRect.y += (EditorGUIUtility.singleLineHeight / 2f) - 1;
|
|
|
|
// Horizontally place on slider. We need to take into account the "knob" size when doing this, because position 0 and 1 starts
|
|
// at the center of the knob when it's placed at the left and right corner respectively. We don't do this adjustment when placing
|
|
// the marker at the corners (to avoid havind the slider slightly extend past the marker)
|
|
float knobSize = (position > 0f && position < 1f) ? SliderConfig.k_KnobSize : 0f;
|
|
float start = rect.x + knobSize / 2f;
|
|
float range = rect.width - knobSize;
|
|
markerRect.x = start + range * position;
|
|
|
|
// Center the marker on value.
|
|
const float halfWidth = width * 0.5f;
|
|
markerRect.x -= halfWidth;
|
|
|
|
// Clamp to the slider edges.
|
|
float min = rect.x;
|
|
float max = (rect.x + rect.width) - width;
|
|
markerRect.x = Mathf.Clamp(markerRect.x, min, max);
|
|
|
|
// Draw marker by manually drawing the rect, and an empty label with the tooltip.
|
|
EditorGUI.DrawRect(markerRect, GetMarkerColor());
|
|
|
|
// Scale the marker tooltip for easier discovery
|
|
const float markerTooltipRectScale = SliderConfig.k_MarkerTooltipScale;
|
|
var markerTooltipRect = markerRect;
|
|
markerTooltipRect.width *= markerTooltipRectScale;
|
|
markerTooltipRect.height *= markerTooltipRectScale;
|
|
markerTooltipRect.x -= (markerTooltipRect.width * 0.5f) - 1;
|
|
markerTooltipRect.y -= (markerTooltipRect.height * 0.5f) - 1;
|
|
EditorGUI.LabelField(markerTooltipRect, GetLightUnitTooltip(tooltip, value, m_Descriptor.unitName));
|
|
}
|
|
|
|
void DoIcon(Rect rect, GUIContent icon, SerializedProperty value, float floatValue, float range)
|
|
{
|
|
// Draw the context menu feedback before the icon
|
|
GUI.Box(rect, GUIContent.none, SliderStyles.k_IconButton);
|
|
|
|
var oldColor = GUI.color;
|
|
GUI.color = Color.clear;
|
|
EditorGUI.DrawTextureTransparent(rect, icon.image);
|
|
GUI.color = oldColor;
|
|
|
|
EditorGUI.LabelField(rect, GetLightUnitTooltip(icon.tooltip, range, m_Descriptor.unitName));
|
|
|
|
// Handle events for context menu
|
|
var e = Event.current;
|
|
if (e.type == EventType.MouseDown && e.button == 0)
|
|
{
|
|
if (rect.Contains(e.mousePosition))
|
|
{
|
|
var menuPosition = rect.position + rect.size;
|
|
DoContextMenu(menuPosition, value, floatValue);
|
|
e.Use();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoContextMenu(Vector2 pos, SerializedProperty value, float floatValue)
|
|
{
|
|
var menu = new GenericMenu();
|
|
|
|
foreach (var preset in m_Descriptor.valueRanges)
|
|
{
|
|
// Indicate a checkmark if the value is within this preset range.
|
|
var isInPreset = CurrentRange(floatValue).value == preset.value;
|
|
|
|
menu.AddItem(EditorGUIUtility.TrTextContent(preset.content.tooltip), isInPreset, () => SetValueToPreset(value, preset));
|
|
}
|
|
|
|
menu.DropDown(new Rect(pos, Vector2.zero));
|
|
}
|
|
|
|
void DoThumbTooltip(Rect rect, float position, float value, string tooltip)
|
|
{
|
|
const float size = SliderConfig.k_ThumbTooltipSize;
|
|
const float halfSize = SliderConfig.k_ThumbTooltipSize * 0.5f;
|
|
|
|
var thumbMarkerRect = rect;
|
|
thumbMarkerRect.width = size;
|
|
thumbMarkerRect.height = size;
|
|
|
|
// Vertically align with slider
|
|
thumbMarkerRect.y += halfSize - 1f;
|
|
|
|
// Horizontally place tooltip on the wheel,
|
|
thumbMarkerRect.x = rect.x + (rect.width - size) * position;
|
|
|
|
EditorGUI.LabelField(thumbMarkerRect, GetLightUnitTooltip(tooltip, value, m_Descriptor.unitName));
|
|
}
|
|
|
|
protected virtual void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
|
|
{
|
|
m_SerializedObject?.Update();
|
|
|
|
// Set the value to the average of the preset range.
|
|
value.floatValue = preset.presetValue;
|
|
|
|
m_SerializedObject?.ApplyModifiedProperties();
|
|
}
|
|
|
|
protected virtual GUIContent GetLightUnitTooltip(string baseTooltip, float value, string unit)
|
|
{
|
|
var formatValue = value < 100 ? $"{value:n}" : $"{value:n0}";
|
|
var tooltip = $"{baseTooltip} | {formatValue} {unit}";
|
|
return new GUIContent(string.Empty, tooltip);
|
|
}
|
|
|
|
protected virtual void DoSlider(Rect rect, ref float value, Vector2 sliderRange, Vector2 valueRange)
|
|
{
|
|
DoSlider(rect, ref value, sliderRange);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws a linear slider mapped to the min/max value range. Override this for different slider behavior (texture background, power).
|
|
/// </summary>
|
|
protected virtual void DoSlider(Rect rect, ref float value, Vector2 sliderRange)
|
|
{
|
|
value = GUI.HorizontalSlider(rect, value, sliderRange.x, sliderRange.y);
|
|
}
|
|
|
|
// Remaps value in the domain { Min0, Max0 } to { Min1, Max1 } (by default, normalizes it to (0, 1).
|
|
static float Remap(float v, float x0, float y0, float x1 = 0f, float y1 = 1f) => x1 + (v - x0) * (y1 - x1) / (y0 - x0);
|
|
|
|
protected virtual float GetPositionOnSlider(float value, Vector2 valueRange)
|
|
{
|
|
return GetPositionOnSlider(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps a light unit value onto the slider. Keeps in sync placement of markers and tooltips with the slider power.
|
|
/// Override this in case of non-linear slider.
|
|
/// </summary>
|
|
protected virtual float GetPositionOnSlider(float value)
|
|
{
|
|
return Remap(value, m_Descriptor.sliderRange.x, m_Descriptor.sliderRange.y);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats the provided descriptor into a piece-wise linear slider with contextual slider markers, tooltips, and icons.
|
|
/// </summary>
|
|
class PiecewiseLightUnitSlider : LightUnitSlider
|
|
{
|
|
struct Piece
|
|
{
|
|
public Vector2 domain;
|
|
public Vector2 range;
|
|
|
|
public float directM;
|
|
public float directB;
|
|
public float inverseM;
|
|
public float inverseB;
|
|
}
|
|
|
|
// Piecewise function indexed by value ranges.
|
|
private readonly Dictionary<Vector2, Piece> m_PiecewiseFunctionMap = new Dictionary<Vector2, Piece>();
|
|
|
|
static void ComputeTransformationParameters(float x0, float x1, float y0, float y1, out float m, out float b)
|
|
{
|
|
m = (y0 - y1) / (x0 - x1);
|
|
b = (m * -x0) + y0;
|
|
}
|
|
|
|
static float DoTransformation(in float x, in float m, in float b) => (m * x) + b;
|
|
|
|
// Ensure clamping to (0,1) as sometimes the function evaluates to slightly below 0 (breaking the handle).
|
|
static float ValueToSlider(Piece p, float x) => Mathf.Clamp01(DoTransformation(x, p.inverseM, p.inverseB));
|
|
static float SliderToValue(Piece p, float x) => DoTransformation(x, p.directM, p.directB);
|
|
|
|
// Ideally we want a continuous, monotonically increasing function, but this is useful as we can easily fit a
|
|
// distribution to a set of (huge) value ranges onto a slider.
|
|
public PiecewiseLightUnitSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor)
|
|
{
|
|
// Sort the ranges into ascending order
|
|
var sortedRanges = m_Descriptor.valueRanges.OrderBy(x => x.value.x).ToArray();
|
|
var sliderDistribution = m_Descriptor.sliderDistribution;
|
|
|
|
// Compute the transformation for each value range.
|
|
for (int i = 0; i < sortedRanges.Length; i++)
|
|
{
|
|
var r = sortedRanges[i].value;
|
|
|
|
var x0 = sliderDistribution[i + 0];
|
|
var x1 = sliderDistribution[i + 1];
|
|
var y0 = r.x;
|
|
var y1 = r.y;
|
|
|
|
Piece piece;
|
|
piece.domain = new Vector2(x0, x1);
|
|
piece.range = new Vector2(y0, y1);
|
|
|
|
ComputeTransformationParameters(x0, x1, y0, y1, out piece.directM, out piece.directB);
|
|
|
|
// Compute the inverse
|
|
ComputeTransformationParameters(y0, y1, x0, x1, out piece.inverseM, out piece.inverseB);
|
|
|
|
m_PiecewiseFunctionMap.Add(sortedRanges[i].value, piece);
|
|
}
|
|
}
|
|
|
|
protected override float GetPositionOnSlider(float value, Vector2 valueRange)
|
|
{
|
|
if (!m_PiecewiseFunctionMap.TryGetValue(valueRange, out var piecewise))
|
|
return -1f;
|
|
|
|
return ValueToSlider(piecewise, value);
|
|
}
|
|
|
|
// Search for the corresponding piece-wise function to a value on the domain and update the input piece to it.
|
|
// Returns true if search was successful and an update was made, false otherwise.
|
|
bool UpdatePiece(ref Piece piece, float x)
|
|
{
|
|
foreach (var pair in m_PiecewiseFunctionMap)
|
|
{
|
|
var p = pair.Value;
|
|
|
|
if (x >= p.domain.x && x <= p.domain.y)
|
|
{
|
|
piece = p;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SliderOutOfBounds(Rect rect, ref float value)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
var internalValue = GUI.HorizontalSlider(rect, value, 0f, 1f);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Piece p = new Piece();
|
|
UpdatePiece(ref p, internalValue);
|
|
value = SliderToValue(p, internalValue);
|
|
}
|
|
}
|
|
|
|
protected override void DoSlider(Rect rect, ref float value, Vector2 sliderRange, Vector2 valueRange)
|
|
{
|
|
// Map the internal slider value to the current piecewise function
|
|
if (!m_PiecewiseFunctionMap.TryGetValue(valueRange, out var piece))
|
|
{
|
|
// Assume that if the piece is not found, that means the unit value is out of bounds.
|
|
SliderOutOfBounds(rect, ref value);
|
|
return;
|
|
}
|
|
|
|
// Maintain an internal value to support a single linear continuous function
|
|
EditorGUI.BeginChangeCheck();
|
|
var internalValue = GUI.HorizontalSlider(rect, ValueToSlider(piece, value), 0f, 1f);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
// Ensure that the current function piece is being used to transform the value
|
|
UpdatePiece(ref piece, internalValue);
|
|
value = SliderToValue(piece, internalValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats the provided descriptor into a punctual light unit slider with contextual slider markers, tooltips, and icons.
|
|
/// </summary>
|
|
class PunctualLightUnitSlider : PiecewiseLightUnitSlider
|
|
{
|
|
public PunctualLightUnitSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor) {}
|
|
|
|
private SerializedHDLight m_Light;
|
|
private Editor m_Editor;
|
|
private LightUnit m_Unit;
|
|
private bool m_SpotReflectorEnabled;
|
|
|
|
// Note: these should be in sync with LightUnit
|
|
private static string[] k_UnitNames =
|
|
{
|
|
"Lumen",
|
|
"Candela",
|
|
"Lux",
|
|
"Nits",
|
|
"EV",
|
|
};
|
|
|
|
public void Setup(LightUnit unit, SerializedHDLight light, Editor owner)
|
|
{
|
|
m_Unit = unit;
|
|
m_Light = light;
|
|
m_Editor = owner;
|
|
|
|
// Cache the spot reflector state as we will need to revert back to it after treating the slider as point light.
|
|
m_SpotReflectorEnabled = light.enableSpotReflector.boolValue;
|
|
}
|
|
|
|
public override void Draw(Rect rect, SerializedProperty value, ref float floatValue)
|
|
{
|
|
// Convert the incoming unit value into Lumen as the punctual slider is always in these terms (internally)
|
|
float convertedValue = UnitToLumen(floatValue);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
base.Draw(rect, value, ref convertedValue);
|
|
if (EditorGUI.EndChangeCheck())
|
|
floatValue = LumenToUnit(convertedValue);
|
|
}
|
|
|
|
protected override GUIContent GetLightUnitTooltip(string baseTooltip, float value, string unit)
|
|
{
|
|
// Convert the internal lumens into the actual light unit value
|
|
value = LumenToUnit(value);
|
|
unit = k_UnitNames[(int)m_Unit];
|
|
|
|
return base.GetLightUnitTooltip(baseTooltip, value, unit);
|
|
}
|
|
|
|
float UnitToLumen(float value)
|
|
{
|
|
if (m_Unit == LightUnit.Lumen)
|
|
return value;
|
|
|
|
// Punctual slider currently does not have any regard for spot shape/reflector.
|
|
// Conversions need to happen as if light is a point, and this is the only setting that influences that.
|
|
m_Light.enableSpotReflector.boolValue = false;
|
|
|
|
return HDLightUI.ConvertLightIntensity(m_Unit, LightUnit.Lumen, m_Light, m_Editor, value);
|
|
}
|
|
|
|
float LumenToUnit(float value)
|
|
{
|
|
if (m_Unit == LightUnit.Lumen)
|
|
return value;
|
|
|
|
// Once again temporarily disable reflector in case we called this for tooltip or context menu preset.
|
|
m_Light.enableSpotReflector.boolValue = false;
|
|
|
|
value = HDLightUI.ConvertLightIntensity(LightUnit.Lumen, m_Unit, m_Light, m_Editor, value);
|
|
|
|
// Restore the state of spot reflector on the light.
|
|
m_Light.enableSpotReflector.boolValue = m_SpotReflectorEnabled;
|
|
|
|
return value;
|
|
}
|
|
|
|
protected override void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
|
|
{
|
|
m_Light?.Update();
|
|
|
|
// Convert to the actual unit value.
|
|
value.floatValue = LumenToUnit(preset.presetValue);
|
|
|
|
m_Light?.Apply();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats the provided descriptor into a temperature unit slider with contextual slider markers, tooltips, and icons.
|
|
/// </summary>
|
|
class TemperatureSlider : LightUnitSlider
|
|
{
|
|
private Vector3 m_ExponentialConstraints;
|
|
|
|
private LightEditor.Settings m_Settings;
|
|
|
|
private static Texture2D s_KelvinGradientTexture;
|
|
|
|
/// <summary>
|
|
/// Exponential slider modeled to set a f(0.5) value.
|
|
/// ref: https://stackoverflow.com/a/17102320
|
|
/// </summary>
|
|
void PrepareExponentialConstraints(float lo, float mi, float hi)
|
|
{
|
|
// float x = lo;
|
|
// float y = mi;
|
|
// float z = hi;
|
|
//
|
|
// // https://www.desmos.com/calculator/yx2yf4huia
|
|
// m_ExponentialConstraints.x = ((x * z) - (y * y)) / (x - (2 * y) + z);
|
|
// m_ExponentialConstraints.y = ((y - x) * (y - x)) / (x - (2 * y) + z);
|
|
// m_ExponentialConstraints.z = 2 * Mathf.Log((z - y) / (y - x));
|
|
|
|
// Warning: These are the coefficients for a system of equation fit for a continuous, monotonic curve that fits a f(0.44) value.
|
|
// f(0.44) is required instead of f(0.5) due to the location of the white in the temperature gradient texture.
|
|
// The equation is solved to get the coefficient for the following constraint for low, mid, hi:
|
|
// f(0) = 1500
|
|
// f(0.44) = 6500
|
|
// f(1.0) = 20000
|
|
// If for any reason the constraints are changed, then the function must be refit and the new coefficients found.
|
|
// Note that we can't re-use the original PowerSlider instead due to how it forces a text field, which we don't want in this case.
|
|
m_ExponentialConstraints.x = -3935.53965427f;
|
|
m_ExponentialConstraints.y = 5435.53965427f;
|
|
m_ExponentialConstraints.z = 1.48240556f;
|
|
}
|
|
|
|
protected float ValueToSlider(float x) => Mathf.Log((x - m_ExponentialConstraints.x) / m_ExponentialConstraints.y) / m_ExponentialConstraints.z;
|
|
protected float SliderToValue(float x) => m_ExponentialConstraints.x + m_ExponentialConstraints.y * Mathf.Exp(m_ExponentialConstraints.z * x);
|
|
|
|
protected override float GetPositionOnSlider(float value, Vector2 valueRange)
|
|
{
|
|
return ValueToSlider(value);
|
|
}
|
|
|
|
static Texture2D GetKelvinGradientTexture(LightEditor.Settings settings)
|
|
{
|
|
if (s_KelvinGradientTexture == null)
|
|
{
|
|
var kelvinTexture = (Texture2D)typeof(LightEditor.Settings).GetField("m_KelvinGradientTexture", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(settings);
|
|
|
|
// This seems to be the only way to gamma-correct the internal gradient tex (aside from drawing it manually).
|
|
var kelvinTextureLinear = new Texture2D(kelvinTexture.width, kelvinTexture.height, TextureFormat.RGBA32, true);
|
|
kelvinTextureLinear.SetPixels(kelvinTexture.GetPixels());
|
|
kelvinTextureLinear.Apply();
|
|
|
|
s_KelvinGradientTexture = kelvinTextureLinear;
|
|
}
|
|
|
|
return s_KelvinGradientTexture;
|
|
}
|
|
|
|
public TemperatureSlider(LightUnitSliderUIDescriptor descriptor) : base(descriptor)
|
|
{
|
|
var halfValue = 6500;
|
|
PrepareExponentialConstraints(m_Descriptor.sliderRange.x, halfValue, m_Descriptor.sliderRange.y);
|
|
}
|
|
|
|
public void Setup(LightEditor.Settings settings)
|
|
{
|
|
m_Settings = settings;
|
|
}
|
|
|
|
// The serialized property for color temperature is stored in the build-in light editor, and we need to use this object to apply the update.
|
|
protected override void SetValueToPreset(SerializedProperty value, LightUnitSliderUIRange preset)
|
|
{
|
|
m_Settings.Update();
|
|
|
|
base.SetValueToPreset(value, preset);
|
|
|
|
m_Settings.ApplyModifiedProperties();
|
|
}
|
|
|
|
protected override void DoSlider(Rect rect, ref float value, Vector2 sliderRange)
|
|
{
|
|
SliderWithTextureNoTextField(rect, ref value, sliderRange, m_Settings);
|
|
}
|
|
|
|
// Note: We could use the internal SliderWithTexture, however: the internal slider func forces a text-field (and no ability to opt-out of it).
|
|
void SliderWithTextureNoTextField(Rect rect, ref float value, Vector2 range, LightEditor.Settings settings)
|
|
{
|
|
GUI.DrawTexture(rect, GetKelvinGradientTexture(settings));
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
// Draw the exponential slider that fits 6500K to the white point on the gradient texture.
|
|
var internalValue = GUI.HorizontalSlider(rect, ValueToSlider(value), 0f, 1f, SliderStyles.k_TemperatureBorder, SliderStyles.k_TemperatureThumb);
|
|
|
|
// Round to nearest since so much precision is not necessary for kelvin while sliding.
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
// Map the value back into kelvin.
|
|
value = SliderToValue(internalValue);
|
|
|
|
value = Mathf.Round(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class LightUnitSliderUIDrawer
|
|
{
|
|
static PiecewiseLightUnitSlider k_DirectionalLightUnitSlider;
|
|
static PunctualLightUnitSlider k_PunctualLightUnitSlider;
|
|
static PiecewiseLightUnitSlider k_ExposureSlider;
|
|
static TemperatureSlider k_TemperatureSlider;
|
|
|
|
static LightUnitSliderUIDrawer()
|
|
{
|
|
// Maintain a unique slider for directional/lux.
|
|
k_DirectionalLightUnitSlider = new PiecewiseLightUnitSlider(LightUnitSliderDescriptors.LuxDescriptor);
|
|
|
|
// Internally, slider is always in terms of lumens, so that the slider is uniform for all light units.
|
|
k_PunctualLightUnitSlider = new PunctualLightUnitSlider(LightUnitSliderDescriptors.LumenDescriptor);
|
|
|
|
// Exposure is in EV100, but we load a separate due to the different icon set.
|
|
k_ExposureSlider = new PiecewiseLightUnitSlider(LightUnitSliderDescriptors.ExposureDescriptor);
|
|
|
|
// Kelvin is not classified internally as a light unit so we handle it independently as well.
|
|
k_TemperatureSlider = new TemperatureSlider(LightUnitSliderDescriptors.TemperatureDescriptor);
|
|
}
|
|
|
|
// Need to cache the serialized object on the slider, to add support for the preset selection context menu (need to apply changes to serialized)
|
|
// TODO: This slider drawer is getting kind of bloated. Break up the implementation into where it is actually used?
|
|
public void SetSerializedObject(SerializedObject serializedObject)
|
|
{
|
|
k_DirectionalLightUnitSlider.SetSerializedObject(serializedObject);
|
|
k_PunctualLightUnitSlider.SetSerializedObject(serializedObject);
|
|
k_ExposureSlider.SetSerializedObject(serializedObject);
|
|
k_TemperatureSlider.SetSerializedObject(serializedObject);
|
|
}
|
|
|
|
public void Draw(HDLightType type, LightUnit lightUnit, SerializedProperty value, Rect rect, SerializedHDLight light, Editor owner)
|
|
{
|
|
using (new EditorGUI.IndentLevelScope(-EditorGUI.indentLevel))
|
|
{
|
|
if (type == HDLightType.Directional)
|
|
DrawDirectionalUnitSlider(value, rect);
|
|
else
|
|
DrawPunctualLightUnitSlider(lightUnit, value, rect, light, owner);
|
|
}
|
|
}
|
|
|
|
void DrawDirectionalUnitSlider(SerializedProperty value, Rect rect)
|
|
{
|
|
float val = value.floatValue;
|
|
k_DirectionalLightUnitSlider.Draw(rect, value, ref val);
|
|
if (val != value.floatValue)
|
|
value.floatValue = val;
|
|
}
|
|
|
|
void DrawPunctualLightUnitSlider(LightUnit lightUnit, SerializedProperty value, Rect rect, SerializedHDLight light, Editor owner)
|
|
{
|
|
k_PunctualLightUnitSlider.Setup(lightUnit, light, owner);
|
|
|
|
float val = value.floatValue;
|
|
k_PunctualLightUnitSlider.Draw(rect, value, ref val);
|
|
if (val != value.floatValue)
|
|
value.floatValue = val;
|
|
}
|
|
|
|
public void DrawExposureSlider(SerializedProperty value, Rect rect)
|
|
{
|
|
using (new EditorGUI.IndentLevelScope(-EditorGUI.indentLevel))
|
|
{
|
|
float val = value.floatValue;
|
|
k_ExposureSlider.Draw(rect, value, ref val);
|
|
if (val != value.floatValue)
|
|
value.floatValue = val;
|
|
}
|
|
}
|
|
|
|
public void DrawTemperatureSlider(LightEditor.Settings settings, SerializedProperty value, Rect rect)
|
|
{
|
|
using (new EditorGUI.IndentLevelScope(-EditorGUI.indentLevel))
|
|
{
|
|
k_TemperatureSlider.Setup(settings);
|
|
|
|
float val = value.floatValue;
|
|
k_TemperatureSlider.Draw(rect, value, ref val);
|
|
if (val != value.floatValue)
|
|
value.floatValue = val;
|
|
}
|
|
}
|
|
}
|
|
}
|