335 lines
13 KiB
C#
335 lines
13 KiB
C#
|
#if UNITY_EDITOR
|
|||
|
using UnityEngine;
|
|||
|
using UnityEditor;
|
|||
|
using UnityEditor.IMGUI.Controls;
|
|||
|
|
|||
|
namespace VLB
|
|||
|
{
|
|||
|
public static class EditorExtensions
|
|||
|
{
|
|||
|
public static class SD
|
|||
|
{
|
|||
|
public static GameObject NewBeam() { return new GameObject("Volumetric Light Beam SD", typeof(VolumetricLightBeamSD)); }
|
|||
|
|
|||
|
public static GameObject NewBeam2D()
|
|||
|
{
|
|||
|
var gao = new GameObject("Volumetric Light Beam SD (2D)", typeof(VolumetricLightBeamSD));
|
|||
|
gao.GetComponent<VolumetricLightBeamSD>().dimensions = Dimensions.Dim2D;
|
|||
|
return gao;
|
|||
|
}
|
|||
|
|
|||
|
public static GameObject NewBeamAndDust() { return new GameObject("Volumetric Light Beam SD + Dust", typeof(VolumetricLightBeamSD), typeof(VolumetricDustParticles)); }
|
|||
|
|
|||
|
public static GameObject NewSpotLightAndBeam()
|
|||
|
{
|
|||
|
var light = Utils.NewWithComponent<Light>("Spotlight and Beam SD");
|
|||
|
light.type = LightType.Spot;
|
|||
|
var gao = light.gameObject;
|
|||
|
gao.AddComponent<VolumetricLightBeamSD>();
|
|||
|
return gao;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static class HD
|
|||
|
{
|
|||
|
public static GameObject NewBeam() { return new GameObject("Volumetric Light Beam HD", typeof(VolumetricLightBeamHD)); }
|
|||
|
public static GameObject NewBeam2D() { return new GameObject("Volumetric Light Beam HD (2D)", typeof(VolumetricLightBeamHD2D)); }
|
|||
|
public static GameObject NewBeamAndDust() { return new GameObject("Volumetric Light Beam HD + Dust", typeof(VolumetricLightBeamHD), typeof(VolumetricDustParticles)); }
|
|||
|
|
|||
|
public static GameObject NewSpotLightAndBeam()
|
|||
|
{
|
|||
|
var light = Utils.NewWithComponent<Light>("Spotlight and Beam HD");
|
|||
|
light.type = LightType.Spot;
|
|||
|
var gao = light.gameObject;
|
|||
|
gao.AddComponent<VolumetricLightBeamHD>().scalable = false;
|
|||
|
return gao;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void OnNewGameObjectCreated(GameObject gao, MenuCommand menuCommand)
|
|||
|
{
|
|||
|
Debug.Assert(gao != null);
|
|||
|
Debug.Assert(menuCommand != null);
|
|||
|
|
|||
|
OnNewGameObjectCreated(gao, menuCommand.context as GameObject);
|
|||
|
}
|
|||
|
|
|||
|
public static void OnNewGameObjectCreated(GameObject gao, GameObject parentGao)
|
|||
|
{
|
|||
|
Debug.Assert(gao != null);
|
|||
|
|
|||
|
if (parentGao == null)
|
|||
|
{
|
|||
|
#if UNITY_2021_2_OR_NEWER
|
|||
|
var currentPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
|
|||
|
#else
|
|||
|
var currentPrefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
|
|||
|
#endif
|
|||
|
if (currentPrefabStage != null)
|
|||
|
{
|
|||
|
// The user is in prefab mode without any GAO selected in the hierarchy. Get the current prefab root as parent.
|
|||
|
parentGao = currentPrefabStage.prefabContentsRoot;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
GameObjectUtility.SetParentAndAlign(gao, parentGao); // Ensure it gets reparented if this was a context click (otherwise does nothing)
|
|||
|
|
|||
|
Undo.RegisterCreatedObjectUndo(gao, "Create " + gao.name); // Register the creation in the undo system
|
|||
|
Selection.activeObject = gao;
|
|||
|
}
|
|||
|
|
|||
|
public static bool CanAddComponentFromEditor<TComp>(VolumetricLightBeamAbstractBase self) where TComp : Component
|
|||
|
{
|
|||
|
return !Application.isPlaying && self != null && self.GetComponent<TComp>() == null;
|
|||
|
}
|
|||
|
|
|||
|
public static void AddComponentFromEditor<TComp>(VolumetricLightBeamAbstractBase self) where TComp : Component
|
|||
|
{
|
|||
|
if (CanAddComponentFromEditor<TComp>(self))
|
|||
|
{
|
|||
|
/*var comp =*/ Undo.AddComponent<TComp>(self.gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add a EditorGUILayout.ToggleLeft which properly handles multi-object editing
|
|||
|
/// </summary>
|
|||
|
public static void ToggleLeft(this SerializedProperty prop, GUIContent label, params GUILayoutOption[] options)
|
|||
|
{
|
|||
|
ToggleLeft(prop, label, prop.boolValue, options);
|
|||
|
}
|
|||
|
|
|||
|
public static void ToggleLeft(this SerializedProperty prop, GUIContent label, bool forcedValue, params GUILayoutOption[] options)
|
|||
|
{
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
|||
|
var newValue = EditorGUILayout.ToggleLeft(label, forcedValue, options);
|
|||
|
EditorGUI.showMixedValue = false;
|
|||
|
if (EditorGUI.EndChangeCheck())
|
|||
|
prop.boolValue = newValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static bool HasAtLeastOneValue(this SerializedProperty prop, bool value)
|
|||
|
{
|
|||
|
return (prop.boolValue == value) || prop.hasMultipleDifferentValues;
|
|||
|
}
|
|||
|
|
|||
|
public static bool HasAtLeastOnePositiveValue(this SerializedProperty prop)
|
|||
|
{
|
|||
|
return (prop.floatValue >= 0.0f) || prop.hasMultipleDifferentValues;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Create a EditorGUILayout.Slider which properly handles multi-object editing
|
|||
|
/// We apply the 'convIn' conversion to the SerializedProperty value before exposing it as a Slider.
|
|||
|
/// We apply the 'convOut' conversion to the Slider value to get the SerializedProperty back.
|
|||
|
/// </summary>
|
|||
|
/// <param name="prop">The value the slider shows.</param>
|
|||
|
/// <param name="label">Label in front of the slider.</param>
|
|||
|
/// <param name="leftValue">The value at the left end of the slider.</param>
|
|||
|
/// <param name="rightValue">The value at the right end of the slider.</param>
|
|||
|
/// <param name="convIn">Conversion applied on the SerializedProperty to get the Slider value</param>
|
|||
|
/// <param name="convOut">Conversion applied on the Slider value to get the SerializedProperty</param>
|
|||
|
public static bool FloatSlider(
|
|||
|
this SerializedProperty prop,
|
|||
|
GUIContent label,
|
|||
|
float leftValue, float rightValue,
|
|||
|
System.Func<float, float> convIn,
|
|||
|
System.Func<float, float> convOut,
|
|||
|
params GUILayoutOption[] options)
|
|||
|
{
|
|||
|
var floatValue = convIn(prop.floatValue);
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
{
|
|||
|
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
|||
|
{
|
|||
|
floatValue = EditorGUILayout.Slider(label, floatValue, leftValue, rightValue, options);
|
|||
|
}
|
|||
|
EditorGUI.showMixedValue = false;
|
|||
|
}
|
|||
|
if (EditorGUI.EndChangeCheck())
|
|||
|
{
|
|||
|
prop.floatValue = convOut(floatValue);
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
public static bool FloatSlider(
|
|||
|
this SerializedProperty prop,
|
|||
|
GUIContent label,
|
|||
|
float leftValue, float rightValue,
|
|||
|
params GUILayoutOption[] options)
|
|||
|
{
|
|||
|
var floatValue = prop.floatValue;
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
{
|
|||
|
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
|||
|
{
|
|||
|
floatValue = EditorGUILayout.Slider(label, floatValue, leftValue, rightValue, options);
|
|||
|
}
|
|||
|
EditorGUI.showMixedValue = false;
|
|||
|
}
|
|||
|
if (EditorGUI.EndChangeCheck())
|
|||
|
{
|
|||
|
prop.floatValue = floatValue;
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
/*
|
|||
|
public static void ToggleFromLight(this SerializedProperty prop)
|
|||
|
{
|
|||
|
ToggleLeft(
|
|||
|
prop,
|
|||
|
new GUIContent("From Spot", "Get the value from the Light Spot"),
|
|||
|
GUILayout.MaxWidth(80.0f));
|
|||
|
}
|
|||
|
*/
|
|||
|
public static void ToggleUseGlobalNoise(this SerializedProperty prop)
|
|||
|
{
|
|||
|
ToggleLeft(
|
|||
|
prop,
|
|||
|
new GUIContent("Global", "Get the value from the Global 3D Noise"),
|
|||
|
GUILayout.MaxWidth(55.0f));
|
|||
|
}
|
|||
|
|
|||
|
public static void CustomEnum<EnumType>(this SerializedProperty prop, GUIContent content, string[] descriptions = null)
|
|||
|
{
|
|||
|
if(descriptions == null)
|
|||
|
descriptions = System.Enum.GetNames(typeof(EnumType));
|
|||
|
|
|||
|
Debug.Assert(System.Enum.GetNames(typeof(EnumType)).Length == descriptions.Length, string.Format("Enum '{0}' and the description array don't have the same size", typeof(EnumType)));
|
|||
|
|
|||
|
int enumValueIndex = prop.enumValueIndex;
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
{
|
|||
|
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
|||
|
{
|
|||
|
#if UNITY_2018_1_OR_NEWER
|
|||
|
enumValueIndex = EditorGUILayout.Popup(content, enumValueIndex, descriptions);
|
|||
|
#else
|
|||
|
enumValueIndex = EditorGUILayout.Popup(content.text, enumValueIndex, descriptions);
|
|||
|
#endif
|
|||
|
}
|
|||
|
EditorGUI.showMixedValue = false;
|
|||
|
}
|
|||
|
if (EditorGUI.EndChangeCheck())
|
|||
|
prop.enumValueIndex = enumValueIndex;
|
|||
|
}
|
|||
|
|
|||
|
public static void CustomMask<EnumType>(this SerializedProperty prop, GUIContent content, string[] descriptions = null)
|
|||
|
{
|
|||
|
if (descriptions == null)
|
|||
|
descriptions = System.Enum.GetNames(typeof(EnumType));
|
|||
|
|
|||
|
Debug.Assert(System.Enum.GetNames(typeof(EnumType)).Length == descriptions.Length, string.Format("Enum '{0}' and the description array don't have the same size", typeof(EnumType)));
|
|||
|
|
|||
|
int intValue = prop.intValue;
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
{
|
|||
|
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
|||
|
{
|
|||
|
intValue = EditorGUILayout.MaskField(content, intValue, descriptions);
|
|||
|
}
|
|||
|
EditorGUI.showMixedValue = false;
|
|||
|
}
|
|||
|
if (EditorGUI.EndChangeCheck())
|
|||
|
prop.intValue = intValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static void DrawLineSeparator()
|
|||
|
{
|
|||
|
DrawLineSeparator(Color.grey, 1, 10);
|
|||
|
}
|
|||
|
|
|||
|
static void DrawLineSeparator(Color color, int thickness = 2, int padding = 10)
|
|||
|
{
|
|||
|
Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
|
|||
|
|
|||
|
r.x = 0;
|
|||
|
r.width = EditorGUIUtility.currentViewWidth;
|
|||
|
|
|||
|
r.y += padding / 2;
|
|||
|
r.height = thickness;
|
|||
|
|
|||
|
EditorGUI.DrawRect(r, color);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static bool GlobalToggleButton(ref bool boolean, GUIContent content, string saveString, float maxWidth = 999.0f)
|
|||
|
{
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
boolean = GUILayout.Toggle(boolean, content, EditorStyles.miniButton, GUILayout.MaxWidth(maxWidth));
|
|||
|
if (EditorGUI.EndChangeCheck())
|
|||
|
{
|
|||
|
EditorPrefs.SetBool(saveString, boolean);
|
|||
|
SceneView.RepaintAll();
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public abstract class EditorGUIWidth : System.IDisposable
|
|||
|
{
|
|||
|
protected abstract void ApplyWidth(float width);
|
|||
|
public EditorGUIWidth(float width) { ApplyWidth(width); }
|
|||
|
public void Dispose() { ApplyWidth(0.0f); }
|
|||
|
}
|
|||
|
|
|||
|
public class LabelWidth : EditorGUIWidth
|
|||
|
{
|
|||
|
public LabelWidth(float width) : base(width) { }
|
|||
|
protected override void ApplyWidth(float width) { EditorGUIUtility.labelWidth = width; }
|
|||
|
}
|
|||
|
|
|||
|
public class FieldWidth : EditorGUIWidth
|
|||
|
{
|
|||
|
public FieldWidth(float width) : base(width) { }
|
|||
|
protected override void ApplyWidth(float width) { EditorGUIUtility.fieldWidth = width; }
|
|||
|
}
|
|||
|
|
|||
|
public class ShowMixedValue : System.IDisposable
|
|||
|
{
|
|||
|
public ShowMixedValue(bool? value) { m_PrevValue = EditorGUI.showMixedValue; EditorGUI.showMixedValue = value ?? false; }
|
|||
|
public ShowMixedValue(SerializedProperty prop) : this(prop?.hasMultipleDifferentValues) { }
|
|||
|
public void Dispose() { EditorGUI.showMixedValue = m_PrevValue; }
|
|||
|
bool m_PrevValue = false;
|
|||
|
}
|
|||
|
|
|||
|
private static ArcHandle ms_ArcHandle = null;
|
|||
|
|
|||
|
// HANDLES
|
|||
|
public static ArcHandle DrawHandleRadius(float radius)
|
|||
|
{
|
|||
|
if (ms_ArcHandle == null)
|
|||
|
ms_ArcHandle = new ArcHandle();
|
|||
|
|
|||
|
ms_ArcHandle.SetColorWithRadiusHandle(Color.white, 0f);
|
|||
|
ms_ArcHandle.angle = 360f;
|
|||
|
ms_ArcHandle.angleHandleSizeFunction = null;
|
|||
|
ms_ArcHandle.angleHandleColor = Color.clear;
|
|||
|
ms_ArcHandle.radius = radius;
|
|||
|
ms_ArcHandle.DrawHandle();
|
|||
|
return ms_ArcHandle;
|
|||
|
}
|
|||
|
|
|||
|
public static ArcHandle DrawHandleSpotAngle(float angle, float radius)
|
|||
|
{
|
|||
|
if (ms_ArcHandle == null)
|
|||
|
ms_ArcHandle = new ArcHandle();
|
|||
|
|
|||
|
ms_ArcHandle.angleHandleSizeFunction = ArcHandle.DefaultAngleHandleSizeFunction;
|
|||
|
ms_ArcHandle.SetColorWithRadiusHandle(Handles.color, Handles.color.maxColorComponent < 0.5f ? 0.25f : 0.1f);
|
|||
|
ms_ArcHandle.angleHandleColor = Handles.color;
|
|||
|
ms_ArcHandle.radius = radius;
|
|||
|
ms_ArcHandle.angle = angle;
|
|||
|
ms_ArcHandle.DrawHandle();
|
|||
|
return ms_ArcHandle;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|