场景设计

This commit is contained in:
SoulliesOfficial
2026-01-12 03:22:16 -05:00
parent 33b1795c1f
commit d94241f36c
8645 changed files with 1242757 additions and 1039728 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c3efbebad5114aa4eae3f9b1dbdae53d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,195 @@
//--------------------------------------------------------------------------//
// Copyright 2023-2025 Chocolate Dinosaur Ltd. All rights reserved. //
// For full documentation visit https://www.chocolatedinosaur.com //
//--------------------------------------------------------------------------//
using UnityEngine;
using UnityEditor;
namespace ChocDino.UIFX.Editor
{
internal struct AboutButton
{
public GUIContent title;
public string url;
public AboutButton(string title, string url)
{
this.title = new GUIContent(title);
this.url = url;
}
}
internal struct AboutSection
{
public GUIContent title;
public AboutButton[] buttons;
public AboutSection(string title)
{
this.title = new GUIContent(title);
this.buttons = null;
}
}
internal class AboutToolbar
{
private int _selectedIndex = -1;
private AboutInfo[] _infos;
public AboutToolbar(AboutInfo[] infos)
{
_infos = infos;
}
internal void OnGUI()
{
if (!Preferences.ShowHeaderAboutButtons)
{
return;
}
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
for (int i = 0; i < _infos.Length; i++)
{
if (_infos[i].Visible())
{
if (_infos[i].OnHeaderGUI())
{
if (i != _selectedIndex)
{
if (_selectedIndex >= 0)
{
_infos[_selectedIndex].isExpanded = false;
}
_selectedIndex = i;
}
}
}
}
GUILayout.EndHorizontal();
if (_selectedIndex >= 0)
{
_infos[_selectedIndex].OnGUI();
}
}
}
/// <summary>
/// A customisable UI window that displays basic information about the asset/component and has
/// categories of buttons that link to documentation and support
/// </summary>
internal class AboutInfo
{
private string iconPath;
private GUIContent title;
internal AboutSection[] sections;
private GUIContent icon;
private GUIContent buttonLabelOpen;
private GUIContent buttonLabelClosed;
private System.Predicate<bool> showAction;
internal bool isExpanded = false;
private static GUIStyle paddedBoxStyle;
private static GUIStyle richBoldLabelStyle;
private static GUIStyle richButtonStyle;
private static GUIStyle titleStyle;
public AboutInfo(string buttonLabel, string title, string iconPath, System.Predicate<bool> showAction = null)
{
this.title = new GUIContent(title);
this.iconPath = iconPath;
this.buttonLabelOpen = new GUIContent("▼ " + buttonLabel);
this.buttonLabelClosed = new GUIContent("► " + buttonLabel);
this.showAction = showAction;
sections = null;
}
internal bool Visible()
{
if (this.showAction != null)
{
return showAction.Invoke(true);
}
return true;
}
internal bool OnHeaderGUI()
{
isExpanded = GUILayout.Toggle(isExpanded, isExpanded?this.buttonLabelOpen:this.buttonLabelClosed, GUI.skin.button);
return isExpanded;
}
internal void OnGUI()
{
if (paddedBoxStyle == null)
{
paddedBoxStyle = new GUIStyle(GUI.skin.window);
paddedBoxStyle.padding = new RectOffset(8, 8, 16, 16);
}
if (titleStyle == null)
{
titleStyle = new GUIStyle(EditorStyles.largeLabel);
titleStyle.wordWrap = true;
titleStyle.richText = true;
titleStyle.alignment = TextAnchor.UpperCenter;
}
if (richBoldLabelStyle == null)
{
richBoldLabelStyle = new GUIStyle(EditorStyles.boldLabel);
richBoldLabelStyle.richText = true;
richBoldLabelStyle.alignment = TextAnchor.UpperCenter;
richBoldLabelStyle.margin.top = 20;
richBoldLabelStyle.margin.bottom = 10;
richBoldLabelStyle.wordWrap = true;
richBoldLabelStyle.fontSize = 14;
}
if (richButtonStyle == null)
{
richButtonStyle = new GUIStyle(GUI.skin.button);
richButtonStyle.richText = true;
richButtonStyle.stretchWidth = true;
}
if (this.icon == null)
{
this.icon = new GUIContent(Resources.Load<Texture2D>(this.iconPath));
}
if (isExpanded)
{
GUILayout.BeginVertical(paddedBoxStyle);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label(this.icon);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Label(this.title, titleStyle);
foreach (AboutSection section in this.sections)
{
GUILayout.Label(section.title, richBoldLabelStyle);
GUILayout.BeginVertical();
if (section.buttons != null)
{
foreach (AboutButton button in section.buttons)
{
if (GUILayout.Button(button.title, richButtonStyle))
{
Application.OpenURL(button.url);
}
}
}
GUILayout.EndVertical();
}
GUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.Space();
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c21bdd0f568f3e74cbf56ac6d3add39b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 274847
packageName: UIFX - Glow Filter
packageVersion: 1.9.10
assetPath: Assets/ChocDino/UIFX/Editor/Scripts/Common/AboutInfo.cs
uploadId: 833966

View File

@@ -0,0 +1,242 @@
//--------------------------------------------------------------------------//
// Copyright 2023-2025 Chocolate Dinosaur Ltd. All rights reserved. //
// For full documentation visit https://www.chocolatedinosaur.com //
//--------------------------------------------------------------------------//
using UnityEngine;
using UnityEditor;
namespace ChocDino.UIFX.Editor
{
public class BaseEditor : UnityEditor.Editor
{
protected const string s_aboutHelp = "About & Help";
protected static readonly string DiscordUrl = "https://discord.gg/wKRzKAHVUE";
protected static readonly string ForumBundleUrl = "https://discussions.unity.com/t/released-uifx-bundle-advanced-effects-for-unity-ui/940575";
protected static readonly string GithubUrl = "https://github.com/Chocolate-Dinosaur/UIFX/issues";
protected static readonly string SupportEmailUrl = "mailto:support@chocdino.com";
protected static readonly string UIFXBundleWebsiteUrl = "https://www.chocdino.com/products/uifx/bundle/about/";
protected static readonly string AssetStoreBundleUrl = "https://assetstore.unity.com/packages/slug/266945?aid=1100lSvNe";
protected static readonly string AssetStoreBundleReviewUrl = "https://assetstore.unity.com/packages/slug/266945?aid=1100lSvNe#reviews";
internal static readonly AboutInfo s_upgradeToBundle =
new AboutInfo("Upgrade ★", "This asset is part of the <b>UIFX Bundle</b> asset.\r\n\r\nAs an existing customer you are entitled to a discounted upgrade!", "uifx-logo-bundle", BaseEditor.ShowUpgradeBundleButton)
{
sections = new AboutSection[]
{
new AboutSection("Upgrade")
{
buttons = new AboutButton[]
{
new AboutButton("<color=#ffd700>★ </color>Upgrade to UIFX Bundle<color=#ffd700> ★</color>", AssetStoreBundleUrl),
}
},
new AboutSection("Read More")
{
buttons = new AboutButton[]
{
new AboutButton("About UIFX Bundle", UIFXBundleWebsiteUrl),
}
},
}
};
internal static bool ShowUpgradeBundleButton(bool dummy)
{
return !DetectUIFXBundle();
}
internal static bool DetectUIFXBundle()
{
// This GUID is from FillGradientFilterEditor.cs.meta which is currently only included in the UIFX Bundle.
const string fileGUID = "df03afa3ecd8c6941a0462c7c870ae83";
return !string.IsNullOrEmpty(AssetDatabase.GUIDToAssetPath(fileGUID));
}
// <summary>
// Creates a button that toggles between two texts but maintains the same size by using the size of the largest.
// This is useful so that the button doesn't change size resulting in the mouse cursor no longer being over the button.
// </summary>
protected bool ToggleButton(bool value, GUIContent labelTrue, GUIContent labelFalse)
{
float maxWidth = Mathf.Max(GUI.skin.button.CalcSize(labelTrue).x, GUI.skin.button.CalcSize(labelFalse).x);
GUIContent content = value ? labelTrue : labelFalse;
return GUILayout.Button(content, GUILayout.Width(maxWidth));
}
protected void EnumAsToolbarCompact(SerializedProperty prop, GUIContent displayName = null)
{
if (displayName == null)
{
displayName = new GUIContent(prop.displayName);
}
if (prop.hasMultipleDifferentValues)
{
EditorGUILayout.PropertyField(prop, displayName);
return;
}
Rect rect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty(rect, displayName, prop);
EditorGUI.PrefixLabel(rect, displayName);
rect.xMin += EditorGUIUtility.labelWidth;
EditorGUI.BeginChangeCheck();
int newIndex = prop.enumValueIndex;
newIndex = GUI.Toolbar(rect, newIndex, prop.enumDisplayNames);
// Only assign the value back if it was actually changed by the user.
// Otherwise a single value will be assigned to all objects when multi-object editing,
// even when the user didn't touch the control.
if (EditorGUI.EndChangeCheck())
{
prop.enumValueIndex = newIndex;
}
EditorGUI.EndProperty();
}
protected void EnumAsToolbar(SerializedProperty prop, GUIContent displayName = null)
{
if (displayName == null)
{
displayName = new GUIContent(prop.displayName);
}
if (prop.hasMultipleDifferentValues)
{
EditorGUILayout.PropertyField(prop, displayName);
return;
}
if (!EditorGUIUtility.wideMode)
{
EditorGUILayout.PropertyField(prop, displayName);
}
else
{
Rect rect = EditorGUILayout.GetControlRect(true);
EditorGUI.BeginProperty(rect, displayName, prop);
EditorGUI.PrefixLabel(rect, displayName);
rect.xMin += EditorGUIUtility.labelWidth;
EditorGUI.BeginChangeCheck();
int newIndex = GUI.Toolbar(rect, prop.enumValueIndex, prop.enumDisplayNames);
// Only assign the value back if it was actually changed by the user.
// Otherwise a single value will be assigned to all objects when multi-object editing,
// even when the user didn't touch the control.
if (EditorGUI.EndChangeCheck())
{
prop.enumValueIndex = newIndex;
}
EditorGUI.EndProperty();
}
}
protected void TextureScaleOffset(SerializedProperty propTexture, SerializedProperty propScale, SerializedProperty propOffset, GUIContent displayName)
{
EditorGUILayout.PropertyField(propTexture);
//EditorGUILayout.PropertyField(_propTextureOffset, Content_Offset);
//EditorGUILayout.PropertyField(_propTextureScale, Content_Scale);
Rect rect = EditorGUILayout.GetControlRect(true, 2 * (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing), EditorStyles.layerMaskField);
EditorGUI.BeginChangeCheck();
Vector4 scaleOffset = new Vector4(propScale.vector2Value.x, propScale.vector2Value.y, propOffset.vector2Value.x, propOffset.vector2Value.y);
EditorGUI.indentLevel++;
scaleOffset = MaterialEditor.TextureScaleOffsetProperty(rect, scaleOffset, false);
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
{
propScale.vector2Value = new Vector2(scaleOffset.x, scaleOffset.y);
propOffset.vector2Value = new Vector2(scaleOffset.z, scaleOffset.w);
}
}
protected SerializedProperty VerifyFindProperty(string propertyPath)
{
SerializedProperty result = serializedObject.FindProperty(propertyPath);
Debug.Assert(result != null);
if (result == null)
{
Debug.LogError("Failed to find property '" + propertyPath + "' in object '" + serializedObject.ToString()+ "'");
}
return result;
}
internal static SerializedProperty VerifyFindPropertyRelative(SerializedProperty property, string relativePropertyPath)
{
SerializedProperty result = null;
Debug.Assert(property != null);
if (property == null)
{
Debug.LogError("Property is null while finding relative property '"+ relativePropertyPath + "'");
}
else
{
result = property.FindPropertyRelative(relativePropertyPath);
Debug.Assert(result != null);
if (result == null)
{
Debug.LogError("Failed to find relative property '" + relativePropertyPath + "' in property '" + property.name + "'");
}
}
return result;
}
#if false
void ShowAlignmentSelector()
{
GUILayoutOption layout = GUILayout.ExpandWidth(false);
GUIStyle style = UnityEditor.EditorStyles.toolbarButton;
//style.margin = new RectOffset(0, 0, 0, 0);
//style.border = new RectOffset(0, 0, 0, 0);
bool toggle;
GUILayout.BeginVertical();
GUILayout.BeginHorizontal();
toggle = _propGradientCenterX.floatValue == -1f;
toggle = GUILayout.Toggle(toggle, "┏", style, layout);
GUILayout.Toggle(false, "┳", style, layout);
GUILayout.Toggle(false, "┓", style, layout);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Toggle(false, "┣", style, layout);
GUILayout.Toggle(false, "╋", style, layout);
GUILayout.Toggle(false, "┫", style, layout);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Toggle(false, "┗", style, layout);
GUILayout.Toggle(false, "┻", style, layout);
GUILayout.Toggle(false, "┛", style, layout);
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
#endif
internal static Gradient GetGradient(SerializedProperty gradientProperty)
{
#if UNITY_2022_1_OR_NEWER
return gradientProperty.gradientValue;
#else
System.Reflection.PropertyInfo propertyInfo = typeof(SerializedProperty).GetProperty("gradientValue", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (propertyInfo == null) { return null; }
else { return propertyInfo.GetValue(gradientProperty, null) as Gradient; }
#endif
}
internal static void SetGradient(SerializedProperty gradientProperty, Gradient value)
{
#if UNITY_2022_1_OR_NEWER
gradientProperty.gradientValue = value;
#else
System.Reflection.PropertyInfo propertyInfo = typeof(SerializedProperty).GetProperty("gradientValue", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (propertyInfo != null) { propertyInfo.SetValue(gradientProperty, value); }
#endif
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c1fb9a5a2bdb55b449705cc16d67f6dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 274847
packageName: UIFX - Glow Filter
packageVersion: 1.9.10
assetPath: Assets/ChocDino/UIFX/Editor/Scripts/Common/BaseEditor.cs
uploadId: 833966

View File

@@ -0,0 +1,294 @@
//--------------------------------------------------------------------------//
// Copyright 2023-2025 Chocolate Dinosaur Ltd. All rights reserved. //
// For full documentation visit https://www.chocolatedinosaur.com //
//--------------------------------------------------------------------------//
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace ChocDino.UIFX.Editor
{
internal static class Preferences
{
internal static readonly string SettingsPath = "Project/Chocolate Dinosaur/UIFX";
private const string KeyPrefix = "UIFX.";
private const string BakedImageSubfolderKey = KeyPrefix + "BakedImageSubfolder";
private const string ShowHeaderAboutButtonsKey = KeyPrefix + "ShowHeaderAboutButtons";
private const string ShowFooterBakeButtonsKey = KeyPrefix + "ShowFooterBakeButtons";
private const string CameraSourcePreviewExpandKey = KeyPrefix + "CameraSource.PreviewExpanded";
internal const string DefaultBakedImageAssetsSubfolder = "Baked-Images";
internal static string BakedImageSubfolder
{
get { return EditorPrefs.GetString(BakedImageSubfolderKey, DefaultBakedImageAssetsSubfolder); }
set { EditorPrefs.SetString(BakedImageSubfolderKey, value); }
}
internal static bool ShowHeaderAboutButtons
{
get { return EditorPrefs.GetBool(ShowHeaderAboutButtonsKey, true); }
set { EditorPrefs.SetBool(ShowHeaderAboutButtonsKey, value); }
}
internal static bool ShowFooterBakeButtons
{
get { return EditorPrefs.GetBool(ShowFooterBakeButtonsKey, true); }
set { EditorPrefs.SetBool(ShowFooterBakeButtonsKey, value); }
}
internal static bool CameraSourcePreviewExpand
{
get { return EditorPrefs.GetBool(CameraSourcePreviewExpandKey, true); }
set { EditorPrefs.SetBool(CameraSourcePreviewExpandKey, value); }
}
[SettingsProvider]
static SettingsProvider CreateSettingsProvider()
{
return new UIFXSettingsProvider(SettingsPath, SettingsScope.Project);
}
private class UIFXSettingsProvider : SettingsProvider
{
public UIFXSettingsProvider(string path, SettingsScope scope) : base(path, scope)
{
this.keywords = new HashSet<string>(new[] { "UIFX", "Chocolate", "Dinosaur", "ChocDino", "UI", "GUI", "UGUI" });
}
private static readonly GUIContent Content_BakedImagesFolder = new GUIContent("Baked Images Folder", "Folder path for baked images. Path is relative to Assets folder.");
private static readonly GUIContent Content_ShowHeaderAboutButtons = new GUIContent("Show Header About Buttons", "Show the about/help buttons that appear at the top of each UIFX component.");
private static readonly GUIContent Content_ShowFooterBakeButtons = new GUIContent("Show Footer Bake Buttons", "Show the bake/save PNG buttons that appear at the bottom of each UIFX component.");
private string _defines;
private string _oldDefines;
private bool _unappliedChanges;
private BuildTargetGroup _buildTarget;
public override void OnActivate(string searchContext, VisualElement rootElement)
{
_buildTarget = BuildTargetGroup.Unknown;
}
public override void OnDeactivate()
{
}
private void CacheDefines()
{
#if UNITY_2023_1_OR_NEWER
var namedBuildTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(_buildTarget);
_oldDefines = _defines = PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget);
#else
_oldDefines = _defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(_buildTarget);
#endif
}
private void ApplyDefines()
{
#if UNITY_2023_1_OR_NEWER
var namedBuildTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(_buildTarget);
PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, _defines);
#else
PlayerSettings.SetScriptingDefineSymbolsForGroup(_buildTarget, _defines);
#endif
CacheDefines();
}
private bool HasDefine(string define)
{
return (_defines.IndexOf(define) >= 0);
}
private void AddDefine(string define)
{
_defines = (_defines + ";" + define + ";").Replace(";;", ";");
}
private void RemoveDefine(string define)
{
_defines = _defines.Replace(define, "").Replace(";;", ";");
}
private bool HasDefineChanged(string define)
{
bool a = HasDefine(define);
bool b = (_oldDefines.IndexOf(define) >= 0);
return (a != b);
}
public override void OnTitleBarGUI()
{
if (_unappliedChanges)
{
GUI.color = Color.green;
if (GUILayout.Button("Apply Changes"))
{
ApplyDefines();
}
GUI.color = Color.white;
}
}
public override void OnFooterBarGUI()
{
}
public override void OnGUI(string searchContext)
{
const string UIFX_SUPPORT_TEXT_ANIMATOR = "UIFX_SUPPORT_TEXT_ANIMATOR";
const string UIFX_BETA = "UIFX_BETA";
const string UIFX_UNRELEASED = "UIFX_UNRELEASED";
const string UIFX_FILTER_HIDE_INSPECTOR_PREVIEW = "UIFX_FILTER_HIDE_INSPECTOR_PREVIEW";
const string UIFX_LOG = "UIFX_LOG";
const string UIFX_FILTER_DEBUG = "UIFX_FILTER_DEBUG";
const string UIFX_FILTERS_FORCE_UPDATE_PLAYMODE = "UIFX_FILTERS_FORCE_UPDATE_PLAYMODE";
const string UIFX_FILTERS_FORCE_UPDATE_EDITMODE = "UIFX_FILTERS_FORCE_UPDATE_EDITMODE";
EditorGUILayout.Space();
ShowEditorPref(Content_BakedImagesFolder, BakedImageSubfolderKey, DefaultBakedImageAssetsSubfolder);
EditorGUI.BeginChangeCheck();
ShowEditorPref(Content_ShowHeaderAboutButtons, ShowHeaderAboutButtonsKey, true);
ShowEditorPref(Content_ShowFooterBakeButtons, ShowFooterBakeButtonsKey, true);
if (EditorGUI.EndChangeCheck())
{
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
EditorGUILayout.Space();
GUILayout.Label("Active platform is: " + BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget).ToString());
bool isActivePlatform = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget) == _buildTarget;
bool changes = false;
{
if (isActivePlatform)
{
GUI.color = new Color(1.1f, 1.1f, 1.1f, 1f);
}
BuildTargetGroup group = EditorGUILayout.BeginBuildTargetSelectionGrouping();
if (_buildTarget != group)
{
_buildTarget = group;
CacheDefines();
}
changes |= ShowDefineToggle("Text Animator Support (Requires Febucci.TextAnimator package)", UIFX_SUPPORT_TEXT_ANIMATOR);
changes |= ShowDefineToggle("Hide Inspector Filter Preview", UIFX_FILTER_HIDE_INSPECTOR_PREVIEW);
changes |= ShowDefineToggle("Beta Features", UIFX_BETA);
EditorGUILayout.EndBuildTargetSelectionGrouping();
}
GUI.color = Color.white;
EditorGUILayout.Space();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
if (SystemInfo.deviceName == "DESKTOP-ULTRA")
{
GUILayout.Label("Developer Mode:", EditorStyles.largeLabel);
if (isActivePlatform)
{
GUI.color = new Color(1.1f, 1.1f, 1.1f, 1f);
}
BuildTargetGroup group = EditorGUILayout.BeginBuildTargetSelectionGrouping();
if (_buildTarget != group)
{
_buildTarget = group;
CacheDefines();
}
changes |= ShowDefineToggle("Debug Logging", UIFX_LOG);
changes |= ShowDefineToggle("Filter Debugging", UIFX_FILTER_DEBUG);
changes |= ShowDefineToggle("Filter Force Update in Play Mode", UIFX_FILTERS_FORCE_UPDATE_PLAYMODE);
changes |= ShowDefineToggle("Filter Force Update in Edit Mode", UIFX_FILTERS_FORCE_UPDATE_EDITMODE);
changes |= ShowDefineToggle("Unreleased Features", UIFX_UNRELEASED);
EditorGUILayout.EndBuildTargetSelectionGrouping();
GUI.color = Color.white;
EditorGUILayout.Space();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
}
_unappliedChanges = changes;
Links();
}
private void Links()
{
const string DiscordCommunityUrl = "https://discord.gg/wKRzKAHVUE";
const string DocumentationUrl = "https://www.chocdino.com/products/category/components/";
const string AssetStoreUrl = "https://assetstore.unity.com/publishers/80225?aid=1100lSvNe";
GUILayout.Label("Chocolate Dinosaur Links:", EditorStyles.largeLabel);
if (GUILayout.Button("UIFX Documentation", EditorStyles.miniButton))
{
Application.OpenURL(DocumentationUrl);
}
if (GUILayout.Button("Discord Community", EditorStyles.miniButton))
{
Application.OpenURL(DiscordCommunityUrl);
}
if (GUILayout.Button("Our Assets", EditorStyles.miniButton))
{
Application.OpenURL(AssetStoreUrl);
}
}
private bool ShowDefineToggle(string label, string define)
{
bool enabled = HasDefine(define);
bool changed = HasDefineChanged(define);
if (changed)
{
label += " *";
}
bool newState = GUILayout.Toggle(enabled, label);
if (newState != enabled)
{
if (newState)
{
AddDefine(define);
}
else
{
RemoveDefine(define);
}
}
return HasDefineChanged(define);
}
private static void ShowEditorPref(GUIContent label, string prefKey, string defaultValue)
{
var oldValue = EditorPrefs.GetString(prefKey, defaultValue);
GUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel(label, EditorStyles.textField);
var newValue = EditorGUILayout.TextField(oldValue);
if (newValue != oldValue)
{
EditorPrefs.SetString(prefKey, newValue);
}
GUILayout.EndHorizontal();
}
private static void ShowEditorPref(GUIContent label, string prefKey, bool defaultValue)
{
var oldValue = EditorPrefs.GetBool(prefKey, defaultValue);
var newValue = GUILayout.Toggle(oldValue, label);
if (newValue != oldValue)
{
EditorPrefs.SetBool(prefKey, newValue);
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a2588906ec7e234419d74d5acae7d54e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 274847
packageName: UIFX - Glow Filter
packageVersion: 1.9.10
assetPath: Assets/ChocDino/UIFX/Editor/Scripts/Common/Preferences.cs
uploadId: 833966

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 990985a698e26ef4c8009d73f7f4d56f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,727 @@
//--------------------------------------------------------------------------//
// Copyright 2023-2025 Chocolate Dinosaur Ltd. All rights reserved. //
// For full documentation visit https://www.chocolatedinosaur.com //
//--------------------------------------------------------------------------//
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
namespace ChocDino.UIFX.Editor
{
internal class FilterBaseEditor : BaseEditor
{
protected static readonly string TextMeshProGraphicTypeName = "TMPro.TextMeshProUGUI";
protected static readonly string FilterStackTextMeshProFullTypeName = "ChocDino.UIFX.FilterStackTextMeshPro, ChocDino.UIFX.TMP";
protected static readonly string FilterStackTextMeshProComponentName = "FilterStackTextMeshPro";
protected static readonly GUIContent Content_R = new GUIContent("R");
protected static readonly GUIContent Content_SpaceCharacter = new GUIContent(" ");
protected static readonly GUIContent Content_Size = new GUIContent("Size");
protected static readonly GUIContent Content_Color = new GUIContent("Color");
protected static readonly GUIContent Content_Colors = new GUIContent("Colors");
protected static readonly GUIContent Content_Apply = new GUIContent("Apply");
protected static readonly GUIContent Content_Border = new GUIContent("Border");
protected static readonly GUIContent Content_Fill = new GUIContent("Fill");
protected static readonly GUIContent Content_Preview = new GUIContent("Preview");
protected static readonly GUIContent Content_Stop = new GUIContent("Stop");
protected static readonly GUIContent Content_Texture = new GUIContent("Texture");
protected static readonly GUIContent Content_Gradient = new GUIContent("Gradient");
protected static readonly GUIContent Content_Reverse = new GUIContent("Reverse");
private static readonly GUIContent Content_Debug = new GUIContent("Debug");
private static readonly GUIContent Content_Strength = new GUIContent("Strength");
private static readonly GUIContent Content_SaveToPNG = new GUIContent("Save to PNG");
private static readonly GUIContent Content_BakeToImage = new GUIContent("Bake To Image", "Bake all filters above to an Image component. Baking currently doesn't support: world-space canvas, rotation or scale, and unmatching anchor min/max values, TextMeshPro.");
private static readonly GUIContent Content_PreviewTitle= new GUIContent("UIFX - Filters");
private void ShowSaveToPngButton()
{
// TODO: Add baking to Image option that bakes to a new GameObject and doesn't destroy the old object
// TODO: Convert the image baking buttons into a EditorGUILayout.DropDownToggle()
if (GUILayout.Button(Content_SaveToPNG))
{
foreach (FilterBase filter in this.targets)
{
System.IO.Directory.CreateDirectory(Application.dataPath + "/../Captures/");
string timestamp = System.DateTime.Now.ToString("yyyyMMdd-HHmmss");
string filterName = filter.GetType().Name;
string path = System.IO.Path.GetFullPath(Application.dataPath + string.Format("/../Captures/Image-{0}-{1}-{2}.png", timestamp, filter.gameObject.name, filterName));
if (filter.SaveToPNG(path))
{
Debug.Log("Saving image to: <b>" + path + "</b>");
}
else
{
Debug.LogError("Failed to save image to: <b>" + path + "</b>");
}
}
}
}
#if !UIFX_FILTER_HIDE_INSPECTOR_PREVIEW
private string GetFilterShortName()
{
return this.target.GetType().Name;
}
public override GUIContent GetPreviewTitle()
{
return Content_PreviewTitle;
}
public override bool HasPreviewGUI()
{
// We can't support multiple targets because the below logic to only show the last item doesn't work
if (targets.Length > 1) return false;
var filter = target as FilterBase;
if (!filter.isActiveAndEnabled) return false;
// Only allow the last ENABLED filter in the stack to preview
var filters = filter.gameObject.GetComponents<FilterBase>();
FilterBase lastEnabledFilter = null;
for (int i = 0; i < filters.Length; i++)
{
if (filters[i].isActiveAndEnabled && filters[i].IsFilterEnabled() && filters[i].CanSelfRender())
{
lastEnabledFilter = filters[i];
}
}
return (lastEnabledFilter == filter);
}
public override string GetInfoString()
{
var filter = target as FilterBase;
return filter.GetDebugString();
}
public override void OnPreviewSettings()
{
ShowSaveToPngButton();
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (Event.current.type == EventType.Repaint)
{
var filter = target as FilterBase;
EditorGUI.DrawTextureTransparent(r, Texture2D.blackTexture, ScaleMode.StretchToFill);
var texture = filter.ResolveToTexture();
if (texture)
{
GUI.DrawTexture(r, texture, ScaleMode.ScaleToFit, true);
}
}
}
#endif
private static void DrawTexture(Texture texture, bool showAlphaBlended)
{
if (texture)
{
GUILayout.Label(string.Format("{0} {1}x{2}:{3}", texture.name, texture.width, texture.height, texture.updateCount));
if (showAlphaBlended)
{
{
Rect r = GUILayoutUtility.GetRect(256f, 256f);
EditorGUI.DrawTextureTransparent(r, Texture2D.blackTexture, ScaleMode.StretchToFill);
GUI.DrawTexture(r, texture, ScaleMode.ScaleToFit, true);
}
}
else
{
GUILayout.BeginHorizontal();
{
float aspect = (float)texture.width / (float)texture.height;
Rect r = GUILayoutUtility.GetAspectRect(aspect * 2f, GUILayout.ExpandWidth(true));
Rect rc = r;
rc.width /= 2f;
GUI.DrawTexture(rc, texture, ScaleMode.ScaleToFit, false);
rc.x += rc.width;
EditorGUI.DrawTextureAlpha(rc, texture, ScaleMode.ScaleToFit);
}
GUILayout.EndHorizontal();
}
GUILayout.BeginHorizontal();
if (GUILayout.Button("Select"))
{
UnityEditor.Selection.activeObject = texture;
}
if (GUILayout.Button("Save"))
{
SaveTexture(texture as RenderTexture);
}
GUILayout.EndHorizontal();
}
}
private bool CanBakeFiltersToImage(FilterBase filter)
{
if (!filter.CanApplyFilter()) { return false; }
var graphic = filter.GetComponent<Graphic>();
if (!graphic) { return false; }
var graphicTypeName = graphic.GetType().ToString();
if (graphicTypeName.Contains(TextMeshProGraphicTypeName)) { return false; }
var canvas = graphic.canvas;
if (!canvas) { return false; }
// NOTE: In the future when working in canvas space we'll be able to support these
if (canvas.renderMode == RenderMode.WorldSpace) { return false; }
var xform = filter.GetComponent<RectTransform>();
if (!xform) { return false; }
// NOTE: In the future when working in canvas space we'll be able to support these
if (xform.localRotation != Quaternion.identity) { return false;}
if (xform.localScale != Vector3.one) { return false;}
// NOTE: Currently just haven't figured out the math for this case where anchor min/max are different
if (xform.anchorMin.x != xform.anchorMax.x) { return false; }
if (xform.anchorMin.y != xform.anchorMax.y) { return false; }
return true;
}
private bool CanSaveFilterToPng(FilterBase filter)
{
if (!filter.CanApplyFilter()) { return false; }
var graphic = filter.GetComponent<Graphic>();
if (!graphic) { return false; }
var graphicTypeName = graphic.GetType().ToString();
if (graphicTypeName.Contains(TextMeshProGraphicTypeName)) { return false; }
var canvas = graphic.canvas;
if (!canvas) { return false; }
// NOTE: In the future when working in canvas space we'll be able to support these
if (canvas.renderMode == RenderMode.WorldSpace) { return false; }
var xform = filter.GetComponent<RectTransform>();
if (!xform) { return false; }
return true;
}
private bool BakeFiltersToImage(FilterBase filter, bool makeCopy)
{
Vector2 anchorOffset = Vector2.zero;
{
var graphic = filter.GetComponent<Graphic>();
if (graphic)
{
var xform = graphic.GetComponent<RectTransform>();
Rect r = filter.GetLocalRect();
r.max += filter._lastRenderAdjustRightUp;
r.min -= filter._lastRenderAdjustLeftDown;
anchorOffset.x = r.x + r.width * xform.pivot.x + xform.anchoredPosition.x;
anchorOffset.y = r.y + r.height * xform.pivot.y + xform.anchoredPosition.y;
}
}
// Bake to new texture asset
string uniqueFileName;
{
string timestamp = System.DateTime.Now.ToString("yyyyMMdd-HHmmss");
string subFolder = Preferences.BakedImageSubfolder;
subFolder = System.IO.Path.Combine("Assets/", subFolder);
if (!subFolder.EndsWith("/")) { subFolder += "/"; }
subFolder = System.IO.Path.Combine(subFolder, string.Format("Baked-{0}-{1}.png", timestamp, filter.gameObject.name));
var fullPath = System.IO.Path.GetFullPath(Application.dataPath + "/../" + subFolder);
string directoryPath = System.IO.Path.GetDirectoryName(fullPath);
if (!System.IO.Directory.Exists(directoryPath))
{
System.IO.Directory.CreateDirectory(directoryPath);
}
uniqueFileName = AssetDatabase.GenerateUniqueAssetPath(subFolder);
fullPath = System.IO.Path.GetFullPath(Application.dataPath + "/../" + uniqueFileName);
AssetDatabase.StartAssetEditing();
filter.SaveToPNG(fullPath);
AssetDatabase.StopAssetEditing();
AssetDatabase.Refresh();
}
// Modify importer settings for new texture asset
TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(uniqueFileName);
if (importer)
{
importer.textureType = TextureImporterType.Sprite;
importer.textureCompression = TextureImporterCompression.Uncompressed;
importer.npotScale = TextureImporterNPOTScale.None;
importer.alphaIsTransparency = true;
importer.mipmapEnabled = false;
importer.sRGBTexture = true;
TextureImporterSettings settings = new TextureImporterSettings();
importer.ReadTextureSettings(settings);
settings.spriteMode = (int)SpriteImportMode.Single;
settings.spriteMeshType = SpriteMeshType.FullRect;
settings.spriteGenerateFallbackPhysicsShape = false;
importer.SetTextureSettings(settings);
EditorUtility.SetDirty(importer);
importer.SaveAndReimport();
AssetDatabase.WriteImportSettingsIfDirty(uniqueFileName);
}
// Get the asset
var textureAsset = (Texture2D)AssetDatabase.LoadAssetAtPath(uniqueFileName, typeof(Texture2D));
Sprite spriteAsset = null;
{
Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath(uniqueFileName);
if (objs != null)
{
foreach (Object obj in objs)
{
if (obj.GetType() == typeof(Sprite))
{
spriteAsset = obj as Sprite;
break;
}
}
}
}
GameObject targetGo = filter.gameObject;
// Make a copy of the GameObject (optional)
if (makeCopy)
{
targetGo = (GameObject)GameObject.Instantiate(filter.gameObject, filter.transform.parent, instantiateInWorldSpace:false);
targetGo.name = filter.gameObject.name + "-Baked";
}
// Get the component index of the original filter
int filterComponentIndex = 0;
{
Component[] sourceComponents = filter.gameObject.GetComponents<Component>();
filterComponentIndex = System.Array.IndexOf(sourceComponents, filter);
}
Component[] components = targetGo.GetComponents<Component>();
int oldGraphicIndex = 0;
bool isRaycastTarget = false;
// Remove the previous Graphic
{
var graphic = targetGo.GetComponent<Graphic>();
if (graphic)
{
isRaycastTarget = graphic.raycastTarget;
oldGraphicIndex = System.Array.IndexOf(components, graphic);
Undo.DestroyObjectImmediate(graphic);
}
}
// Add RawImage component and assign texture
var image = Undo.AddComponent<RawImage>(targetGo);
//image.sprite = spriteAsset;
image.texture = textureAsset;
image.raycastTarget = isRaycastTarget;
//image.preserveAspect = true;
image.maskable = false;
float scale = image.canvas.scaleFactor;
// Move RawImage component to order position of old Graphic
int newGraphicIndex = (components.Length - 1);
int moveDelta = Mathf.Abs(oldGraphicIndex - newGraphicIndex);
for (int i = 0; i < moveDelta; i++)
{
if (newGraphicIndex > oldGraphicIndex) { UnityEditorInternal.ComponentUtility.MoveComponentUp(image); }
else { UnityEditorInternal.ComponentUtility.MoveComponentDown(image); }
}
// Change the RectTransform
{
var xform = image.rectTransform;
xform.sizeDelta = new Vector2(textureAsset.width / scale, textureAsset.height / scale);
xform.anchoredPosition = anchorOffset;
}
// Remove all FilterBase and IMeshModifiers that affect this render
{
int componentIndex = 0;
foreach (var component in components)
{
if (componentIndex <= filterComponentIndex)
{
if (component is FilterBase || component is IMeshModifier)
{
Undo.DestroyObjectImmediate(component);
}
}
componentIndex++;
}
}
// Select the texture so the user knows where it exists
//Selection.activeObject = textureAsset;
//Object prevSelection = Selection.activeObject;
// Select the old or new GameObject
if (makeCopy)
{
Selection.activeGameObject = targetGo;
}
//else
{
// Selection.activeObject = prevSelection;
}
//Undo.DestroyObjectImmediate(filter);
return true;
}
private bool ShowBakeFiltersToImageDialog(FilterBase filter)
{
bool result = false;
int option = EditorUtility.DisplayDialogComplex("Bake To Image", "Do you want to override the current GameObject or bake to a copy of it?", "Override", "Cancel", "Make Copy");
switch (option)
{
// Override.
case 0:
result = BakeFiltersToImage(filter, makeCopy:false);
break;
// Make Copy.
case 2:
result = BakeFiltersToImage(filter, makeCopy:true);
break;
// Cancel.
case 1:
break;
default:
Debug.LogError("Unrecognized option.");
break;
}
return result;
}
internal bool OnInspectorGUI_Baking(FilterBase filter)
{
if (!Preferences.ShowFooterBakeButtons)
{
return false;
}
bool result = false;
EditorGUILayout.Space();
GUILayout.BeginHorizontal();
bool wasEnabled = GUI.enabled;
GUI.enabled = wasEnabled & CanBakeFiltersToImage(filter);
if (GUILayout.Button(Content_BakeToImage))
{
// Use a delay because we're showing a dialog which breaks IMGUI flow
EditorApplication.delayCall += () =>
{
ShowBakeFiltersToImageDialog(filter);
};
}
GUI.enabled = wasEnabled & CanSaveFilterToPng(filter);
ShowSaveToPngButton();
GUI.enabled = wasEnabled;
GUILayout.EndHorizontal();
return result;
}
// Returns true if checks fail and the rest of the inspector shouldn't be shown
internal bool OnInspectorGUI_Check(FilterBase filter)
{
bool result = false;
var graphic = filter.GraphicComponent;
if (graphic)
{
// Check for TextMeshPro in the selection
bool selectionHasTextMeshPro = false;
foreach (var obj in this.targets)
{
var filterInstance = obj as FilterBase;
if (filterInstance.GraphicComponent)
{
if (filterInstance.GraphicComponent.GetType().ToString().Contains(TextMeshProGraphicTypeName))
{
selectionHasTextMeshPro = true;
break;
}
}
}
if (selectionHasTextMeshPro)
{
#if !UIFX_TMPRO
result = true;
EditorGUILayout.HelpBox("TextMeshPro not detected...", MessageType.Error, true);
EditorGUILayout.Space();
#else
bool needsFilterStackTMP = false;
foreach (var obj in this.targets)
{
var filterInstance = obj as FilterBase;
if (filterInstance.GraphicComponent)
{
if (filterInstance.GraphicComponent.GetType().ToString().Contains(TextMeshProGraphicTypeName))
{
if (null == filterInstance.gameObject.GetComponent(FilterStackTextMeshProComponentName))
{
needsFilterStackTMP = true;
break;
}
}
}
}
if (needsFilterStackTMP)
{
result = true;
EditorGUILayout.HelpBox("The FilterStackTextMeshPro component is required to apply filters to TextMeshPro", MessageType.Error, true);
if (GUILayout.Button("Add FilterStackTextMeshPro"))
{
var filterStackType = System.Type.GetType(FilterStackTextMeshProFullTypeName, false);
if (filterStackType != null)
{
foreach (var obj in this.targets)
{
var filterInstance = obj as FilterBase;
if (filterInstance.GraphicComponent)
{
if (filterInstance.GraphicComponent.GetType().ToString().Contains(TextMeshProGraphicTypeName))
{
if (null == filterInstance.gameObject.GetComponent(FilterStackTextMeshProComponentName))
{
filterInstance.gameObject.AddComponent(filterStackType);
}
}
}
}
}
else
{
Debug.LogError("Couldn't find " + FilterStackTextMeshProFullTypeName);
}
}
EditorGUILayout.Space();
}
#endif
}
// Warn user about out of range Canvas.planeDistance
if (filter.IsCanvasPlaneDistanceOutOfRange())
{
EditorGUILayout.HelpBox(FilterBase.s_warnCanvasPlaneDistanceCullingMessage, MessageType.Warning, true);
EditorGUILayout.Space();
}
if (filter.IsTextureTooLarge())
{
EditorGUILayout.HelpBox("Requested texture is larger than the supported size of " + Filters.GetMaxiumumTextureSize() + ", rescaling texture to supported size, this can lead to lower texture quality. Consider invstigating why such a large texture is required.", MessageType.Error, true);
EditorGUILayout.Space();
}
}
return result;
}
internal static void OnInspectorGUI_Debug(FilterBase filter)
{
#if UIFX_FILTER_DEBUG
{
EditorGUILayout.Space();
GUILayout.Label(Content_Debug, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.TextArea(filter.GetDebugString());
EditorGUI.indentLevel--;
EditorGUILayout.Space();
Texture[] textures = filter.GetDebugTextures();
foreach (var texture in textures)
{
DrawTexture(texture, false);
EditorGUILayout.Space();
}
if (filter.isActiveAndEnabled)
{
DrawTexture(filter.ResolveToTexture(), true);
if (GUILayout.Button("Save Final"))
{
filter.SaveToPNG(Application.dataPath + "/../final.png");
}
}
}
#endif
}
internal static void PropertyReset_Slider(SerializedProperty prop, GUIContent label, float min, float max, float resetValue)
{
float buttonWidth = 0f;
if (EditorGUIUtility.wideMode)
{
buttonWidth = GUI.skin.button.CalcSize(Content_R).x;
}
Rect rect = EditorGUILayout.GetControlRect(true);
EditorGUI.BeginProperty(rect, label, prop);
rect.xMax -= buttonWidth;
EditorGUI.BeginChangeCheck();
float newValue = EditorGUI.Slider(rect, label, prop.floatValue, min, max);
if (EditorGUI.EndChangeCheck())
{
prop.floatValue = newValue;
}
if (EditorGUIUtility.wideMode)
{
rect.xMin += rect.width;
rect.xMax += buttonWidth;
{
bool wasEnabled = GUI.enabled;
GUI.enabled = (prop.floatValue != resetValue);
if (GUI.Button(rect, Content_R))
{
prop.floatValue = resetValue;
}
GUI.enabled = wasEnabled;
}
}
EditorGUI.EndProperty();
}
internal static void PropertyReset_Float(SerializedProperty prop, float resetValue)
{
if (!EditorGUIUtility.wideMode)
{
EditorGUILayout.PropertyField(prop);
}
else
{
GUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(prop);
bool wasEnabled = GUI.enabled;
GUI.enabled = (prop.floatValue != resetValue);
if (GUILayout.Button(Content_R, GUILayout.ExpandWidth(false)))
{
prop.floatValue = resetValue;
}
GUI.enabled = wasEnabled;
GUILayout.EndHorizontal();
}
}
internal static void DrawStrengthProperty(SerializedProperty prop)
{
Rect rect = EditorGUILayout.GetControlRect(true);
EditorGUI.BeginProperty(rect, Content_Strength, prop);
float strength = prop.floatValue;
if (DrawStrengthProperty(rect, ref strength))
{
prop.floatValue = strength;
}
EditorGUI.EndProperty();
}
internal static bool DrawStrengthProperty(ref float value)
{
bool hasChanged = false;
Rect rect = EditorGUILayout.GetControlRect(true);
if (DrawStrengthProperty(rect, ref value))
{
hasChanged = true;
}
return hasChanged;
}
internal static bool DrawStrengthProperty(Rect rect, ref float value)
{
bool changed = false;
const float resetValue = 1f;
float buttonWidth = 0f;
if (EditorGUIUtility.wideMode)
{
buttonWidth = GUI.skin.button.CalcSize(Content_R).x;
}
bool isColored = false;
if (value < 1f)
{
isColored = true;
if (value > 0f)
{
GUI.backgroundColor = Color.yellow;
}
else
{
GUI.backgroundColor = Color.red;
}
}
EditorGUI.BeginChangeCheck();
rect.xMax -= buttonWidth;
float newValue = EditorGUI.Slider(rect, Content_Strength, value, 0f, 1f);
if (EditorGUIUtility.wideMode)
{
rect.xMin += rect.width;
rect.xMax += buttonWidth;
bool wasEnabled = GUI.enabled;
GUI.enabled = (value != resetValue);
if (GUI.Button(rect, Content_R))
{
value = newValue = resetValue;
changed = true;
}
GUI.enabled = wasEnabled;
}
if (EditorGUI.EndChangeCheck())
{
value = newValue;
changed = true;
}
if (isColored)
{
GUI.backgroundColor = Color.white;
}
return changed;
}
internal static void DrawDualColors(SerializedProperty col1, SerializedProperty col2, GUIContent label)
{
GUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel(label, EditorStyles.colorField);
EditorGUI.indentLevel-=1; // NOTE: This seems to be a bug in Unity where it shows the indentation with ColorFields, so we have to remove it manually...
EditorGUILayout.PropertyField(col1, GUIContent.none);
EditorGUILayout.PropertyField(col2, GUIContent.none);
EditorGUI.indentLevel+=1;
GUILayout.EndHorizontal();
}
protected static void SaveTexture(RenderTexture texture)
{
#if UNITY_2022_1_OR_NEWER
Texture2D rwTexture = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, mipChain: false, linear: false, createUninitialized: true);
#else
Texture2D rwTexture = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, mipChain: false);
#endif
TextureUtils.WriteToPNG(texture, rwTexture, Application.dataPath + "/../SavedScreen.png");
ObjectHelper.Destroy(ref rwTexture);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 91387ed1db237a14c997b34ed9a7f8ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 274847
packageName: UIFX - Glow Filter
packageVersion: 1.9.10
assetPath: Assets/ChocDino/UIFX/Editor/Scripts/Filters/FilterBaseEditor.cs
uploadId: 833966

View File

@@ -0,0 +1,211 @@
//--------------------------------------------------------------------------//
// Copyright 2023-2025 Chocolate Dinosaur Ltd. All rights reserved. //
// For full documentation visit https://www.chocolatedinosaur.com //
//--------------------------------------------------------------------------//
using UnityEngine;
using UnityEditor;
namespace ChocDino.UIFX.Editor
{
[CustomEditor(typeof(GlowFilter), true)]
[CanEditMultipleObjects]
internal class GlowFilterEditor : FilterBaseEditor
{
private static readonly AboutInfo s_aboutInfo =
new AboutInfo(s_aboutHelp, "UIFX - Glow Filter\n© Chocolate Dinosaur Ltd", "uifx-logo-glow-filter")
{
sections = new AboutSection[]
{
new AboutSection("Asset Guides")
{
buttons = new AboutButton[]
{
new AboutButton("User Guide", "https://www.chocdino.com/products/uifx/glow-filter/about/"),
new AboutButton("Scripting Guide", "https://www.chocdino.com/products/uifx/glow-filter/scripting/"),
new AboutButton("Components Reference", "https://www.chocdino.com/products/uifx/glow-filter/components/glow-filter/"),
new AboutButton("API Reference", "https://www.chocdino.com/products/uifx/glow-filter/API/ChocDino.UIFX/"),
}
},
new AboutSection("Unity Asset Store Review\r\n<color=#ffd700>★★★★☆</color>")
{
buttons = new AboutButton[]
{
new AboutButton("Review <b>UIFX - Glow Filter</b>", "https://assetstore.unity.com/packages/slug/274847?aid=1100lSvNe#reviews"),
new AboutButton("Review <b>UIFX Bundle</b>", AssetStoreBundleReviewUrl),
}
},
new AboutSection("UIFX Support")
{
buttons = new AboutButton[]
{
new AboutButton("Discord Community", DiscordUrl),
new AboutButton("Post to Unity Discussions", ""),
new AboutButton("Post Issues to GitHub", GithubUrl),
new AboutButton("Email Us", SupportEmailUrl),
}
}
}
};
private static readonly AboutToolbar s_aboutToolbar = new AboutToolbar(new AboutInfo[] { s_upgradeToBundle, s_aboutInfo } );
private static readonly GUIContent Content_Shape = new GUIContent("Shape");
private static readonly GUIContent Content_Falloff = new GUIContent("Falloff");
private static readonly GUIContent Content_Distance = new GUIContent("Distance");
private static readonly GUIContent Content_Mode = new GUIContent("Mode");
private static readonly GUIContent Content_Curve = new GUIContent("Curve");
private static readonly GUIContent Content_Energy = new GUIContent("Energy");
private static readonly GUIContent Content_Power = new GUIContent("Power");
private static readonly GUIContent Content_Gamma = new GUIContent("Gamma");
private static readonly GUIContent Content_Offset = new GUIContent("Offset");
private SerializedProperty _propEdgeSide;
private SerializedProperty _propDistanceShape;
private SerializedProperty _propMaxDistance;
private SerializedProperty _propReuseDistanceMap;
private SerializedProperty _propFalloffMode;
private SerializedProperty _propExpFalloffEnergy;
private SerializedProperty _propExpFalloffPower;
private SerializedProperty _propExpFalloffOffset;
private SerializedProperty _propFalloffCurve;
private SerializedProperty _propFalloffCurveGamma;
private SerializedProperty _propFillMode;
private SerializedProperty _propColor;
private SerializedProperty _propGradient;
private SerializedProperty _propGradientTexture;
private SerializedProperty _propGradientOffset;
private SerializedProperty _propGradientGamma;
private SerializedProperty _propGradientReverse;
private SerializedProperty _propBlur;
private SerializedProperty _propSourceAlpha;
private SerializedProperty _propAdditive;
private SerializedProperty _propNoiseScale;
private SerializedProperty _propStrength;
private SerializedProperty _propRenderSpace;
private SerializedProperty _propExpand;
void OnEnable()
{
_propDistanceShape = VerifyFindProperty("_distanceShape");
_propMaxDistance = VerifyFindProperty("_maxDistance");
_propEdgeSide = VerifyFindProperty("_edgeSide");
_propBlur = VerifyFindProperty("_blur");
_propReuseDistanceMap = VerifyFindProperty("_reuseDistanceMap");
_propFalloffMode = VerifyFindProperty("_falloffMode");
_propExpFalloffEnergy = VerifyFindProperty("_expFalloffEnergy");
_propExpFalloffPower = VerifyFindProperty("_expFalloffPower");
_propExpFalloffOffset = VerifyFindProperty("_expFalloffOffset");
_propFalloffCurve = VerifyFindProperty("_falloffCurve");
_propFalloffCurveGamma = VerifyFindProperty("_falloffCurveGamma");
_propFillMode = VerifyFindProperty("_fillMode");
_propColor = VerifyFindProperty("_color");
_propGradient = VerifyFindProperty("_gradient");
_propGradientTexture = VerifyFindProperty("_gradientTexture");
_propGradientOffset = VerifyFindProperty("_gradientOffset");
_propGradientGamma = VerifyFindProperty("_gradientGamma");
_propGradientReverse = VerifyFindProperty("_gradientReverse");
_propAdditive = VerifyFindProperty("_additive");
_propNoiseScale = VerifyFindProperty("_noiseScale");
_propSourceAlpha = VerifyFindProperty("_sourceAlpha");
_propStrength = VerifyFindProperty("_strength");
_propRenderSpace = VerifyFindProperty("_renderSpace");
_propExpand = VerifyFindProperty("_expand");
}
public override void OnInspectorGUI()
{
s_aboutToolbar.OnGUI();
serializedObject.Update();
var filter = this.target as FilterBase;
if (OnInspectorGUI_Check(filter))
{
return;
}
GUILayout.Label(Content_Distance, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EnumAsToolbar(_propEdgeSide);
EnumAsToolbar(_propDistanceShape, Content_Shape);
EditorGUILayout.PropertyField(_propMaxDistance);
EditorGUILayout.PropertyField(_propBlur);
EditorGUILayout.PropertyField(_propReuseDistanceMap);
EditorGUI.indentLevel--;
GUILayout.Label(Content_Falloff, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EnumAsToolbar(_propFalloffMode, Content_Mode);
if (_propFalloffMode.enumValueIndex == (int)GlowFalloffMode.Exponential)
{
EditorGUILayout.PropertyField(_propExpFalloffEnergy, Content_Energy);
EditorGUILayout.PropertyField(_propExpFalloffPower, Content_Power);
EditorGUILayout.PropertyField(_propExpFalloffOffset, Content_Offset);
}
else
{
EditorGUILayout.PropertyField(_propFalloffCurve, Content_Curve);
// Show a warning if curve key values of out of sensible range.
// NOTE: We have to detect whether the curve window has focus currently, otherwise if the HelpBox() appears
// while dragging curve keys, it can cause the keys to not update.
if (!EditorHelper.IsEditingCurve())
{
if (_propFalloffCurve.animationCurveValue.HasOutOfRangeValues(0f, 1f, 0f))
{
EditorGUILayout.HelpBox("Some curve points are outside of the range [0..1]. This might be fine, or could lead to unexpected results.", MessageType.Warning, true);
}
}
EditorGUILayout.PropertyField(_propFalloffCurveGamma, Content_Gamma);
}
EditorGUI.indentLevel--;
GUILayout.Label(Content_Fill, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EnumAsToolbar(_propFillMode, Content_Mode);
if (_propFillMode.enumValueIndex == (int)GlowFillMode.Color)
{
EditorGUILayout.PropertyField(_propColor);
}
if (_propFillMode.enumValueIndex == (int)GlowFillMode.Texture)
{
EditorGUILayout.PropertyField(_propGradientTexture, Content_Texture);
EditorGUILayout.PropertyField(_propGradientOffset, Content_Offset);
EditorGUILayout.PropertyField(_propGradientGamma, Content_Gamma);
EditorGUILayout.PropertyField(_propGradientReverse, Content_Reverse);
}
else if (_propFillMode.enumValueIndex == (int)GlowFillMode.Gradient)
{
EditorGUILayout.PropertyField(_propGradient);
EditorGUILayout.PropertyField(_propGradientOffset, Content_Offset);
EditorGUILayout.PropertyField(_propGradientGamma, Content_Gamma);
EditorGUILayout.PropertyField(_propGradientReverse, Content_Reverse);
}
EditorGUI.indentLevel--;
GUILayout.Label(Content_Apply, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(_propNoiseScale);
EditorGUILayout.PropertyField(_propAdditive);
EditorGUILayout.PropertyField(_propSourceAlpha);
EnumAsToolbarCompact(_propRenderSpace);
EnumAsToolbarCompact(_propExpand);
DrawStrengthProperty(_propStrength);
EditorGUI.indentLevel--;
if (OnInspectorGUI_Baking(filter))
{
return;
}
FilterBaseEditor.OnInspectorGUI_Debug(filter);
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: af4ccd4e17aaeae4c9eadf9bed968d3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 274847
packageName: UIFX - Glow Filter
packageVersion: 1.9.10
assetPath: Assets/ChocDino/UIFX/Editor/Scripts/Filters/GlowFilterEditor.cs
uploadId: 833966