Car/Assets/VolumetricLightBeam/Editor/Editor_VolumetricLightBeamA...

342 lines
14 KiB
C#
Raw Normal View History

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace VLB
{
public abstract class Editor_VolumetricLightBeamAbstractBase : Editor_Common
{
TargetList<VolumetricLightBeamAbstractBase> m_Targets;
protected override void OnEnable()
{
base.OnEnable();
m_Targets = new TargetList<VolumetricLightBeamAbstractBase>(targets);
}
protected string GetBatchingReport()
{
if (m_Targets.Count > 1)
{
string reasons = "";
for (int i = 1; i < m_Targets.Count; ++i)
{
if (!BatchingHelper.CanBeBatched(m_Targets[0], m_Targets[i], ref reasons))
{
return "Selected beams can't be batched together:\n" + reasons;
}
}
}
return null;
}
protected void AddComponentToTargets<T>() where T : MonoBehaviour
{
foreach (var target in m_Targets) EditorExtensions.AddComponentFromEditor<T>(target);
}
protected void DrawEditInSceneButton()
{
EditorGUI.BeginChangeCheck();
bool editInScene = EditorPrefs.GetBool(EditorStrings.Beam.PrefEditInScene, false);
editInScene = GUILayout.Toggle(editInScene, EditorStrings.Beam.ButtonEditInScene, EditorStyles.miniButton);
if (EditorGUI.EndChangeCheck())
{
EditorPrefs.SetBool(EditorStrings.Beam.PrefEditInScene, editInScene);
SceneView.RepaintAll();
}
}
protected bool DrawFallOffSliderHandle(Transform beamTransf, Vector3 beamGlobalForward, Vector3 beamScale, float lineStartOffset, float lineAlpha, Handles.CapFunction capFunction, string recordName, System.Func<float> getValue, System.Action<float> setValue)
{
Debug.Assert(beamTransf != null);
EditorGUI.BeginChangeCheck();
var sliderPos = beamTransf.position + getValue() * beamScale.z * beamGlobalForward;
sliderPos = Handles.Slider(sliderPos, beamGlobalForward, HandleUtility.GetHandleSize(sliderPos) * 0.1f, capFunction, 0.5f);
Handles.Label(sliderPos, string.Format("{0} {1:0.0}", recordName, getValue()), labelStyle);
var savedCol = Handles.color;
{
var col = savedCol;
col.a = lineAlpha;
Handles.color = col;
Handles.DrawLine(beamTransf.position + beamGlobalForward * lineStartOffset, sliderPos);
Handles.color = savedCol;
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, string.Format("Edit Beam '{0}'", recordName));
var sliderVec = (sliderPos - beamTransf.position);
var sliderLength = 0.0f;
if (Vector3.Dot(sliderVec, beamGlobalForward) > 0.0f)
sliderLength = sliderVec.magnitude;
sliderLength /= beamScale.z;
setValue(sliderLength);
return true;
}
return false;
}
protected GUIStyle labelStyle
{
get
{
var style = new GUIStyle(GUI.skin.GetStyle("Label"));
style.normal.textColor = Handles.color;
style.alignment = TextAnchor.LowerCenter;
style.fixedWidth = 200.0f;
return style;
}
}
bool DrawRadiusHandle(Transform beamTransf, Vector3 beamGlobalForward, Vector3 beamScale, Vector3 pos, string recordName, System.Func<float> getValue, System.Action<float> setValue)
{
Debug.Assert(beamTransf != null);
var rot = Quaternion.LookRotation(beamTransf.up, beamGlobalForward);
UnityEditor.IMGUI.Controls.ArcHandle hdl = null;
float maxScaleXY = Mathf.Max(beamScale.x, beamScale.y);
EditorGUI.BeginChangeCheck();
{
using (new Handles.DrawingScope(Matrix4x4.TRS(pos, rot * Quaternion.Euler(0.0f, 45.0f, 0.0f), Vector3.one)))
{
hdl = EditorExtensions.DrawHandleRadius(getValue() * maxScaleXY);
}
using (new Handles.DrawingScope(Matrix4x4.TRS(pos, rot, Vector3.one)))
{
Handles.Label(getValue() * maxScaleXY * Vector3.forward, string.Format("{0} {1:0.00}", recordName, getValue()), labelStyle);
}
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, string.Format("Edit Beam '{0}'", recordName));
setValue(hdl.radius / maxScaleXY);
return true;
}
return false;
}
bool DrawSpotAngleHandle(Transform beamTransf, Vector3 beamGlobalForward, Vector3 pos, float handleRadius, string recordName, System.Func<float> getValue, System.Action<float> setValue)
{
Debug.Assert(beamTransf != null);
var left = Vector3.Cross(beamGlobalForward, beamTransf.up); // show angle handle properly with 2d beams
var rot = Quaternion.LookRotation(beamGlobalForward, left);
UnityEditor.IMGUI.Controls.ArcHandle hdl = null;
EditorGUI.BeginChangeCheck();
{
using (new Handles.DrawingScope(Matrix4x4.TRS(pos, rot * Quaternion.Euler(0.0f, -getValue() / 2, 0.0f), Vector3.one)))
{
hdl = EditorExtensions.DrawHandleSpotAngle(getValue(), handleRadius);
}
using (new Handles.DrawingScope(Matrix4x4.TRS(pos, rot, Vector3.one)))
{
Handles.Label(Vector3.forward * handleRadius, string.Format("{0} {1:0.0}", recordName, getValue()), labelStyle);
}
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, string.Format("Edit Beam '{0}'", recordName));
setValue(hdl.angle);
return true;
}
return false;
}
static Vector3 GetBeamGlobalForward(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.beamGlobalForward;
if (beam is VolumetricLightBeamHD hd) return hd.beamGlobalForward;
return Vector3.forward;
}
static Vector3 GetBeamLossyScaleIfScalable(VolumetricLightBeamAbstractBase beam)
{
if (beam.IsScalable())
return beam.GetLossyScale();
return Vector3.one;
}
static float GetBeamConeRadiusStart(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.coneRadiusStart;
if (beam is VolumetricLightBeamHD hd) return hd.coneRadiusStart;
return 0.0f;
}
static void SetBeamConeRadiusStart(VolumetricLightBeamAbstractBase beam, float radius)
{
if (beam is VolumetricLightBeamSD sd) sd.coneRadiusStart = radius;
if (beam is VolumetricLightBeamHD hd) hd.coneRadiusStart = radius;
}
static float GetBeamConeRadiusEnd(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.coneRadiusEnd;
if (beam is VolumetricLightBeamHD hd) return hd.coneRadiusEnd;
return 1.0f;
}
static void SetBeamConeRadiusEnd(VolumetricLightBeamAbstractBase beam, float radius)
{
if (beam is VolumetricLightBeamSD sd) sd.coneRadiusEnd = radius;
if (beam is VolumetricLightBeamHD hd) hd.coneRadiusEnd = radius;
}
static float GetBeamSpotAngle(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.spotAngle;
if (beam is VolumetricLightBeamHD hd) return hd.spotAngle;
return 1.0f;
}
static void SetBeamSpotAngle(VolumetricLightBeamAbstractBase beam, float radius)
{
if (beam is VolumetricLightBeamSD sd) sd.spotAngle = radius;
if (beam is VolumetricLightBeamHD hd) hd.spotAngle = radius;
}
static float GetBeamFallOffEnd(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.fallOffEnd;
if (beam is VolumetricLightBeamHD hd) return hd.fallOffEnd;
return 1.0f;
}
static void SetBeamFallOffEnd(VolumetricLightBeamAbstractBase beam, float radius)
{
if (beam is VolumetricLightBeamSD sd) sd.fallOffEnd = radius;
if (beam is VolumetricLightBeamHD hd) hd.fallOffEnd = radius;
}
static float GetBeamFallOffStart(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.fallOffStart;
if (beam is VolumetricLightBeamHD hd) return hd.fallOffStart;
return 1.0f;
}
static bool GetBeamHasMeshSkewing(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.hasMeshSkewing;
return false;
}
static bool GetBeamUseSpotAngleFromLight(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.spotAngleFromLight;
if (beam is VolumetricLightBeamHD hd) return hd.useSpotAngleFromAttachedLightSpot;
return false;
}
static bool GetBeamUseFallOffEndFromLight(VolumetricLightBeamAbstractBase beam)
{
if (beam is VolumetricLightBeamSD sd) return sd.fallOffEndFromLight;
if (beam is VolumetricLightBeamHD hd) return hd.useFallOffEndFromAttachedLightSpot;
return false;
}
protected virtual bool DrawEditInSceneHandles()
{
bool editInScene = EditorPrefs.GetBool(EditorStrings.Beam.PrefEditInScene, false);
if (!editInScene)
return false;
var beam = target as VolumetricLightBeamAbstractBase;
Debug.Assert(beam != null);
bool update = false;
VolumetricLightBeamSD.AttachedLightType lightType;
var hasSpotLight = beam.GetLightSpotAttachedSlow(out lightType) != null;
Handles.color = beam.ComputeColorAtDepth(0.0f).ComputeComplementaryColor(true);
{
update |= DrawRadiusHandle(beam.transform, GetBeamGlobalForward(beam), GetBeamLossyScaleIfScalable(beam), beam.transform.position, "Source Radius", () => GetBeamConeRadiusStart(beam), (float v) => SetBeamConeRadiusStart(beam, v));
if (!hasSpotLight || !GetBeamUseSpotAngleFromLight(beam))
{
update |= DrawSpotAngleHandle(beam.transform, GetBeamGlobalForward(beam), beam.transform.position, GetBeamFallOffEnd(beam) / 2, "Spot Angle", () => GetBeamSpotAngle(beam), (float v) => SetBeamSpotAngle(beam, v));
}
}
if (!GetBeamHasMeshSkewing(beam))
{
Handles.color = beam.ComputeColorAtDepth(1.0f).ComputeComplementaryColor(true);
{
if (!hasSpotLight || !GetBeamUseFallOffEndFromLight(beam))
{
update |= DrawFallOffSliderHandle(beam.transform, GetBeamGlobalForward(beam), GetBeamLossyScaleIfScalable(beam), GetBeamFallOffStart(beam), 0.5f, Handles.CubeHandleCap, "Range Limit", () => GetBeamFallOffEnd(beam), (float v) => SetBeamFallOffEnd(beam, v));
}
if (!hasSpotLight || !GetBeamUseSpotAngleFromLight(beam))
{
var fallOffEndPos = beam.transform.TransformPoint(GetBeamGlobalForward(beam) * GetBeamFallOffEnd(beam));
update |= DrawRadiusHandle(beam.transform, GetBeamGlobalForward(beam), GetBeamLossyScaleIfScalable(beam), fallOffEndPos, "End Radius", () => GetBeamConeRadiusEnd(beam), (float v) => SetBeamConeRadiusEnd(beam, v));
}
}
}
return update;
}
protected GUIStyle buttonAddComponentStyle { get => GUI.skin.button; }
protected void DrawButtonAddComponentDust()
{
bool showButtonDust = m_Targets.HasAtLeastOneTargetWith((VolumetricLightBeamAbstractBase beam) => { return beam.GetComponent<VolumetricDustParticles>() == null; });
if (showButtonDust && GUILayout.Button(EditorData.Instance.contentAddDustParticles, buttonAddComponentStyle))
AddComponentToTargets<VolumetricDustParticles>();
}
protected void DrawButtonAddComponentTriggerZone()
{
bool showButtonTriggerZone = m_Targets.HasAtLeastOneTargetWith((VolumetricLightBeamAbstractBase beam) => { return beam.GetComponent<TriggerZone>() == null; });
if (showButtonTriggerZone && GUILayout.Button(EditorData.Instance.contentAddTriggerZone, buttonAddComponentStyle))
AddComponentToTargets<TriggerZone>();
}
protected void DrawButtonAddComponentEffect()
{
bool showButtonEffect = m_Targets.HasAtLeastOneTargetWith((VolumetricLightBeamAbstractBase beam) => { return beam.GetComponent<EffectAbstractBase>() == null; });
if (showButtonEffect && GUILayout.Button(EditorData.Instance.contentAddEffect, buttonAddComponentStyle))
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent(EditorStrings.Beam.ButtonAddEffectFlicker), false, AddComponentToTargets<EffectFlicker>);
menu.AddItem(new GUIContent(EditorStrings.Beam.ButtonAddEffectPulse), false, AddComponentToTargets<EffectPulse>);
menu.ShowAsContext();
}
}
protected override void GetInfoTips(List<InfoTip> tips)
{
var gpuInstancingReport = GetBatchingReport();
if (!string.IsNullOrEmpty(gpuInstancingReport))
tips.Add(new InfoTip { type = MessageType.Warning, message = gpuInstancingReport });
base.GetInfoTips(tips);
}
}
}
#endif // UNITY_EDITOR