428 lines
15 KiB
C#
428 lines
15 KiB
C#
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using LeTai.Common.Editor;
|
|
using LeTai.Paraform.Scaffold.Editor;
|
|
using UnityEditor;
|
|
using UnityEditor.AnimatedValues;
|
|
using UnityEditor.UI;
|
|
using UnityEngine;
|
|
using Debug = System.Diagnostics.Debug;
|
|
using Image = UnityEngine.UI.Image;
|
|
using Object = UnityEngine.Object;
|
|
|
|
#pragma warning disable CS0162 // Unreachable code detected
|
|
|
|
namespace LeTai.Asset.TranslucentImage.Editor
|
|
{
|
|
[CustomEditor(typeof(TranslucentImage))]
|
|
[CanEditMultipleObjects]
|
|
public class TranslucentImageEditor : ImageEditor
|
|
{
|
|
SerializedProperty type;
|
|
SerializedProperty sprite;
|
|
SerializedProperty preserveAspect;
|
|
SerializedProperty useSpriteMesh;
|
|
|
|
EditorProperty source;
|
|
EditorProperty foregroundOpacity;
|
|
EditorProperty _vibrancy;
|
|
EditorProperty _brightness;
|
|
EditorProperty _flatten;
|
|
|
|
GUIStyle styleBtnSource;
|
|
|
|
static readonly EditorPrefValue<bool> SHOW_PARAFORM_SHAPE_CONTROLS = new("TranslucentImage_ShowParaformShapeControls", HAVE_PARAFORM);
|
|
static readonly EditorPrefValue<bool> SHOW_MATERIAL_PROPERTIES = new("TranslucentImage_ShowMaterialProperties", true);
|
|
|
|
AnimBool showTypeAnim;
|
|
|
|
List<TranslucentImage> tiList;
|
|
UnityEditor.Editor materialEditor;
|
|
|
|
ParaformEditor paraformEditor;
|
|
|
|
bool needValidateSource;
|
|
bool needValidateMaterial;
|
|
bool materialUsedInDifferentSource;
|
|
bool usingIncorrectShader;
|
|
int smallFontSize;
|
|
|
|
const bool HAVE_PARAFORM =
|
|
#if LETAI_PARAFORM
|
|
true;
|
|
#else
|
|
false;
|
|
#endif
|
|
|
|
protected override void OnEnable()
|
|
{
|
|
base.OnEnable();
|
|
|
|
typeof(ImageEditor).GetField("m_SpriteContent", BindingFlags.Instance | BindingFlags.NonPublic)
|
|
.SetValue(this, new GUIContent("Sprite"));
|
|
|
|
sprite = serializedObject.FindProperty("m_Sprite");
|
|
type = serializedObject.FindProperty("m_Type");
|
|
preserveAspect = serializedObject.FindProperty("m_PreserveAspect");
|
|
useSpriteMesh = serializedObject.FindProperty("m_UseSpriteMesh");
|
|
|
|
source = new EditorProperty(serializedObject, nameof(TranslucentImage.source), "_source");
|
|
foregroundOpacity = new EditorProperty(serializedObject, nameof(TranslucentImage.foregroundOpacity));
|
|
_vibrancy = new EditorProperty(serializedObject, nameof(TranslucentImage.vibrancy));
|
|
_brightness = new EditorProperty(serializedObject, nameof(TranslucentImage.brightness));
|
|
_flatten = new EditorProperty(serializedObject, nameof(TranslucentImage.flatten));
|
|
paraformEditor = new ParaformEditor(serializedObject.FindProperty("paraformConfig"));
|
|
|
|
showTypeAnim = new AnimBool(sprite.objectReferenceValue);
|
|
showTypeAnim.valueChanged.AddListener(Repaint);
|
|
|
|
tiList = targets.Cast<TranslucentImage>().ToList();
|
|
if (tiList.Count > 0)
|
|
{
|
|
CheckMaterialUsedInDifferentSource();
|
|
CheckCorrectShader();
|
|
}
|
|
}
|
|
|
|
void InitStyle()
|
|
{
|
|
if (styleBtnSource != null)
|
|
return;
|
|
|
|
styleBtnSource = new GUIStyle(GUI.skin.button) {
|
|
alignment = TextAnchor.MiddleLeft,
|
|
richText = true,
|
|
};
|
|
|
|
smallFontSize = Mathf.RoundToInt(styleBtnSource.fontSize * .8f);
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
InitStyle();
|
|
|
|
serializedObject.Update();
|
|
|
|
tiList = targets.Cast<TranslucentImage>().ToList();
|
|
Debug.Assert(tiList.Count > 0, "Translucent Image Editor serializedObject target is null");
|
|
|
|
DrawSourceControls();
|
|
|
|
DrawShapeControls();
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
EditorGUILayout.LabelField("Appearance", EditorStyles.boldLabel);
|
|
|
|
DrawSpriteControls();
|
|
EditorGUILayout.PropertyField(m_Color);
|
|
foregroundOpacity.Draw();
|
|
_vibrancy.Draw();
|
|
_brightness.Draw();
|
|
_flatten.Draw();
|
|
EditorGUILayout.Space();
|
|
DrawMaterialControls();
|
|
DrawMaterialProperties();
|
|
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.LabelField("Interaction", EditorStyles.boldLabel);
|
|
RaycastControlsGUI();
|
|
MaskableControlsGUI();
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
|
|
if (needValidateSource) ValidateSource();
|
|
if (needValidateMaterial) ValidateMaterial();
|
|
}
|
|
|
|
void DrawSourceControls()
|
|
{
|
|
using (var changes = new EditorGUI.ChangeCheckScope())
|
|
{
|
|
source.Draw();
|
|
if (changes.changed)
|
|
needValidateSource = true;
|
|
}
|
|
|
|
if (!source.serializedProperty.objectReferenceValue)
|
|
{
|
|
var existingSources = Shims.FindObjectsOfType<TranslucentImageSource>();
|
|
if (existingSources.Length > 0)
|
|
{
|
|
using (new EditorGUI.IndentLevelScope())
|
|
{
|
|
using var h = new EditorGUILayout.HorizontalScope();
|
|
|
|
EditorGUILayout.PrefixLabel("From current Scene");
|
|
using var v = new EditorGUILayout.VerticalScope();
|
|
foreach (var s in existingSources)
|
|
{
|
|
SetSourceBtn($"{s.gameObject.name}\t{GetSourceDescriptionLabel(s)}", s);
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.Space();
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.HelpBox("No Translucent Image Source(s) found in current scene", MessageType.Warning);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using var _ = new EditorGUI.IndentLevelScope(1);
|
|
|
|
var sourceObj = (TranslucentImageSource)source.serializedProperty.objectReferenceValue;
|
|
var config = sourceObj.BlurConfig;
|
|
|
|
if (config)
|
|
{
|
|
var oldStrength = config.Strength;
|
|
var newStrength = EditorGUILayout.FloatField("Blur Strength", oldStrength);
|
|
|
|
if (!Mathf.Approximately(newStrength, oldStrength))
|
|
{
|
|
Undo.RecordObject(config, "Change blur config");
|
|
config.Strength = newStrength;
|
|
EditorUtility.SetDirty(config);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using var h = new EditorGUILayout.HorizontalScope();
|
|
EditorGUILayout.LabelField(" ", "No Blur Config");
|
|
}
|
|
|
|
var sameCameraSources = sourceObj.GetComponents<TranslucentImageSource>();
|
|
if (sameCameraSources.Length > 1)
|
|
{
|
|
using var h = new EditorGUILayout.HorizontalScope();
|
|
EditorGUILayout.PrefixLabel("Other Sources");
|
|
foreach (var s in sameCameraSources)
|
|
{
|
|
if (s == sourceObj)
|
|
continue;
|
|
|
|
SetSourceBtn(GetSourceDescriptionLabel(s), s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
string GetSourceDescriptionLabel(TranslucentImageSource s)
|
|
{
|
|
if (s.BlurConfig)
|
|
return $"<size={smallFontSize}>STR: </size>{s.BlurConfig.Strength:0.#}";
|
|
|
|
return $"<size={smallFontSize}>No Blur Config</size>";
|
|
}
|
|
|
|
void SetSourceBtn(string label, TranslucentImageSource newSource)
|
|
{
|
|
if (GUILayout.Button(label, styleBtnSource, GUILayout.ExpandWidth(false)))
|
|
{
|
|
Undo.RecordObject(target, $"Set source to {newSource.gameObject.name}");
|
|
source.serializedProperty.objectReferenceValue = newSource;
|
|
source.CallSetters(newSource);
|
|
needValidateSource = true;
|
|
needValidateMaterial = true;
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse")]
|
|
[SuppressMessage("ReSharper", "HeuristicUnreachableCode")]
|
|
void DrawShapeControls()
|
|
{
|
|
var useParaform = tiList.Any(ti => ti.material && ti.material.shader.name.EndsWith("-Paraform"));
|
|
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
var label = "Paraform";
|
|
if (!HAVE_PARAFORM)
|
|
label += " (not installed)";
|
|
else if (!useParaform)
|
|
label += " (Not supported by material)";
|
|
SHOW_PARAFORM_SHAPE_CONTROLS.Value = EditorGUILayout.BeginFoldoutHeaderGroup(SHOW_PARAFORM_SHAPE_CONTROLS, label);
|
|
|
|
if (HAVE_PARAFORM && !useParaform)
|
|
{
|
|
if (GUILayout.Button("Use Paraform Shader"))
|
|
{
|
|
foreach (var ti in tiList)
|
|
{
|
|
var mat = ti.material;
|
|
Undo.RecordObject(mat, "Use Paraform Shader");
|
|
mat.shader = Shader.Find("UI/TranslucentImage-Paraform");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
using var disabledGroupScope = new EditorGUI.DisabledGroupScope(!HAVE_PARAFORM || !useParaform);
|
|
|
|
if (SHOW_PARAFORM_SHAPE_CONTROLS)
|
|
{
|
|
using var changes = new EditorGUI.ChangeCheckScope();
|
|
|
|
paraformEditor?.DrawShapeControls();
|
|
|
|
if (changes.changed)
|
|
{
|
|
serializedObject.ApplyModifiedProperties();
|
|
foreach (var ti in tiList) ti.paraformConfig.NotifyChanged();
|
|
}
|
|
|
|
ParaformEditor.MaybeGetParaformLinkBtn();
|
|
}
|
|
EditorGUILayout.EndFoldoutHeaderGroup();
|
|
}
|
|
|
|
void DrawSpriteControls()
|
|
{
|
|
SpriteGUI();
|
|
showTypeAnim.target = sprite.objectReferenceValue != null;
|
|
if (EditorGUILayout.BeginFadeGroup(showTypeAnim.faded))
|
|
TypeGUI();
|
|
EditorGUILayout.EndFadeGroup();
|
|
|
|
Image.Type type = (Image.Type)this.type.enumValueIndex;
|
|
bool showNativeSize = (type == Image.Type.Simple || type == Image.Type.Filled)
|
|
&& sprite.objectReferenceValue != null;
|
|
SetShowNativeSize(showNativeSize, false);
|
|
|
|
if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded))
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
|
|
if ((Image.Type)this.type.enumValueIndex == Image.Type.Simple)
|
|
EditorGUILayout.PropertyField(useSpriteMesh);
|
|
|
|
EditorGUILayout.PropertyField(preserveAspect);
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndFadeGroup();
|
|
NativeSizeButtonGUI();
|
|
}
|
|
|
|
void DrawMaterialControls()
|
|
{
|
|
using var changes = new EditorGUI.ChangeCheckScope();
|
|
EditorGUILayout.PropertyField(m_Material);
|
|
if (changes.changed)
|
|
needValidateMaterial = true;
|
|
|
|
if (usingIncorrectShader)
|
|
{
|
|
EditorGUILayout.HelpBox("Material is using unsupported shader", MessageType.Warning);
|
|
}
|
|
if (materialUsedInDifferentSource)
|
|
{
|
|
EditorGUILayout.HelpBox("Translucent Images with different Sources" +
|
|
" should also use different Materials",
|
|
MessageType.Error);
|
|
}
|
|
}
|
|
|
|
void DrawMaterialProperties()
|
|
{
|
|
using var change = new EditorGUI.ChangeCheckScope();
|
|
var targetMaterials = tiList.Select(t => t.material).Cast<Object>().ToArray();
|
|
|
|
using (_ = new EditorGUI.IndentLevelScope())
|
|
{
|
|
SHOW_MATERIAL_PROPERTIES.Value = EditorGUILayout.BeginFoldoutHeaderGroup(SHOW_MATERIAL_PROPERTIES, "Material settings");
|
|
if (SHOW_MATERIAL_PROPERTIES)
|
|
{
|
|
bool prevGuiEnabled = GUI.enabled;
|
|
if (targetMaterials.Any(m => m.hideFlags == HideFlags.HideAndDontSave))
|
|
{
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
EditorGUILayout.HelpBox("Create a new Material to edit", MessageType.Info);
|
|
if (GUILayout.Button("Create Material", GUILayout.ExpandHeight(true)))
|
|
{
|
|
var path = EditorUtility.SaveFilePanelInProject("Save New Material", "Translucent Image Material", "mat", "");
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
var material = Instantiate(HAVE_PARAFORM
|
|
? DefaultResources.Instance.paraformMaterial
|
|
: DefaultResources.Instance.material);
|
|
m_Material.objectReferenceValue = material;
|
|
AssetDatabase.CreateAsset(material, path);
|
|
}
|
|
}
|
|
}
|
|
GUI.enabled = false;
|
|
}
|
|
|
|
CreateCachedEditor(targetMaterials, typeof(MaterialEditor), ref materialEditor);
|
|
var materialProperties = MaterialEditor.GetMaterialProperties(targetMaterials);
|
|
TranslucentImageShaderGUI.DrawProperties((MaterialEditor)materialEditor, materialProperties, true);
|
|
|
|
GUI.enabled = prevGuiEnabled;
|
|
}
|
|
EditorGUILayout.EndFoldoutHeaderGroup();
|
|
}
|
|
|
|
|
|
if (change.changed)
|
|
{
|
|
foreach (var ti in tiList)
|
|
{
|
|
if (ti.materialForRendering != ti.material)
|
|
{
|
|
Undo.RecordObject(ti.materialForRendering, $"Modify material {ti.material.name}");
|
|
TranslucentImage.CopyMaterialPropertiesTo(ti.material, ti.materialForRendering);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ValidateSource()
|
|
{
|
|
CheckMaterialUsedInDifferentSource();
|
|
needValidateSource = false;
|
|
}
|
|
|
|
void ValidateMaterial()
|
|
{
|
|
CheckMaterialUsedInDifferentSource();
|
|
CheckCorrectShader();
|
|
needValidateMaterial = false;
|
|
}
|
|
|
|
private void CheckCorrectShader()
|
|
{
|
|
usingIncorrectShader = tiList.Any(ti => !ti.material.shader.name.Contains("TranslucentImage"));
|
|
}
|
|
|
|
private void CheckMaterialUsedInDifferentSource()
|
|
{
|
|
if (!tiList[0].source
|
|
|| tiList[0].material.IsKeywordEnabled(ShaderID.KW_BACKGROUND_MODE_OPAQUE))
|
|
{
|
|
materialUsedInDifferentSource = false;
|
|
return;
|
|
}
|
|
|
|
var diffSource = Shims.FindObjectsOfType<TranslucentImage>()
|
|
.Where(ti => ti.source != tiList[0].source)
|
|
.ToList();
|
|
|
|
if (!diffSource.Any())
|
|
{
|
|
materialUsedInDifferentSource = false;
|
|
return;
|
|
}
|
|
|
|
var sameMat = diffSource.GroupBy(ti => ti.material).ToList();
|
|
|
|
materialUsedInDifferentSource = sameMat.Any(group => group.Key == tiList[0].material);
|
|
|
|
needValidateMaterial = false;
|
|
}
|
|
}
|
|
}
|