diff --git a/Packages/SoftMaskForUGUI/Samples/Demo/SoftMask_Demo.cs b/Packages/SoftMaskForUGUI/Samples/Demo/SoftMask_Demo.cs index f88c5da..d110938 100644 --- a/Packages/SoftMaskForUGUI/Samples/Demo/SoftMask_Demo.cs +++ b/Packages/SoftMaskForUGUI/Samples/Demo/SoftMask_Demo.cs @@ -5,55 +5,55 @@ using UnityEngine.UI; namespace Coffee.UISoftMask.Demos { - public class SoftMask_Demo : MonoBehaviour - { - [SerializeField] RawImage[] softMaskBufferViewer; - [SerializeField] SoftMask[] softMask; - [SerializeField] Text text; - [SerializeField] GameObject title; + public class SoftMask_Demo : MonoBehaviour + { + [SerializeField] RawImage[] softMaskBufferViewer; + [SerializeField] SoftMask[] softMask; + [SerializeField] Text text; + [SerializeField] GameObject title; - // Use this for initialization - void OnEnable() - { - title.SetActive(true); + // Use this for initialization + void OnEnable() + { + title.SetActive(true); - text.text = string.Format("GPU: {0}\nDeviceType: {1}\nShaderLevel: {2}\nUVStartsAtTop: {3}", + text.text = string.Format("GPU: {0}\nDeviceType: {1}\nShaderLevel: {2}\nUVStartsAtTop: {3}", SystemInfo.graphicsDeviceName, SystemInfo.graphicsDeviceType, SystemInfo.graphicsShaderLevel, SystemInfo.graphicsUVStartsAtTop); - for (int i = 0; i < softMask.Length; i++) - { - softMaskBufferViewer[i].texture = softMask[i].softMaskBuffer; - } - } + for (int i = 0; i < softMask.Length; i++) + { + softMaskBufferViewer[i].texture = softMask[i].softMaskBuffer; + } + } - public void SetWorldSpase(bool flag) - { - if(flag) - { - GetComponent ().renderMode = RenderMode.ScreenSpaceCamera; - GetComponent ().renderMode = RenderMode.WorldSpace; - transform.rotation = Quaternion.Euler (new Vector3 (0, 6, 0)); - } - } + public void SetWorldSpase(bool flag) + { + if (flag) + { + GetComponent().renderMode = RenderMode.ScreenSpaceCamera; + GetComponent().renderMode = RenderMode.WorldSpace; + transform.rotation = Quaternion.Euler(new Vector3(0, 6, 0)); + } + } - public void SetScreenSpase (bool flag) - { - if (flag) - { - GetComponent ().renderMode = RenderMode.ScreenSpaceCamera; - } - } + public void SetScreenSpase(bool flag) + { + if (flag) + { + GetComponent().renderMode = RenderMode.ScreenSpaceCamera; + } + } - public void SetOverlay (bool flag) - { - if (flag) - { - GetComponent ().renderMode = RenderMode.ScreenSpaceOverlay; - } - } - } + public void SetOverlay(bool flag) + { + if (flag) + { + GetComponent().renderMode = RenderMode.ScreenSpaceOverlay; + } + } + } } diff --git a/Packages/SoftMaskForUGUI/Scripts/Editor/EditorUtils.cs b/Packages/SoftMaskForUGUI/Scripts/Editor/EditorUtils.cs index 4c5df6c..d41f9f7 100644 --- a/Packages/SoftMaskForUGUI/Scripts/Editor/EditorUtils.cs +++ b/Packages/SoftMaskForUGUI/Scripts/Editor/EditorUtils.cs @@ -1,22 +1,57 @@ #if UNITY_2018_3_OR_NEWER using UnityEditor.Experimental.SceneManagement; #endif +using UnityEditor; using UnityEditor.SceneManagement; +using UnityEngine; namespace Coffee.UISoftMask { - public static class EditorUtils + internal static class EditorUtils { - public static void MarkPrefabDirty () + internal static void MarkPrefabDirty() { - #if UNITY_2018_3_OR_NEWER - var prefabStage = PrefabStageUtility.GetCurrentPrefabStage (); - if (prefabStage != null) - { - EditorSceneManager.MarkSceneDirty (prefabStage.scene); - } - #endif +#if UNITY_2018_3_OR_NEWER + var prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); + if (prefabStage == null) return; + EditorSceneManager.MarkSceneDirty(prefabStage.scene); +#endif + } + + /// + /// Verify whether it can be converted to the specified component. + /// + internal static bool CanConvertTo(Object context) where T : MonoBehaviour + { + return context && context.GetType() != typeof(T); + } + + /// + /// Convert to the specified component. + /// + internal static void ConvertTo(Object context) where T : MonoBehaviour + { + var target = context as MonoBehaviour; + var so = new SerializedObject(target); + so.Update(); + + bool oldEnable = target.enabled; + target.enabled = false; + + // Find MonoScript of the specified component. + foreach (var script in Resources.FindObjectsOfTypeAll()) + { + if (script.GetClass() != typeof(T)) + continue; + + // Set 'm_Script' to convert. + so.FindProperty("m_Script").objectReferenceValue = script; + so.ApplyModifiedProperties(); + break; + } + + (so.targetObject as MonoBehaviour).enabled = oldEnable; } } } diff --git a/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskEditor.cs b/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskEditor.cs index a99ecff..8116ea0 100644 --- a/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskEditor.cs +++ b/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskEditor.cs @@ -7,128 +7,101 @@ using System.Linq; namespace Coffee.UISoftMask { - /// - /// SoftMask editor. - /// - [CustomEditor(typeof(SoftMask))] - [CanEditMultipleObjects] - public class SoftMaskEditor : Editor - { - const string k_PrefsPreview = "SoftMaskEditor_Preview"; - static readonly List s_Graphics = new List (); - static bool s_Preview; + /// + /// SoftMask editor. + /// + [CustomEditor(typeof(SoftMask))] + [CanEditMultipleObjects] + public class SoftMaskEditor : Editor + { + const string k_PrefsPreview = "SoftMaskEditor_Preview"; + static readonly List s_Graphics = new List(); + static bool s_Preview; - private void OnEnable () - { - s_Preview = EditorPrefs.GetBool (k_PrefsPreview, false); - } + private void OnEnable() + { + s_Preview = EditorPrefs.GetBool(k_PrefsPreview, false); + } - public override void OnInspectorGUI () - { - base.OnInspectorGUI (); + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); - var current = target as SoftMask; - current.GetComponentsInChildren (true, s_Graphics); - var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent () && (!x.GetComponent () || x.GetComponent ().showMaskGraphic)).ToList (); - if (0 < fixTargets.Count) - { - GUILayout.BeginHorizontal (); - EditorGUILayout.HelpBox ("There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.", MessageType.Warning); - GUILayout.BeginVertical (); - if (GUILayout.Button ("Fix")) - { - foreach (var p in fixTargets) - { - p.gameObject.AddComponent (); - } + var current = target as SoftMask; + current.GetComponentsInChildren(true, s_Graphics); + var fixTargets = s_Graphics.Where(x => + x.gameObject != current.gameObject && !x.GetComponent() && + (!x.GetComponent() || x.GetComponent().showMaskGraphic)).ToList(); + if (0 < fixTargets.Count) + { + GUILayout.BeginHorizontal(); + EditorGUILayout.HelpBox( + "There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.", + MessageType.Warning); + GUILayout.BeginVertical(); + if (GUILayout.Button("Fix")) + { + foreach (var p in fixTargets) + { + p.gameObject.AddComponent(); + } - EditorUtils.MarkPrefabDirty (); - } - if (GUILayout.Button ("Ping")) - { - EditorGUIUtility.PingObject (fixTargets[0]); - } - GUILayout.EndVertical (); - GUILayout.EndHorizontal (); - } + EditorUtils.MarkPrefabDirty(); + } - // Preview buffer. - GUILayout.BeginHorizontal (EditorStyles.helpBox); - if (s_Preview != (s_Preview = EditorGUILayout.ToggleLeft ("Preview Buffer", s_Preview, GUILayout.MaxWidth (EditorGUIUtility.labelWidth)))) - { - EditorPrefs.SetBool (k_PrefsPreview, s_Preview); - } - if (s_Preview) - { - var tex = current.softMaskBuffer; - var width = tex.width * 64 / tex.height; - EditorGUI.DrawPreviewTexture (GUILayoutUtility.GetRect (width, 64), tex, null, ScaleMode.ScaleToFit); - Repaint (); - } - GUILayout.FlexibleSpace (); - GUILayout.EndHorizontal (); - } + if (GUILayout.Button("Ping")) + { + EditorGUIUtility.PingObject(fixTargets[0]); + } + + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + } + + // Preview buffer. + GUILayout.BeginHorizontal(EditorStyles.helpBox); + if (s_Preview != (s_Preview = EditorGUILayout.ToggleLeft("Preview Buffer", s_Preview, + GUILayout.MaxWidth(EditorGUIUtility.labelWidth)))) + { + EditorPrefs.SetBool(k_PrefsPreview, s_Preview); + } + + if (s_Preview) + { + var tex = current.softMaskBuffer; + var width = tex.width * 64 / tex.height; + EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(width, 64), tex, null, ScaleMode.ScaleToFit); + Repaint(); + } + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } - //%%%% Context menu for editor %%%% - [MenuItem("CONTEXT/Mask/Convert To SoftMask", true)] - static bool _ConvertToSoftMask(MenuCommand command) - { - return CanConvertTo(command.context); - } + //%%%% Context menu for editor %%%% + [MenuItem("CONTEXT/Mask/Convert To SoftMask", true)] + static bool _ConvertToSoftMask(MenuCommand command) + { + return EditorUtils.CanConvertTo(command.context); + } - [MenuItem("CONTEXT/Mask/Convert To SoftMask", false)] - static void ConvertToSoftMask(MenuCommand command) - { - ConvertTo(command.context); - } + [MenuItem("CONTEXT/Mask/Convert To SoftMask", false)] + static void ConvertToSoftMask(MenuCommand command) + { + EditorUtils.ConvertTo(command.context); + } - [MenuItem("CONTEXT/Mask/Convert To Mask", true)] - static bool _ConvertToMask(MenuCommand command) - { - return CanConvertTo(command.context); - } + [MenuItem("CONTEXT/Mask/Convert To Mask", true)] + static bool _ConvertToMask(MenuCommand command) + { + return EditorUtils.CanConvertTo(command.context); + } - [MenuItem("CONTEXT/Mask/Convert To Mask", false)] - static void ConvertToMask(MenuCommand command) - { - ConvertTo(command.context); - } - - /// - /// Verify whether it can be converted to the specified component. - /// - protected static bool CanConvertTo(Object context) - where T : MonoBehaviour - { - return context && context.GetType() != typeof(T); - } - - /// - /// Convert to the specified component. - /// - protected static void ConvertTo(Object context) where T : MonoBehaviour - { - var target = context as MonoBehaviour; - var so = new SerializedObject(target); - so.Update(); - - bool oldEnable = target.enabled; - target.enabled = false; - - // Find MonoScript of the specified component. - foreach (var script in Resources.FindObjectsOfTypeAll()) - { - if (script.GetClass() != typeof(T)) - continue; - - // Set 'm_Script' to convert. - so.FindProperty("m_Script").objectReferenceValue = script; - so.ApplyModifiedProperties(); - break; - } - - (so.targetObject as MonoBehaviour).enabled = oldEnable; - } - } + [MenuItem("CONTEXT/Mask/Convert To Mask", false)] + static void ConvertToMask(MenuCommand command) + { + EditorUtils.ConvertTo(command.context); + } + } } diff --git a/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskableEditor.cs b/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskableEditor.cs index 8fdbf4e..54272f9 100644 --- a/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskableEditor.cs +++ b/Packages/SoftMaskForUGUI/Scripts/Editor/SoftMaskableEditor.cs @@ -11,403 +11,174 @@ using System.IO; namespace Coffee.UISoftMask { - /// - /// SoftMaskable editor. - /// - [CustomEditor (typeof (SoftMaskable))] - [CanEditMultipleObjects] - public class SoftMaskableEditor : Editor - { - //################################ - // Constant or Static Members. - //################################ - public enum MaskInteraction : int - { - VisibleInsideMask = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6), - VisibleOutsideMask = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6), - Custom = -1, - } + /// + /// SoftMaskable editor. + /// + [CustomEditor(typeof(SoftMaskable))] + [CanEditMultipleObjects] + public class SoftMaskableEditor : Editor + { + public enum MaskInteraction : int + { + VisibleInsideMask = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6), + VisibleOutsideMask = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6), + Custom = -1, + } - MaskInteraction maskInteraction - { - get - { - int value = _spMaskInteraction.intValue; - return _custom - ? MaskInteraction.Custom - : System.Enum.IsDefined(typeof(MaskInteraction), value) - ? (MaskInteraction)value - : MaskInteraction.Custom; - } - set - { - _custom = (value == MaskInteraction.Custom); - if (!_custom) - { - _spMaskInteraction.intValue = (int)value; - } - } - } - bool _custom = false; + MaskInteraction maskInteraction + { + get + { + int value = _spMaskInteraction.intValue; + return _custom + ? MaskInteraction.Custom + : System.Enum.IsDefined(typeof(MaskInteraction), value) + ? (MaskInteraction) value + : MaskInteraction.Custom; + } + set + { + _custom = (value == MaskInteraction.Custom); + if (!_custom) + { + _spMaskInteraction.intValue = (int) value; + } + } + } - static readonly Type s_TypeTMPro = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Text"); - static readonly Type s_TypeTMP_SpriteAsset = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SpriteAsset"); - static readonly Type s_TypeTMProSettings = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Settings"); - static readonly Type s_TypeTMP_SubMesh = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SubMesh"); - static readonly Type s_TypeTMP_SubMeshUI = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SubMeshUI"); - static PropertyInfo s_PiFontSharedMaterial; - static PropertyInfo s_PiFontSharedMaterials; - static PropertyInfo s_PiSpriteAsset; - static PropertyInfo s_PiRichText; - static PropertyInfo s_PiText; - static PropertyInfo s_PiDefaultFontAssetPath; - static PropertyInfo s_PiDefaultSpriteAssetPath; - static FieldInfo s_FiMaterial; - static MethodInfo s_miGetSpriteAsset; - static readonly List s_Graphics = new List (); - Shader _shader; - Shader _mobileShader; - Shader _spriteShader; - List _materialEditors = new List (); - SerializedProperty _spMaskInteraction; + bool _custom = false; - void OnEnable () - { - _spMaskInteraction = serializedObject.FindProperty("m_MaskInteraction"); - _custom = (maskInteraction == MaskInteraction.Custom); - - ClearMaterialEditors (); - - _shader = Shader.Find ("TextMeshPro/Distance Field (SoftMaskable)"); - _mobileShader = Shader.Find ("TextMeshPro/Mobile/Distance Field (SoftMaskable)"); - _spriteShader = Shader.Find ("TextMeshPro/Sprite (SoftMaskable)"); - - if(s_TypeTMPro != null) - { - s_PiFontSharedMaterial = s_TypeTMPro.GetProperty ("fontSharedMaterial"); - s_PiSpriteAsset = s_TypeTMPro.GetProperty ("spriteAsset"); - s_PiRichText = s_TypeTMPro.GetProperty ("richText"); - s_PiText = s_TypeTMPro.GetProperty ("text"); - s_FiMaterial = s_TypeTMP_SpriteAsset.GetField ("material"); - s_PiFontSharedMaterials = s_TypeTMPro.GetProperty ("fontSharedMaterials"); - s_miGetSpriteAsset = s_TypeTMProSettings.GetMethod ("GetSpriteAsset", BindingFlags.Static | BindingFlags.Public); - - s_PiDefaultFontAssetPath = s_TypeTMProSettings.GetProperty ("defaultFontAssetPath", BindingFlags.Static | BindingFlags.Public); - s_PiDefaultSpriteAssetPath = s_TypeTMProSettings.GetProperty ("defaultSpriteAssetPath", BindingFlags.Static | BindingFlags.Public); - } - - s_MaskWarning = new GUIContent(EditorGUIUtility.FindTexture("console.warnicon.sml"), "This component is not SoftMask. Use SoftMask instead of Mask."); - } - - void OnDisable () - { - ClearMaterialEditors (); - } - - List tmpMasks = new List(); - - void DrawMaskInteractions() - { - (target as SoftMaskable).GetComponentsInParent(true, tmpMasks); - tmpMasks.RemoveAll(x => !x.enabled); - tmpMasks.Reverse(); - - maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction); - if (_custom) - { - var l = EditorGUIUtility.labelWidth; - EditorGUIUtility.labelWidth = 45; - - using (var ccs = new EditorGUI.ChangeCheckScope()) - { - int intr0 = DrawMaskInteraction(0); - int intr1 = DrawMaskInteraction(1); - int intr2 = DrawMaskInteraction(2); - int intr3 = DrawMaskInteraction(3); - - if (ccs.changed) { - _spMaskInteraction.intValue = (intr0 << 0) + (intr1 << 2) + (intr2 << 4) + (intr3 << 6); - } - } - - EditorGUIUtility.labelWidth = l; - } - } - - static GUIContent s_MaskWarning = new GUIContent(); - - int DrawMaskInteraction(int layer) - { - Mask mask = layer < tmpMasks.Count ? tmpMasks[layer] : null; - MaskIntr intr = (MaskIntr)((_spMaskInteraction.intValue >> layer * 2) & 0x3); - if (!mask) - { - return (int)intr; - } - - using (new EditorGUILayout.HorizontalScope()) - { - EditorGUILayout.LabelField(mask is SoftMask ? GUIContent.none : s_MaskWarning, GUILayout.Width(16)); - GUILayout.Space(-5); - EditorGUILayout.ObjectField("Mask " + layer, mask, typeof(Mask), false); - GUILayout.Space(-15); - return (int)(MaskIntr)EditorGUILayout.EnumPopup(intr); - } - } - - public override void OnInspectorGUI () - { - base.OnInspectorGUI (); - - serializedObject.Update(); - DrawMaskInteractions(); - -// maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction); - serializedObject.ApplyModifiedProperties(); - /* - EditorGUI.indentLevel++; - var l = EditorGUIUtility.labelWidth; - EditorGUIUtility.labelWidth = 60; - using (new EditorGUILayout.HorizontalScope()) - { - EditorGUILayout.ObjectField("Mask 0", null, typeof(Mask), false); - EditorGUILayout.EnumPopup (MaskIntr.None); - } - EditorGUIUtility.labelWidth = l; - EditorGUI.indentLevel--; - - var spMaskInteraction = serializedObject.FindProperty ("m_MaskInteraction"); - MaskIntr intr0 = (MaskIntr)((spMaskInteraction.intValue >> 0) & 0x3); - MaskIntr intr1 = (MaskIntr)((spMaskInteraction.intValue >> 2) & 0x3); - MaskIntr intr2 = (MaskIntr)((spMaskInteraction.intValue >> 4) & 0x3); - MaskIntr intr3 = (MaskIntr)((spMaskInteraction.intValue >> 6) & 0x3); - - using (var ccs = new EditorGUI.ChangeCheckScope ()) { - - intr0 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 0", intr0); - intr1 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 1", intr1); - intr2 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 2", intr2); - intr3 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 3", intr3); - - if (ccs.changed) { - current.SetMaskInteractions (intr0,intr1,intr2,intr3); - } - } - */ - -// spMaskInteraction.intValue = (intr0 << 0) | (intr1 << 2) | (intr2 << 4) | (intr3 << 6); -// -// serializedObject.ApplyModifiedProperties (); + static readonly List s_Graphics = new List(); + SerializedProperty _spMaskInteraction; + List tmpMasks = new List(); + static GUIContent s_MaskWarning; + private void OnEnable() + { + _spMaskInteraction = serializedObject.FindProperty("m_MaskInteraction"); + _custom = (maskInteraction == MaskInteraction.Custom); + s_MaskWarning = new GUIContent(EditorGUIUtility.FindTexture("console.warnicon.sml"), + "This is not a SoftMask component."); + } - var current = target as SoftMaskable; - current.GetComponentsInChildren (true, s_Graphics); - var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent () && (!x.GetComponent () || x.GetComponent ().showMaskGraphic)).ToList (); - if (0 < fixTargets.Count) - { - GUILayout.BeginHorizontal (); - EditorGUILayout.HelpBox ("There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.", MessageType.Warning); - GUILayout.BeginVertical (); - if (GUILayout.Button ("Fix")) - { - foreach (var p in fixTargets) - { - p.gameObject.AddComponent (); - } - } - if (GUILayout.Button ("Ping")) - { - EditorGUIUtility.PingObject (fixTargets [0]); - } - GUILayout.EndVertical (); - GUILayout.EndHorizontal (); - } + private void DrawMaskInteractions() + { + var softMaskable = target as SoftMaskable; + if (softMaskable == null) return; - if(s_TypeTMPro != null) - { - ShowTMProWarning (_shader, _mobileShader, _spriteShader, m => { }); - var textMeshPro = current.GetComponent (s_TypeTMPro); - if (textMeshPro != null) - { - Material [] fontSharedMaterials = s_PiFontSharedMaterials.GetValue (textMeshPro, new object [0]) as Material []; - ShowMaterialEditors (fontSharedMaterials, 1, fontSharedMaterials.Length - 1); - } - } + softMaskable.GetComponentsInParent(true, tmpMasks); + tmpMasks.RemoveAll(x => !x.enabled); + tmpMasks.Reverse(); - if (!DetectMask (current.transform.parent)) - { - GUILayout.BeginHorizontal (); - EditorGUILayout.HelpBox ("This is unnecessary SoftMaskable.\nCan't find any SoftMask components above.", MessageType.Warning); - if (GUILayout.Button ("Remove", GUILayout.Height (40))) - { - DestroyImmediate (current); + maskInteraction = (MaskInteraction) EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction); + if (!_custom) return; - EditorUtils.MarkPrefabDirty (); - } - GUILayout.EndHorizontal (); - } - } + var l = EditorGUIUtility.labelWidth; + EditorGUIUtility.labelWidth = 45; - static bool DetectMask (Transform transform) - { - if (transform == null) - { - return false; - } + using (var ccs = new EditorGUI.ChangeCheckScope()) + { + int intr0 = DrawMaskInteraction(0); + int intr1 = DrawMaskInteraction(1); + int intr2 = DrawMaskInteraction(2); + int intr3 = DrawMaskInteraction(3); - if (transform.GetComponent () != null) - { - return true; - } + if (ccs.changed) + { + _spMaskInteraction.intValue = (intr0 << 0) + (intr1 << 2) + (intr2 << 4) + (intr3 << 6); + } + } - return DetectMask (transform.parent); - } + EditorGUIUtility.labelWidth = l; + } - void ClearMaterialEditors () - { - foreach (var e in _materialEditors) - { - if (e) - { - DestroyImmediate (e); - } - } - _materialEditors.Clear (); - } - protected void ShowMaterialEditors (Material [] materials, int startIndex, int count) - { - for (int i = 0; i < count; i++) - { - if (_materialEditors.Count == i) - { - _materialEditors.Add (null); - } + private int DrawMaskInteraction(int layer) + { + Mask mask = layer < tmpMasks.Count ? tmpMasks[layer] : null; + MaskIntr intr = (MaskIntr) ((_spMaskInteraction.intValue >> layer * 2) & 0x3); + if (!mask) + { + return (int) intr; + } - var mat = materials [startIndex + i]; - var editor = _materialEditors [i]; - if (editor && editor.target != mat) - { - DestroyImmediate (editor); - editor = null; - } + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.LabelField(mask is SoftMask ? GUIContent.none : s_MaskWarning, GUILayout.Width(16)); + GUILayout.Space(-5); + EditorGUILayout.ObjectField("Mask " + layer, mask, typeof(Mask), false); + GUILayout.Space(-15); + return (int) (MaskIntr) EditorGUILayout.EnumPopup(intr); + } + } - if (!editor) - { - editor = _materialEditors [i] = Editor.CreateEditor (mat) as MaterialEditor; - } + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); - editor.DrawHeader (); - editor.OnInspectorGUI (); - } - } + serializedObject.Update(); + DrawMaskInteractions(); - public void ShowTMProWarning (Shader shader, Shader mobileShader, Shader spriteShader, System.Action onCreatedMaterial) - { - var current = target as SoftMaskable; - var textMeshPro = current.GetComponent (s_TypeTMPro); - if (textMeshPro == null) - { - return; - } + serializedObject.ApplyModifiedProperties(); - Material fontSharedMaterial = s_PiFontSharedMaterial.GetValue (textMeshPro, new object [0]) as Material; - if (fontSharedMaterial == null) - { - return; - } + var current = target as SoftMaskable; - // Is the material preset for dissolve? - Material m = fontSharedMaterial; - if (m.shader != shader && m.shader != mobileShader) - { - EditorGUILayout.BeginHorizontal (); - EditorGUILayout.HelpBox (string.Format ("{0} requires '{1}' or '{2}' as a shader for material preset.", current.GetType ().Name, shader.name, mobileShader.name), MessageType.Warning); - if (GUILayout.Button ("Fix")) - { - var correctShader = m.shader.name.Contains ("Mobile") ? mobileShader : shader; - m = ModifyTMProMaterialPreset (m, correctShader, onCreatedMaterial); - s_PiFontSharedMaterial.SetValue (textMeshPro, m, new object [0]); - } - EditorGUILayout.EndHorizontal (); - return; - } + current.GetComponentsInChildren(true, s_Graphics); + var fixTargets = s_Graphics.Where(x => + x.gameObject != current.gameObject && !x.GetComponent() && + (!x.GetComponent() || x.GetComponent().showMaskGraphic)).ToList(); + if (0 < fixTargets.Count) + { + GUILayout.BeginHorizontal(); + EditorGUILayout.HelpBox( + "There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.", + MessageType.Warning); + GUILayout.BeginVertical(); + if (GUILayout.Button("Fix")) + { + foreach (var p in fixTargets) + { + p.gameObject.AddComponent(); + } + } - // Is the sprite asset for dissolve? - object spriteAsset = s_PiSpriteAsset.GetValue (textMeshPro, new object [0]) ?? s_miGetSpriteAsset.Invoke (null, new object [0]); - //TMP_SpriteAsset spriteAsset = textMeshPro.spriteAsset ?? TMP_Settings.GetSpriteAsset (); - m = s_FiMaterial.GetValue (spriteAsset) as Material; - bool hasSprite = (bool)s_PiRichText.GetValue (textMeshPro, new object [0]) && (s_PiText.GetValue (textMeshPro, new object [0]) as string).Contains (" x.gameObject).ToList ().ForEach (DestroyImmediate); - current.GetComponentsInChildren (s_TypeTMP_SubMeshUI).Select (x => x.gameObject).ToList ().ForEach (DestroyImmediate); - spriteAsset = ModifyTMProSpriteAsset (m, _spriteShader, mat => { }); - s_PiSpriteAsset.SetValue (textMeshPro, spriteAsset, new object [0]); - } - EditorGUILayout.EndHorizontal (); - return; - } - } + if (GUILayout.Button("Ping")) + { + EditorGUIUtility.PingObject(fixTargets[0]); + } - Material ModifyTMProMaterialPreset (Material baseMaterial, Shader shader, System.Action onCreatedMaterial) - { - string path = AssetDatabase.GetAssetPath (baseMaterial); - string filename = Path.GetFileNameWithoutExtension (path) + " (" + typeof (SoftMaskable).Name + ")"; - string defaultAssetPath = s_PiDefaultFontAssetPath.GetValue (null, new object [0]) as string; - Material mat = Resources.Load (defaultAssetPath + filename); - if (!mat) - { - mat = new Material (baseMaterial) - { - shaderKeywords = baseMaterial.shaderKeywords, - shader = shader, - }; - onCreatedMaterial (mat); - AssetDatabase.CreateAsset (mat, Path.GetDirectoryName (path) + "/" + filename + ".mat"); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + } - EditorUtility.FocusProjectWindow (); - EditorGUIUtility.PingObject (mat); - } - else - { - mat.shader = shader; - } - EditorUtility.SetDirty (mat); - return mat; - } + if (!DetectMask(current.transform.parent)) + { + GUILayout.BeginHorizontal(); + EditorGUILayout.HelpBox("This is unnecessary SoftMaskable.\nCan't find any SoftMask components above.", + MessageType.Warning); + if (GUILayout.Button("Remove", GUILayout.Height(40))) + { + DestroyImmediate(current); - object ModifyTMProSpriteAsset (Material baseMaterial, Shader shader, System.Action onCreatedMaterial) - { - string path = AssetDatabase.GetAssetPath (baseMaterial); - string filename = Path.GetFileNameWithoutExtension (path) + " (" + typeof (SoftMaskable).Name + ")"; - string defaultAssetPath = s_PiDefaultSpriteAssetPath.GetValue (null, new object [0]) as string; - Object spriteAsset = Resources.Load (defaultAssetPath + filename, s_TypeTMP_SpriteAsset); - if (spriteAsset == null) - { - AssetDatabase.CopyAsset (path, Path.GetDirectoryName (path) + "/" + filename + ".mat"); - spriteAsset = Resources.Load (defaultAssetPath + filename, s_TypeTMP_SpriteAsset); - Material m = s_FiMaterial.GetValue (spriteAsset) as Material; - m.shader = shader; - m.name = shader.name; - onCreatedMaterial (m); + EditorUtils.MarkPrefabDirty(); + } - EditorUtility.FocusProjectWindow (); - EditorGUIUtility.PingObject (spriteAsset); - } - else - { - Material m = s_FiMaterial.GetValue (spriteAsset) as Material; - m.shader = shader; - } - EditorUtility.SetDirty (spriteAsset); - return spriteAsset; - } - } + GUILayout.EndHorizontal(); + } + } + + static bool DetectMask(Transform transform) + { + while (transform) + { + if (transform.GetComponent()) return true; + + transform = transform.parent; + } + + return false; + } + } } diff --git a/Packages/SoftMaskForUGUI/Scripts/GraphicConnector.cs b/Packages/SoftMaskForUGUI/Scripts/GraphicConnector.cs index 1b38a6d..a437335 100644 --- a/Packages/SoftMaskForUGUI/Scripts/GraphicConnector.cs +++ b/Packages/SoftMaskForUGUI/Scripts/GraphicConnector.cs @@ -26,9 +26,11 @@ namespace Coffee.UISoftMask public class GraphicConnector { - private static readonly List s_Connectors = new List(); - private static readonly Dictionary s_ConnectorMap = new Dictionary(); + + private static readonly Dictionary s_ConnectorMap = + new Dictionary(); + private static readonly GraphicConnector s_EmptyConnector = new GraphicConnector(); #if UNITY_EDITOR @@ -74,7 +76,6 @@ namespace Coffee.UISoftMask } - /// /// Find effect shader. /// diff --git a/Packages/SoftMaskForUGUI/Scripts/SoftMask.cs b/Packages/SoftMaskForUGUI/Scripts/SoftMask.cs index c2c6f7b..4c38ebb 100644 --- a/Packages/SoftMaskForUGUI/Scripts/SoftMask.cs +++ b/Packages/SoftMaskForUGUI/Scripts/SoftMask.cs @@ -1,719 +1,714 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; +using Object = UnityEngine.Object; namespace Coffee.UISoftMask { - /// - /// Soft mask. - /// Use instead of Mask for smooth masking. - /// - public class SoftMask : Mask, IMeshModifier - { - //################################ - // Constant or Static Members. - //################################ - /// - /// Desampling rate. - /// - public enum DesamplingRate - { - None = 0, - x1 = 1, - x2 = 2, - x4 = 4, - x8 = 8, - } + /// + /// Soft mask. + /// Use instead of Mask for smooth masking. + /// + public class SoftMask : Mask, IMeshModifier + { + /// + /// Desampling rate. + /// + public enum DesamplingRate + { + None = 0, + x1 = 1, + x2 = 2, + x4 = 4, + x8 = 8, + } - static readonly List[] s_TmpSoftMasks = new List[] - { - new List(), - new List(), - new List(), - new List(), - }; + static readonly List[] s_TmpSoftMasks = new List[] + { + new List(), + new List(), + new List(), + new List(), + }; - static readonly Color[] s_ClearColors = new Color[] - { - new Color(0, 0, 0, 0), - new Color(1, 0, 0, 0), - new Color(1, 1, 0, 0), - new Color(1, 1, 1, 0), - }; + static readonly Color[] s_ClearColors = new Color[] + { + new Color(0, 0, 0, 0), + new Color(1, 0, 0, 0), + new Color(1, 1, 0, 0), + new Color(1, 1, 1, 0), + }; - static bool s_UVStartsAtTop; + static bool s_UVStartsAtTop; + + static Shader s_SoftMaskShader; + static Texture2D s_ReadTexture; + static readonly List s_ActiveSoftMasks = new List(); + static readonly List s_TempRelatables = new List(); + static readonly Dictionary s_previousViewProjectionMatrices = new Dictionary(); + static readonly Dictionary s_nowViewProjectionMatrices = new Dictionary(); + static int s_StencilCompId; + static int s_ColorMaskId; + static int s_MainTexId; + static int s_SoftnessId; + static int s_GameVPId; + static int s_GameTVPId; + static int s_Alpha; + MaterialPropertyBlock _mpb; + CommandBuffer _cb; + Material _material; + RenderTexture _softMaskBuffer; + int _stencilDepth; + Mesh _mesh; + SoftMask _parent; + readonly List _children = new List(); + bool _hasChanged = false; + bool _hasStencilStateChanged = false; - //################################ - // Serialize Members. - //################################ - [Tooltip("The desampling rate for soft mask buffer.")] - [SerializeField] DesamplingRate m_DesamplingRate = DesamplingRate.None; - [Tooltip("The value used by the soft mask to select the area of influence defined over the soft mask's graphic.")] - [SerializeField][Range(0.01f, 1)] float m_Softness = 1; - [Tooltip("The transparency of the whole masked graphic.")] - [SerializeField][Range(0f, 1f)] float m_Alpha = 1; - [Tooltip("Should the soft mask ignore parent soft masks?")] - [SerializeField] bool m_IgnoreParent = false; - [Tooltip("Is the soft mask a part of parent soft mask?")] - [SerializeField] bool m_PartOfParent = false; + [Tooltip("The desampling rate for soft mask buffer.")] [SerializeField] + DesamplingRate m_DesamplingRate = DesamplingRate.None; + + [Tooltip( + "The value used by the soft mask to select the area of influence defined over the soft mask's graphic.")] + [SerializeField] + [Range(0.01f, 1)] + float m_Softness = 1; + + [Tooltip("The transparency of the whole masked graphic.")] [SerializeField] [Range(0f, 1f)] + float m_Alpha = 1; + + [Tooltip("Should the soft mask ignore parent soft masks?")] [SerializeField] + bool m_IgnoreParent = false; + + [Tooltip("Is the soft mask a part of parent soft mask?")] [SerializeField] + bool m_PartOfParent = false; - //################################ - // Public Members. - //################################ - /// - /// The desampling rate for soft mask buffer. - /// - public DesamplingRate desamplingRate - { - get { return m_DesamplingRate; } - set - { - if (m_DesamplingRate != value) - { - m_DesamplingRate = value; - hasChanged = true; - } - } - } + /// + /// The desampling rate for soft mask buffer. + /// + public DesamplingRate desamplingRate + { + get { return m_DesamplingRate; } + set + { + if (m_DesamplingRate == value) return; + m_DesamplingRate = value; + hasChanged = true; + } + } - /// - /// The value used by the soft mask to select the area of influence defined over the soft mask's graphic. - /// - public float softness - { - get { return m_Softness; } - set - { - value = Mathf.Clamp01(value); - if (m_Softness != value) - { - m_Softness = value; - hasChanged = true; - } - } - } + /// + /// The value used by the soft mask to select the area of influence defined over the soft mask's graphic. + /// + public float softness + { + get { return m_Softness; } + set + { + value = Mathf.Clamp01(value); + if (Mathf.Approximately(m_Softness, value)) return; + m_Softness = value; + hasChanged = true; + } + } - /// - /// The transparency of the whole masked graphic. - /// - public float alpha - { - get { return m_Alpha; } - set - { - value = Mathf.Clamp01(value); - if (m_Alpha != value) - { - m_Alpha = value; - hasChanged = true; - } - } - } + /// + /// The transparency of the whole masked graphic. + /// + public float alpha + { + get { return m_Alpha; } + set + { + value = Mathf.Clamp01(value); + if (Mathf.Approximately(m_Alpha, value)) return; + m_Alpha = value; + hasChanged = true; + } + } - /// - /// Should the soft mask ignore parent soft masks? - /// - /// If set to true the soft mask will ignore any parent soft mask settings. - public bool ignoreParent - { - get { return m_IgnoreParent; } - set - { - if (m_IgnoreParent != value) - { - m_IgnoreParent = value; - hasChanged = true; - OnTransformParentChanged(); - } - } - } + /// + /// Should the soft mask ignore parent soft masks? + /// + /// If set to true the soft mask will ignore any parent soft mask settings. + public bool ignoreParent + { + get { return m_IgnoreParent; } + set + { + if (m_IgnoreParent == value) return; + m_IgnoreParent = value; + hasChanged = true; + OnTransformParentChanged(); + } + } - /// - /// Is the soft mask a part of parent soft mask? - /// - public bool partOfParent - { - get { return m_PartOfParent; } - set - { - if (m_PartOfParent != value) - { - m_PartOfParent = value; - hasChanged = true; - OnTransformParentChanged(); - } - } - } + /// + /// Is the soft mask a part of parent soft mask? + /// + public bool partOfParent + { + get { return m_PartOfParent; } + set + { + if (m_PartOfParent == value) return; + m_PartOfParent = value; + hasChanged = true; + OnTransformParentChanged(); + } + } - /// - /// The soft mask buffer. - /// - public RenderTexture softMaskBuffer - { - get - { - if (_parent) - { - ReleaseRT(ref _softMaskBuffer); - return _parent.softMaskBuffer; - } + /// + /// The soft mask buffer. + /// + public RenderTexture softMaskBuffer + { + get + { + if (_parent) + { + ReleaseRt(ref _softMaskBuffer); + return _parent.softMaskBuffer; + } - // Check the size of soft mask buffer. - int w, h; - GetDesamplingSize(m_DesamplingRate, out w, out h); - if (_softMaskBuffer && (_softMaskBuffer.width != w || _softMaskBuffer.height != h)) - { - ReleaseRT(ref _softMaskBuffer); - } + // Check the size of soft mask buffer. + int w, h; + GetDesamplingSize(m_DesamplingRate, out w, out h); + if (_softMaskBuffer && (_softMaskBuffer.width != w || _softMaskBuffer.height != h)) + { + ReleaseRt(ref _softMaskBuffer); + } - if (!_softMaskBuffer) - { - _softMaskBuffer = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); - hasChanged = true; - _hasStencilStateChanged = true; - } + if (!_softMaskBuffer) + { + _softMaskBuffer = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32, + RenderTextureReadWrite.Default); + hasChanged = true; + _hasStencilStateChanged = true; + } - return _softMaskBuffer; - } - } + return _softMaskBuffer; + } + } - public bool hasChanged - { - get - { - return _parent ? _parent.hasChanged : _hasChanged; - } - private set - { - if (_parent) - { - _parent.hasChanged = value; - } - _hasChanged = value; - } - } + public bool hasChanged + { + get { return _parent ? _parent.hasChanged : _hasChanged; } + private set + { + if (_parent) + { + _parent.hasChanged = value; + } - public SoftMask parent - { - get - { - return _parent; - } - } + _hasChanged = value; + } + } + + public SoftMask parent + { + get { return _parent; } + } + + Material material + { + get + { + return _material + ? _material + : _material = + new Material(s_SoftMaskShader + ? s_SoftMaskShader + : s_SoftMaskShader = Resources.Load("SoftMask")) + {hideFlags = HideFlags.HideAndDontSave}; + } + } + + Mesh mesh + { + get { return _mesh ? _mesh : _mesh = new Mesh() {hideFlags = HideFlags.HideAndDontSave}; } + } - /// - /// Perform material modification in this function. - /// - /// Modified material. - /// Configured Material. - public override Material GetModifiedMaterial(Material baseMaterial) - { - hasChanged = true; - var result = base.GetModifiedMaterial(baseMaterial); - if (m_IgnoreParent && result != baseMaterial) - { - result.SetInt(s_StencilCompId, (int)CompareFunction.Always); - } - return result; - } + /// + /// Perform material modification in this function. + /// + /// Modified material. + /// Configured Material. + public override Material GetModifiedMaterial(Material baseMaterial) + { + hasChanged = true; + var result = base.GetModifiedMaterial(baseMaterial); + if (m_IgnoreParent && result != baseMaterial) + { + result.SetInt(s_StencilCompId, (int) CompareFunction.Always); + } + + return result; + } - /// - /// Call used to modify mesh. - /// - void IMeshModifier.ModifyMesh(Mesh mesh) - { - hasChanged = true; - _mesh = mesh; - } + /// + /// Call used to modify mesh. + /// + void IMeshModifier.ModifyMesh(Mesh mesh) + { + hasChanged = true; + _mesh = mesh; + } - /// - /// Call used to modify mesh. - /// - void IMeshModifier.ModifyMesh(VertexHelper verts) - { - if (isActiveAndEnabled) - { - verts.FillMesh(mesh); - } - hasChanged = true; - } + /// + /// Call used to modify mesh. + /// + void IMeshModifier.ModifyMesh(VertexHelper verts) + { + if (isActiveAndEnabled) + verts.FillMesh(mesh); + hasChanged = true; + } - /// - /// Given a point and a camera is the raycast valid. - /// - /// Valid. - /// Screen position. - /// Raycast camera. - /// Target graphic. - public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera, Graphic g, int[] interactions) - { - if (!isActiveAndEnabled || (g == graphic && !g.raycastTarget)) - { - return true; - } + /// + /// Given a point and a camera is the raycast valid. + /// + /// Valid. + /// Screen position. + /// Raycast camera. + /// Target graphic. + public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera, Graphic g, int[] interactions) + { + if (!isActiveAndEnabled || (g == graphic && !g.raycastTarget)) return true; - int x = (int)((softMaskBuffer.width - 1) * Mathf.Clamp01(sp.x / Screen.width)); - int y = s_UVStartsAtTop - ? (int)((softMaskBuffer.height - 1) * (1 - Mathf.Clamp01(sp.y / Screen.height))) - : (int)((softMaskBuffer.height - 1) * Mathf.Clamp01(sp.y / Screen.height)); - return 0.5f < GetPixelValue(x, y, interactions); - } + int x = (int) ((softMaskBuffer.width - 1) * Mathf.Clamp01(sp.x / Screen.width)); + int y = s_UVStartsAtTop + ? (int) ((softMaskBuffer.height - 1) * (1 - Mathf.Clamp01(sp.y / Screen.height))) + : (int) ((softMaskBuffer.height - 1) * Mathf.Clamp01(sp.y / Screen.height)); + return 0.5f < GetPixelValue(x, y, interactions); + } - public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) - { - return true; - } + public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) + { + return true; + } - //################################ - // Protected Members. - //################################ + /// + /// This function is called when the object becomes enabled and active. + /// + protected override void OnEnable() + { + hasChanged = true; - /// - /// This function is called when the object becomes enabled and active. - /// - protected override void OnEnable() - { - hasChanged = true; + // Register. + if (s_ActiveSoftMasks.Count == 0) + { + Canvas.willRenderCanvases += UpdateMaskTextures; - // Register. - if (s_ActiveSoftMasks.Count == 0) - { - Canvas.willRenderCanvases += UpdateMaskTextures; - - if (s_StencilCompId == 0) - { - s_UVStartsAtTop = SystemInfo.graphicsUVStartsAtTop; - s_StencilCompId = Shader.PropertyToID("_StencilComp"); - s_ColorMaskId = Shader.PropertyToID("_ColorMask"); - s_MainTexId = Shader.PropertyToID("_MainTex"); - s_SoftnessId = Shader.PropertyToID("_Softness"); - s_Alpha = Shader.PropertyToID("_Alpha"); + if (s_StencilCompId == 0) + { + s_UVStartsAtTop = SystemInfo.graphicsUVStartsAtTop; + s_StencilCompId = Shader.PropertyToID("_StencilComp"); + s_ColorMaskId = Shader.PropertyToID("_ColorMask"); + s_MainTexId = Shader.PropertyToID("_MainTex"); + s_SoftnessId = Shader.PropertyToID("_Softness"); + s_Alpha = Shader.PropertyToID("_Alpha"); #if UNITY_EDITOR - s_GameVPId = Shader.PropertyToID("_GameVP"); - s_GameTVPId = Shader.PropertyToID("_GameTVP"); + s_GameVPId = Shader.PropertyToID("_GameVP"); + s_GameTVPId = Shader.PropertyToID("_GameTVP"); #endif - } - } - s_ActiveSoftMasks.Add(this); + } + } - // Reset the parent-child relation. - GetComponentsInChildren(false, s_TempRelatables); - for (int i = s_TempRelatables.Count - 1; 0 <= i; i--) - { - s_TempRelatables[i].OnTransformParentChanged(); - } - s_TempRelatables.Clear(); + s_ActiveSoftMasks.Add(this); - // Create objects. - _mpb = new MaterialPropertyBlock(); - _cb = new CommandBuffer(); + // Reset the parent-child relation. + GetComponentsInChildren(false, s_TempRelatables); + for (int i = s_TempRelatables.Count - 1; 0 <= i; i--) + { + s_TempRelatables[i].OnTransformParentChanged(); + } - graphic.SetVerticesDirty(); + s_TempRelatables.Clear(); - base.OnEnable(); - _hasStencilStateChanged = false; - } + // Create objects. + _mpb = new MaterialPropertyBlock(); + _cb = new CommandBuffer(); - /// - /// This function is called when the behaviour becomes disabled. - /// - protected override void OnDisable() - { - // Unregister. - s_ActiveSoftMasks.Remove(this); - if (s_ActiveSoftMasks.Count == 0) - { - Canvas.willRenderCanvases -= UpdateMaskTextures; - } + graphic.SetVerticesDirty(); - // Reset the parent-child relation. - for (int i = _children.Count - 1; 0 <= i; i--) - { - _children[i].SetParent(_parent); - } - _children.Clear(); - SetParent(null); + base.OnEnable(); + _hasStencilStateChanged = false; + } - // Destroy objects. - _mpb.Clear(); - _mpb = null; - _cb.Release(); - _cb = null; + /// + /// This function is called when the behaviour becomes disabled. + /// + protected override void OnDisable() + { + // Unregister. + s_ActiveSoftMasks.Remove(this); + if (s_ActiveSoftMasks.Count == 0) + { + Canvas.willRenderCanvases -= UpdateMaskTextures; + } - ReleaseObject(_mesh); - _mesh = null; - ReleaseObject(_material); - _material = null; - ReleaseRT(ref _softMaskBuffer); + // Reset the parent-child relation. + for (int i = _children.Count - 1; 0 <= i; i--) + { + _children[i].SetParent(_parent); + } - base.OnDisable(); - _hasStencilStateChanged = false; - } + _children.Clear(); + SetParent(null); - /// - /// This function is called when the parent property of the transform of the GameObject has changed. - /// - protected override void OnTransformParentChanged() - { - hasChanged = true; - SoftMask newParent = null; - if (isActiveAndEnabled && !m_IgnoreParent) - { - var parentTransform = transform.parent; - while (parentTransform && (!newParent || !newParent.enabled)) - { - newParent = parentTransform.GetComponent(); - parentTransform = parentTransform.parent; - } - } - SetParent(newParent); - hasChanged = true; - } + // Destroy objects. + _mpb.Clear(); + _mpb = null; + _cb.Release(); + _cb = null; - protected override void OnRectTransformDimensionsChange() - { - hasChanged = true; - } + ReleaseObject(_mesh); + _mesh = null; + ReleaseObject(_material); + _material = null; + ReleaseRt(ref _softMaskBuffer); + + base.OnDisable(); + _hasStencilStateChanged = false; + } + + /// + /// This function is called when the parent property of the transform of the GameObject has changed. + /// + protected override void OnTransformParentChanged() + { + hasChanged = true; + SoftMask newParent = null; + if (isActiveAndEnabled && !m_IgnoreParent) + { + var parentTransform = transform.parent; + while (parentTransform && (!newParent || !newParent.enabled)) + { + newParent = parentTransform.GetComponent(); + parentTransform = parentTransform.parent; + } + } + + SetParent(newParent); + hasChanged = true; + } + + protected override void OnRectTransformDimensionsChange() + { + hasChanged = true; + } #if UNITY_EDITOR - /// - /// Update the scene view matrix for shader. - /// - - /// - /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). - /// - protected override void OnValidate() - { - graphic.SetMaterialDirty(); - OnTransformParentChanged(); - base.OnValidate(); - _hasStencilStateChanged = false; - } + /// + /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). + /// + protected override void OnValidate() + { + graphic.SetMaterialDirty(); + OnTransformParentChanged(); + base.OnValidate(); + _hasStencilStateChanged = false; + } #endif - //################################ - // Private Members. - //################################ - static Shader s_SoftMaskShader; - static Texture2D s_ReadTexture; - static List s_ActiveSoftMasks = new List(); - static List s_TempRelatables = new List(); - static int s_StencilCompId; - static int s_ColorMaskId; - static int s_MainTexId; - static int s_SoftnessId; - static int s_GameVPId; - static int s_GameTVPId; - static int s_Alpha; - MaterialPropertyBlock _mpb; - CommandBuffer _cb; - Material _material; - RenderTexture _softMaskBuffer; - int _stencilDepth; - Mesh _mesh; - SoftMask _parent; - List _children = new List(); - bool _hasChanged = false; - bool _hasStencilStateChanged = false; - static readonly Dictionary s_previousViewProjectionMatrices = new Dictionary (); - static readonly Dictionary s_nowViewProjectionMatrices = new Dictionary (); + /// + /// Update all soft mask textures. + /// + static void UpdateMaskTextures() + { + foreach (var sm in s_ActiveSoftMasks) + { + if (!sm || sm._hasChanged) + continue; - Material material { get { return _material ? _material : _material = new Material(s_SoftMaskShader ? s_SoftMaskShader : s_SoftMaskShader = Resources.Load("SoftMask")){ hideFlags = HideFlags.HideAndDontSave }; } } + var canvas = sm.graphic.canvas; + if (!canvas) + continue; - Mesh mesh { get { return _mesh ? _mesh : _mesh = new Mesh(){ hideFlags = HideFlags.HideAndDontSave }; } } + if (canvas.renderMode == RenderMode.WorldSpace) + { + var cam = canvas.worldCamera; + if (!cam) + continue; - /// - /// Update all soft mask textures. - /// - static void UpdateMaskTextures() - { - foreach (var sm in s_ActiveSoftMasks) - { - if (!sm || sm._hasChanged) - continue; + var nowVP = cam.projectionMatrix * cam.worldToCameraMatrix; + var previousVP = default(Matrix4x4); + var id = cam.GetInstanceID(); + s_previousViewProjectionMatrices.TryGetValue(id, out previousVP); + s_nowViewProjectionMatrices[id] = nowVP; - var canvas = sm.graphic.canvas; - if(!canvas) - continue; + if (previousVP != nowVP) + { + sm.hasChanged = true; + } + } - if (canvas.renderMode == RenderMode.WorldSpace) - { - var cam = canvas.worldCamera; - if(!cam) - continue; - - Matrix4x4 nowVP = cam.projectionMatrix * cam.worldToCameraMatrix; - - Matrix4x4 previousVP = default(Matrix4x4); - int id = cam.GetInstanceID (); - s_previousViewProjectionMatrices.TryGetValue (id, out previousVP); - s_nowViewProjectionMatrices[id] = nowVP; - - if (previousVP != nowVP) - { - sm.hasChanged = true; - } - } - - var rt = sm.rectTransform; - if (rt.hasChanged) - { - rt.hasChanged = false; - sm.hasChanged = true; - } + var rt = sm.rectTransform; + if (rt.hasChanged) + { + rt.hasChanged = false; + sm.hasChanged = true; + } #if UNITY_EDITOR - if (!Application.isPlaying) - { - sm.hasChanged = true; - } + if (!Application.isPlaying) + { + sm.hasChanged = true; + } #endif - } + } - foreach (var sm in s_ActiveSoftMasks) - { - if (!sm || !sm._hasChanged) - continue; + foreach (var sm in s_ActiveSoftMasks) + { + if (!sm || !sm._hasChanged) + continue; - sm._hasChanged = false; - if (!sm._parent) - { - sm.UpdateMaskTexture(); - if (sm._hasStencilStateChanged) - { - sm._hasStencilStateChanged = false; - MaskUtilities.NotifyStencilStateChanged (sm); - } - } - } + sm._hasChanged = false; + if (sm._parent) continue; + sm.UpdateMaskTexture(); - s_previousViewProjectionMatrices.Clear (); - foreach (int id in s_nowViewProjectionMatrices.Keys) - { - s_previousViewProjectionMatrices [id] = s_nowViewProjectionMatrices [id]; - } - s_nowViewProjectionMatrices.Clear (); + if (!sm._hasStencilStateChanged) continue; + sm._hasStencilStateChanged = false; + MaskUtilities.NotifyStencilStateChanged(sm); + } - } + s_previousViewProjectionMatrices.Clear(); + foreach (var id in s_nowViewProjectionMatrices.Keys) + { + s_previousViewProjectionMatrices[id] = s_nowViewProjectionMatrices[id]; + } - /// - /// Update the mask texture. - /// - void UpdateMaskTexture() - { - if (!graphic || !graphic.canvas) - { - return; - } + s_nowViewProjectionMatrices.Clear(); + } - _stencilDepth = MaskUtilities.GetStencilDepth(transform, MaskUtilities.FindRootSortOverrideCanvas(transform)); + /// + /// Update the mask texture. + /// + private void UpdateMaskTexture() + { + if (!graphic || !graphic.canvas) return; - // Collect children soft masks. - int depth = 0; - s_TmpSoftMasks[0].Add(this); - while (_stencilDepth + depth < 3) - { - int count = s_TmpSoftMasks[depth].Count; - for (int i = 0; i < count; i++) - { - List children = s_TmpSoftMasks[depth][i]._children; - int childCount = children.Count; - for (int j = 0; j < childCount; j++) - { - var child = children[j]; - var childDepth = child.m_PartOfParent ? depth : depth + 1; - s_TmpSoftMasks[childDepth].Add(child); - } - } - depth++; - } + _stencilDepth = + MaskUtilities.GetStencilDepth(transform, MaskUtilities.FindRootSortOverrideCanvas(transform)); - // Clear. - _cb.Clear(); - _cb.SetRenderTarget(softMaskBuffer); - _cb.ClearRenderTarget(false, true, s_ClearColors[_stencilDepth]); + // Collect children soft masks. + var depth = 0; + s_TmpSoftMasks[0].Add(this); + while (_stencilDepth + depth < 3) + { + var count = s_TmpSoftMasks[depth].Count; + for (var i = 0; i < count; i++) + { + List children = s_TmpSoftMasks[depth][i]._children; + var childCount = children.Count; + for (var j = 0; j < childCount; j++) + { + var child = children[j]; + var childDepth = child.m_PartOfParent ? depth : depth + 1; + s_TmpSoftMasks[childDepth].Add(child); + } + } - // Set view and projection matrices. - var c = graphic.canvas.rootCanvas; - var cam = c.worldCamera ?? Camera.main; - if (c && c.renderMode != RenderMode.ScreenSpaceOverlay && cam) - { - _cb.SetViewProjectionMatrices(cam.worldToCameraMatrix, GL.GetGPUProjectionMatrix(cam.projectionMatrix, false)); + depth++; + } + + // Clear. + _cb.Clear(); + _cb.SetRenderTarget(softMaskBuffer); + _cb.ClearRenderTarget(false, true, s_ClearColors[_stencilDepth]); + + // Set view and projection matrices. + var c = graphic.canvas.rootCanvas; + var cam = c.worldCamera ?? Camera.main; + if (c && c.renderMode != RenderMode.ScreenSpaceOverlay && cam) + { + _cb.SetViewProjectionMatrices(cam.worldToCameraMatrix, + GL.GetGPUProjectionMatrix(cam.projectionMatrix, false)); #if UNITY_EDITOR - var pv = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false) * cam.worldToCameraMatrix; - _cb.SetGlobalMatrix(s_GameVPId, pv); - _cb.SetGlobalMatrix(s_GameTVPId, pv); + var pv = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false) * cam.worldToCameraMatrix; + _cb.SetGlobalMatrix(s_GameVPId, pv); + _cb.SetGlobalMatrix(s_GameTVPId, pv); #endif - } - else - { - var pos = c.transform.position; - var vm = Matrix4x4.TRS(new Vector3(-pos.x, -pos.y, -1000), Quaternion.identity, new Vector3(1, 1, -1f)); - var pm = Matrix4x4.TRS(new Vector3(0, 0, -1), Quaternion.identity, new Vector3(1 / pos.x, 1 / pos.y, -2 / 10000f)); - _cb.SetViewProjectionMatrices(vm, pm); + } + else + { + var pos = c.transform.position; + var vm = Matrix4x4.TRS(new Vector3(-pos.x, -pos.y, -1000), Quaternion.identity, new Vector3(1, 1, -1f)); + var pm = Matrix4x4.TRS(new Vector3(0, 0, -1), Quaternion.identity, + new Vector3(1 / pos.x, 1 / pos.y, -2 / 10000f)); + _cb.SetViewProjectionMatrices(vm, pm); #if UNITY_EDITOR - var scale = c.transform.localScale.x; - var size = (c.transform as RectTransform).sizeDelta; - _cb.SetGlobalMatrix(s_GameVPId, Matrix4x4.TRS(new Vector3(0, 0, 0.5f), Quaternion.identity, new Vector3(2 / size.x, 2 / size.y, 0.0005f * scale))); - _cb.SetGlobalMatrix(s_GameTVPId, Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(1 / pos.x, 1 / pos.y, -2 / 2000f)) * Matrix4x4.Translate(-pos)); + var scale = c.transform.localScale.x; + var size = (c.transform as RectTransform).sizeDelta; + _cb.SetGlobalMatrix(s_GameVPId, + Matrix4x4.TRS(new Vector3(0, 0, 0.5f), Quaternion.identity, + new Vector3(2 / size.x, 2 / size.y, 0.0005f * scale))); + _cb.SetGlobalMatrix(s_GameTVPId, + Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, + new Vector3(1 / pos.x, 1 / pos.y, -2 / 2000f)) * Matrix4x4.Translate(-pos)); #endif - } + } - // Draw soft masks. - for (int i = 0; i < s_TmpSoftMasks.Length; i++) - { - int count = s_TmpSoftMasks[i].Count; - for (int j = 0; j < count; j++) - { - var sm = s_TmpSoftMasks[i][j]; + // Draw soft masks. + for (var i = 0; i < s_TmpSoftMasks.Length; i++) + { + var count = s_TmpSoftMasks[i].Count; + for (var j = 0; j < count; j++) + { + var sm = s_TmpSoftMasks[i][j]; - if (i != 0) - { - sm._stencilDepth = MaskUtilities.GetStencilDepth(sm.transform, MaskUtilities.FindRootSortOverrideCanvas(sm.transform)); - } + if (i != 0) + { + sm._stencilDepth = MaskUtilities.GetStencilDepth(sm.transform, + MaskUtilities.FindRootSortOverrideCanvas(sm.transform)); + } - // Set material property. - sm.material.SetInt(s_ColorMaskId, (int)1 << (3 - _stencilDepth - i)); - sm._mpb.SetTexture(s_MainTexId, sm.graphic.mainTexture); - sm._mpb.SetFloat(s_SoftnessId, sm.m_Softness); - sm._mpb.SetFloat(s_Alpha, sm.m_Alpha); + // Set material property. + sm.material.SetInt(s_ColorMaskId, (int) 1 << (3 - _stencilDepth - i)); + sm._mpb.SetTexture(s_MainTexId, sm.graphic.mainTexture); + sm._mpb.SetFloat(s_SoftnessId, sm.m_Softness); + sm._mpb.SetFloat(s_Alpha, sm.m_Alpha); - // Draw mesh. - _cb.DrawMesh(sm.mesh, sm.transform.localToWorldMatrix, sm.material, 0, 0, sm._mpb); - } - s_TmpSoftMasks[i].Clear(); - } + // Draw mesh. + _cb.DrawMesh(sm.mesh, sm.transform.localToWorldMatrix, sm.material, 0, 0, sm._mpb); + } - Graphics.ExecuteCommandBuffer(_cb); - } + s_TmpSoftMasks[i].Clear(); + } - /// - /// Gets the size of the desampling. - /// - void GetDesamplingSize(DesamplingRate rate, out int w, out int h) - { + Graphics.ExecuteCommandBuffer(_cb); + } + + /// + /// Gets the size of the desampling. + /// + private static void GetDesamplingSize(DesamplingRate rate, out int w, out int h) + { #if UNITY_EDITOR - var res = UnityEditor.UnityStats.screenRes.Split('x'); - w = int.Parse(res[0]); - h = int.Parse(res[1]); + var res = UnityEditor.UnityStats.screenRes.Split('x'); + w = int.Parse(res[0]); + h = int.Parse(res[1]); #else w = Screen.width; h = Screen.height; #endif - if (rate == DesamplingRate.None) - return; + if (rate == DesamplingRate.None) + return; - float aspect = (float)w / h; - if (w < h) - { - h = Mathf.ClosestPowerOfTwo(h / (int)rate); - w = Mathf.CeilToInt(h * aspect); - } - else - { - w = Mathf.ClosestPowerOfTwo(w / (int)rate); - h = Mathf.CeilToInt(w / aspect); - } - } + var aspect = (float) w / h; + if (w < h) + { + h = Mathf.ClosestPowerOfTwo(h / (int) rate); + w = Mathf.CeilToInt(h * aspect); + } + else + { + w = Mathf.ClosestPowerOfTwo(w / (int) rate); + h = Mathf.CeilToInt(w / aspect); + } + } - /// - /// Release the specified obj. - /// - /// Object. - void ReleaseRT(ref RenderTexture tmpRT) - { - if (tmpRT) - { - tmpRT.Release(); - RenderTexture.ReleaseTemporary(tmpRT); - tmpRT = null; - } - } + /// + /// Release the specified obj. + /// + /// Object. + private static void ReleaseRt(ref RenderTexture tmpRT) + { + if (!tmpRT) return; + tmpRT.Release(); + RenderTexture.ReleaseTemporary(tmpRT); + tmpRT = null; + } - /// - /// Release the specified obj. - /// - /// Object. - void ReleaseObject(Object obj) - { - if (obj) - { - #if UNITY_EDITOR - if (!Application.isPlaying) - DestroyImmediate(obj); - else - #endif - Destroy(obj); - obj = null; - } - } + /// + /// Release the specified obj. + /// + /// Object. + private static void ReleaseObject(Object obj) + { + if (!obj) return; +#if UNITY_EDITOR + if (!Application.isPlaying) + DestroyImmediate(obj); + else +#endif + Destroy(obj); + obj = null; + } - /// - /// Set the parent of the soft mask. - /// - /// The parent soft mask to use. - void SetParent(SoftMask newParent) - { - if (_parent != newParent && this != newParent) - { - if (_parent && _parent._children.Contains(this)) - { - _parent._children.Remove(this); - _parent._children.RemoveAll(x => x == null); - } - _parent = newParent; - } + /// + /// Set the parent of the soft mask. + /// + /// The parent soft mask to use. + private void SetParent(SoftMask newParent) + { + if (_parent != newParent && this != newParent) + { + if (_parent && _parent._children.Contains(this)) + { + _parent._children.Remove(this); + _parent._children.RemoveAll(x => x == null); + } - if (_parent && !_parent._children.Contains(this)) - { - _parent._children.Add(this); - } - } + _parent = newParent; + } - /// - /// Gets the pixel value. - /// - float GetPixelValue(int x, int y, int[] interactions) - { - if (!s_ReadTexture) - { - s_ReadTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false); - } - var currentRT = RenderTexture.active; + if (_parent && !_parent._children.Contains(this)) + { + _parent._children.Add(this); + } + } - RenderTexture.active = softMaskBuffer; - s_ReadTexture.ReadPixels(new Rect(x, y, 1, 1), 0, 0); - s_ReadTexture.Apply(false, false); - RenderTexture.active = currentRT; + /// + /// Gets the pixel value. + /// + private float GetPixelValue(int x, int y, int[] interactions) + { + if (!s_ReadTexture) + { + s_ReadTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false); + } - var colors = s_ReadTexture.GetRawTextureData(); + var currentRt = RenderTexture.active; - for (int i = 0; i < 4; i++) - { - switch (interactions[(i + 3)%4]) - { - case 0: colors[i] = 255; break; - case 2: colors[i] = (byte)(255 - colors[i]); break; - } - } + RenderTexture.active = softMaskBuffer; + s_ReadTexture.ReadPixels(new Rect(x, y, 1, 1), 0, 0); + s_ReadTexture.Apply(false, false); + RenderTexture.active = currentRt; - switch (_stencilDepth) - { - case 0: return (colors[1] / 255f); - case 1: return (colors[1] / 255f) * (colors[2] / 255f); - case 2: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f); - case 3: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f) * (colors[0] / 255f); - default: return 0; - } - } - } + var colors = s_ReadTexture.GetRawTextureData(); + + for (int i = 0; i < 4; i++) + { + switch (interactions[(i + 3) % 4]) + { + case 0: + colors[i] = 255; + break; + case 2: + colors[i] = (byte) (255 - colors[i]); + break; + } + } + + switch (_stencilDepth) + { + case 0: return (colors[1] / 255f); + case 1: return (colors[1] / 255f) * (colors[2] / 255f); + case 2: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f); + case 3: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f) * (colors[0] / 255f); + default: return 0; + } + } + } } diff --git a/Packages/SoftMaskForUGUI/Scripts/SoftMaskable.cs b/Packages/SoftMaskForUGUI/Scripts/SoftMaskable.cs index ea05ddc..8c30a99 100755 --- a/Packages/SoftMaskForUGUI/Scripts/SoftMaskable.cs +++ b/Packages/SoftMaskForUGUI/Scripts/SoftMaskable.cs @@ -6,290 +6,283 @@ using MaskIntr = UnityEngine.SpriteMaskInteraction; namespace Coffee.UISoftMask { - /// - /// Soft maskable. - /// Add this component to Graphic under SoftMask for smooth masking. - /// + /// + /// Soft maskable. + /// Add this component to Graphic under SoftMask for smooth masking. + /// #if UNITY_2018_3_OR_NEWER - [ExecuteAlways] + [ExecuteAlways] #else [ExecuteInEditMode] # endif - public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter + public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter #if UNITY_EDITOR - , ISerializationCallbackReceiver + , ISerializationCallbackReceiver # endif - { - const int kVisibleInside = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6); - const int kVisibleOutside = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6); - static readonly Hash128 k_InvalidHash = new Hash128(); + { + const int kVisibleInside = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6); + const int kVisibleOutside = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6); + static readonly Hash128 k_InvalidHash = new Hash128(); - [Tooltip("The graphic will be visible only in areas where no mask is present.")] - [System.Obsolete] - [HideInInspector] - [SerializeField] bool m_Inverse = false; - [Tooltip("The interaction for each masks.")] - [HideInInspector] - [SerializeField] int m_MaskInteraction = kVisibleInside; - [Tooltip("Use stencil to mask.")] - [SerializeField] bool m_UseStencil = false; - [Tooltip("Use soft-masked raycast target.\n\nNote: This option is expensive.")] - [SerializeField] bool m_RaycastFilter = false; + static int s_SoftMaskTexId; + static int s_StencilCompId; + static int s_MaskInteractionId; + static List s_ActiveSoftMaskables; + static int[] s_Interactions = new int[4]; - Graphic _graphic = null; - SoftMask _softMask = null; - Material _maskMaterial = null; - static int s_SoftMaskTexId; - static int s_StencilCompId; - static int s_MaskInteractionId; - static List s_ActiveSoftMaskables; - static int[] s_Interactions = new int[4]; - Hash128 _effectMaterialHash; + [Tooltip("The graphic will be visible only in areas where no mask is present.")] + [System.Obsolete] + [HideInInspector] + [SerializeField] + bool m_Inverse = false; - /// - /// Perform material modification in this function. - /// - /// Modified material. - /// Configured Material. - public Material GetModifiedMaterial(Material baseMaterial) - { - _softMask = null; - if (!isActiveAndEnabled) - { - return baseMaterial; - } + [Tooltip("The interaction for each masks.")] [HideInInspector] [SerializeField] + int m_MaskInteraction = kVisibleInside; - // Find the nearest parent softmask. - var parentTransform = transform.parent; - while (parentTransform) - { - var sm = parentTransform.GetComponent(); - if (sm && sm.enabled) - { - _softMask = sm; - break; - } - parentTransform = parentTransform.parent; - } + [Tooltip("Use stencil to mask.")] [SerializeField] + bool m_UseStencil = false; - var oldHash = _effectMaterialHash; - var modifiedMaterial = baseMaterial; - if (_softMask) - { - _effectMaterialHash = GetMaterialHash(baseMaterial); - modifiedMaterial = MaterialCache.Register(baseMaterial, _effectMaterialHash, mat => - { - Debug.Log(mat.shader.name); - mat.shader = Shader.Find(string.Format("Hidden/{0} (SoftMaskable)", mat.shader.name)); + [Tooltip("Use soft-masked raycast target.\n\nNote: This option is expensive.")] [SerializeField] + bool m_RaycastFilter = false; + + Graphic _graphic = null; + SoftMask _softMask = null; + Material _maskMaterial = null; + Hash128 _effectMaterialHash; + + /// + /// The graphic will be visible only in areas where no mask is present. + /// + public bool inverse + { + get { return m_MaskInteraction == kVisibleOutside; } + set + { + var intValue = value ? kVisibleOutside : kVisibleInside; + if (m_MaskInteraction == intValue) return; + m_MaskInteraction = intValue; + graphic.SetMaterialDirtyEx(); + } + } + + /// + /// Use soft-masked raycast target. This option is expensive. + /// + public bool raycastFilter + { + get { return m_RaycastFilter; } + set { m_RaycastFilter = value; } + } + + /// + /// The graphic associated with the soft mask. + /// + public Graphic graphic + { + get { return _graphic ? _graphic : _graphic = GetComponent(); } + } + + /// + /// Perform material modification in this function. + /// + /// Modified material. + /// Configured Material. + Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial) + { + _softMask = null; + if (!isActiveAndEnabled) + { + return baseMaterial; + } + + // Find the nearest parent softmask. + var parentTransform = transform.parent; + while (parentTransform) + { + var sm = parentTransform.GetComponent(); + if (sm && sm.enabled) + { + _softMask = sm; + break; + } + + parentTransform = parentTransform.parent; + } + + var oldHash = _effectMaterialHash; + var modifiedMaterial = baseMaterial; + if (_softMask) + { + _effectMaterialHash = GetMaterialHash(baseMaterial); + modifiedMaterial = MaterialCache.Register(baseMaterial, _effectMaterialHash, mat => + { + mat.shader = Shader.Find(string.Format("Hidden/{0} (SoftMaskable)", mat.shader.name)); #if UNITY_EDITOR - mat.EnableKeyword("SOFTMASK_EDITOR"); + mat.EnableKeyword("SOFTMASK_EDITOR"); #endif - mat.SetTexture(s_SoftMaskTexId, _softMask.softMaskBuffer); - mat.SetInt(s_StencilCompId, m_UseStencil ? (int)CompareFunction.Equal : (int)CompareFunction.Always); - mat.SetVector(s_MaskInteractionId, new Vector4( - (m_MaskInteraction & 0x3), - ((m_MaskInteraction >> 2) & 0x3), - ((m_MaskInteraction >> 4) & 0x3), - ((m_MaskInteraction >> 6) & 0x3) - )); - }); - ReleaseMaterial(ref _maskMaterial); - _maskMaterial = modifiedMaterial; - } + mat.SetTexture(s_SoftMaskTexId, _softMask.softMaskBuffer); + mat.SetInt(s_StencilCompId, + m_UseStencil ? (int) CompareFunction.Equal : (int) CompareFunction.Always); + mat.SetVector(s_MaskInteractionId, new Vector4( + (m_MaskInteraction & 0x3), + ((m_MaskInteraction >> 2) & 0x3), + ((m_MaskInteraction >> 4) & 0x3), + ((m_MaskInteraction >> 6) & 0x3) + )); + }); + ReleaseMaterial(ref _maskMaterial); + _maskMaterial = modifiedMaterial; + } - MaterialCache.Unregister(oldHash); - return modifiedMaterial; - } + MaterialCache.Unregister(oldHash); + return modifiedMaterial; + } - private Hash128 GetMaterialHash(Material material) - { - if (!isActiveAndEnabled || !material || !material.shader) - return k_InvalidHash; + private Hash128 GetMaterialHash(Material material) + { + if (!isActiveAndEnabled || !material || !material.shader) + return k_InvalidHash; - return new Hash128( - (uint) material.GetInstanceID(), - (uint) m_MaskInteraction, - (uint) (m_UseStencil ? 1 : 0), - 0 - ); - } + return new Hash128( + (uint) material.GetInstanceID(), + (uint) m_MaskInteraction, + (uint) (m_UseStencil ? 1 : 0), + 0 + ); + } - /// - /// Given a point and a camera is the raycast valid. - /// - /// Valid. - /// Screen position. - /// Raycast camera. - public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) - { - if (!isActiveAndEnabled || !_softMask) - return true; - if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera)) - return false; - if (!m_RaycastFilter) - return true; + /// + /// Given a point and a camera is the raycast valid. + /// + /// Valid. + /// Screen position. + /// Raycast camera. + bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 sp, Camera eventCamera) + { + if (!isActiveAndEnabled || !_softMask) + return true; + if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera)) + return false; + if (!m_RaycastFilter) + return true; - var sm = _softMask; - for (int i = 0; i < 4; i++) - { - s_Interactions[i] = sm ? ((m_MaskInteraction >> i * 2) & 0x3) : 0; - sm = sm ? sm.parent : null; - } + var sm = _softMask; + for (var i = 0; i < 4; i++) + { + s_Interactions[i] = sm ? ((m_MaskInteraction >> i * 2) & 0x3) : 0; + sm = sm ? sm.parent : null; + } - return _softMask.IsRaycastLocationValid(sp, eventCamera, graphic, s_Interactions); - } + return _softMask.IsRaycastLocationValid(sp, eventCamera, graphic, s_Interactions); + } + + /// + /// Set the interaction for each mask. + /// + public void SetMaskInteraction(SpriteMaskInteraction intr) + { + SetMaskInteraction(intr, intr, intr, intr); + } + + /// + /// Set the interaction for each mask. + /// + public void SetMaskInteraction(SpriteMaskInteraction layer0, SpriteMaskInteraction layer1, + SpriteMaskInteraction layer2, SpriteMaskInteraction layer3) + { + m_MaskInteraction = (int) layer0 + ((int) layer1 << 2) + ((int) layer2 << 4) + ((int) layer3 << 6); + graphic.SetMaterialDirtyEx(); + } - /// - /// The graphic will be visible only in areas where no mask is present. - /// - public bool inverse - { - get { return m_MaskInteraction == kVisibleOutside; } - set - { - int intValue = value ? kVisibleOutside : kVisibleInside; - if (m_MaskInteraction != intValue) - { - m_MaskInteraction = intValue; - graphic.SetMaterialDirtyEx(); - } - } - } + /// + /// This function is called when the object becomes enabled and active. + /// + private void OnEnable() + { + // Register. + if (s_ActiveSoftMaskables == null) + { + s_ActiveSoftMaskables = new List(); - /// - /// Use soft-masked raycast target. This option is expensive. - /// - public bool raycastFilter - { - get { return m_RaycastFilter; } - set { m_RaycastFilter = value; } - } + s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex"); + s_StencilCompId = Shader.PropertyToID("_StencilComp"); + s_MaskInteractionId = Shader.PropertyToID("_MaskInteraction"); + } - /// - /// The graphic associated with the soft mask. - /// - public Graphic graphic{ get { return _graphic ? _graphic : _graphic = GetComponent(); } } + s_ActiveSoftMaskables.Add(this); - /// - /// Set the interaction for each mask. - /// - public void SetMaskInteraction(SpriteMaskInteraction intr) - { - SetMaskInteraction(intr, intr, intr, intr); - } + graphic.SetMaterialDirtyEx(); + _softMask = null; + } - /// - /// Set the interaction for each mask. - /// - public void SetMaskInteraction(SpriteMaskInteraction layer0, SpriteMaskInteraction layer1, SpriteMaskInteraction layer2, SpriteMaskInteraction layer3) - { - m_MaskInteraction = (int)layer0 + ((int)layer1 << 2) + ((int)layer2 << 4) + ((int)layer3 << 6); - graphic.SetMaterialDirtyEx(); - } + /// + /// This function is called when the behaviour becomes disabled. + /// + private void OnDisable() + { + s_ActiveSoftMaskables.Remove(this); + graphic.SetMaterialDirtyEx(); + _softMask = null; + ReleaseMaterial(ref _maskMaterial); - /// - /// This function is called when the object becomes enabled and active. - /// - void OnEnable() - { - // Register. - if (s_ActiveSoftMaskables == null) - { - s_ActiveSoftMaskables = new List(); + MaterialCache.Unregister(_effectMaterialHash); + _effectMaterialHash = k_InvalidHash; + } - s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex"); - s_StencilCompId = Shader.PropertyToID("_StencilComp"); - s_MaskInteractionId = Shader.PropertyToID("_MaskInteraction"); - } - s_ActiveSoftMaskables.Add(this); + /// + /// Release the material. + /// + static void ReleaseMaterial(ref Material mat) + { + if (!mat) return; +#if UNITY_EDITOR + if (!Application.isPlaying) + DestroyImmediate(mat); + else +#endif + Destroy(mat); - var g = graphic; - if (g) - { - g.SetMaterialDirty(); - } - _softMask = null; - } - - /// - /// This function is called when the behaviour becomes disabled. - /// - void OnDisable() - { - s_ActiveSoftMaskables.Remove(this); - - var g = graphic; - if (g) - { - g.SetMaterialDirty(); - } - ReleaseMaterial(ref _maskMaterial); - - _softMask = null; - - MaterialCache.Unregister(_effectMaterialHash); - _effectMaterialHash = k_InvalidHash; - } - - /// - /// Release the material. - /// - void ReleaseMaterial(ref Material mat) - { - if (mat) - { - #if UNITY_EDITOR - if (!Application.isPlaying) - { - DestroyImmediate(mat); - } - else - #endif - { - Destroy(mat); - } - mat = null; - } - } + mat = null; + } #if UNITY_EDITOR - /// - /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). - /// - private void OnValidate() - { - graphic.SetMaterialDirtyEx(); - } + /// + /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). + /// + private void OnValidate() + { + graphic.SetMaterialDirtyEx(); + } - void ISerializationCallbackReceiver.OnBeforeSerialize() - { - } + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + } - void ISerializationCallbackReceiver.OnAfterDeserialize() - { - #pragma warning disable 0612 - if (m_Inverse) - { - m_Inverse = false; - m_MaskInteraction = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6); - } - #pragma warning restore 0612 + void ISerializationCallbackReceiver.OnAfterDeserialize() + { +#pragma warning disable 0612 + if (m_Inverse) + { + m_Inverse = false; + m_MaskInteraction = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6); + } +#pragma warning restore 0612 - var current = this; - UnityEditor.EditorApplication.delayCall += () => - { - if (current && graphic && graphic.material && graphic.material.shader && graphic.material.shader.name == "Hidden/UI/Default (SoftMaskable)") - { - Debug.LogFormat("OnAfterDeserialize: reset material {0}",current); - graphic.material = null; - graphic.SetMaterialDirtyEx(); - } - }; + var current = this; + UnityEditor.EditorApplication.delayCall += () => + { + if (current && graphic && graphic.material && graphic.material.shader && + graphic.material.shader.name == "Hidden/UI/Default (SoftMaskable)") + { + graphic.material = null; + graphic.SetMaterialDirtyEx(); + } + }; #endif - } - } + } + } }