阶段性完成

This commit is contained in:
SoulliesOfficial
2025-12-08 05:27:53 -05:00
parent ef7b479712
commit f7af60351b
8770 changed files with 15637030 additions and 208354 deletions

View File

@@ -0,0 +1,427 @@
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;
}
}
}