diff --git a/Samples~/Cartoon FX & War FX Demo/CFX_Demo_With_UIParticle.cs b/Samples~/Cartoon FX & War FX Demo/CFX_Demo_With_UIParticle.cs index c4c2aa1..122d98f 100644 --- a/Samples~/Cartoon FX & War FX Demo/CFX_Demo_With_UIParticle.cs +++ b/Samples~/Cartoon FX & War FX Demo/CFX_Demo_With_UIParticle.cs @@ -1,85 +1,87 @@ using System; using System.Linq; using System.Reflection; -using Coffee.UIExtensions; -using UnityEditor; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using Object = UnityEngine.Object; -public class CFX_Demo_With_UIParticle : MonoBehaviour +namespace Coffee.UIExtensions.Demo { - private UIParticle UiParticle; - private Toggle spawnOnUI; - private MonoBehaviour demo; - - // Start is called before the first frame update - private void Start() + public class CFX_Demo_With_UIParticle : MonoBehaviour { - UiParticle = GetComponentInChildren(); - spawnOnUI = GetComponentInChildren(); + private MonoBehaviour _demo; + private Toggle _spawnOnUI; + private UIParticle _uiParticle; - demo = FindObjectOfType("CFX_Demo_New") as MonoBehaviour - ?? FindObjectOfType("WFX_Demo_New") as MonoBehaviour; - - SetCanvasWidth(800); - SetCanvasRenderOverlay(true); - } - - private Object FindObjectOfType(string typeName) - { - var type = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(x => x.GetTypes()) - .FirstOrDefault(x => x.Name == typeName); - - return type == null ? null : FindObjectOfType(type); - } - - // Update is called once per frame - private void Update() - { - if (!spawnOnUI.isOn || !demo || !Input.GetMouseButtonDown(0)) return; - - foreach (Transform child in UiParticle.transform) + // Start is called before the first frame update + private void Start() { - Destroy(child.gameObject); + _uiParticle = GetComponentInChildren(); + _spawnOnUI = GetComponentInChildren(); + _demo = FindObjectOfType("CFX_Demo_New") as MonoBehaviour + ?? FindObjectOfType("WFX_Demo_New") as MonoBehaviour; + + SetCanvasWidth(800); + SetCanvasRenderOverlay(true); } - var particle = demo.GetType() - .GetMethod("spawnParticle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) - .Invoke(demo, new object[0]) as GameObject; - particle.transform.localScale = Vector3.one; - UiParticle.SetParticleSystemInstance(particle); - } - - public void SetCanvasWidth(int width) - { - var scaler = GetComponentInParent(); - scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; - scaler.matchWidthOrHeight = 0; - var resolution = scaler.referenceResolution; - resolution.x = width; - scaler.referenceResolution = resolution; - } - - public void SetCanvasRenderOverlay(bool enable) - { - var canvas = GetComponentInParent(); - if (enable) + // Update is called once per frame + private void Update() { - canvas.renderMode = RenderMode.ScreenSpaceOverlay; - } - else - { - canvas.worldCamera = Camera.main; - canvas.renderMode = RenderMode.ScreenSpaceCamera; - canvas.planeDistance = 5; - } - } + if (!_spawnOnUI.isOn || !_demo || !Input.GetMouseButtonDown(0)) return; - public void LoadScene(string scene) - { - SceneManager.LoadScene(scene); + foreach (Transform child in _uiParticle.transform) + { + Destroy(child.gameObject); + } + + var particle = _demo.GetType() + .GetMethod("spawnParticle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) + ?.Invoke(_demo, Array.Empty()) as GameObject; + if (!particle) return; + + particle.transform.localScale = Vector3.one; + _uiParticle.SetParticleSystemInstance(particle); + } + + private static Object FindObjectOfType(string typeName) + { + var type = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(x => x.GetTypes()) + .FirstOrDefault(x => x.Name == typeName); + + return type == null ? null : FindObjectOfType(type); + } + + public void SetCanvasWidth(int width) + { + var scaler = GetComponentInParent(); + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + scaler.matchWidthOrHeight = 0; + var resolution = scaler.referenceResolution; + resolution.x = width; + scaler.referenceResolution = resolution; + } + + public void SetCanvasRenderOverlay(bool enable) + { + var canvas = GetComponentInParent(); + if (enable) + { + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + } + else + { + canvas.worldCamera = Camera.main; + canvas.renderMode = RenderMode.ScreenSpaceCamera; + canvas.planeDistance = 5; + } + } + + public void LoadScene(string scene) + { + SceneManager.LoadScene(scene); + } } } diff --git a/Samples~/Demo/Scripts/CopyItemOnStart.cs b/Samples~/Demo/Scripts/CopyItemOnStart.cs index bf4d560..04d0d26 100644 --- a/Samples~/Demo/Scripts/CopyItemOnStart.cs +++ b/Samples~/Demo/Scripts/CopyItemOnStart.cs @@ -1,25 +1,31 @@ using UnityEngine; +using UnityEngine.Serialization; namespace Coffee.UIExtensions.Demo { public class CopyItemOnStart : MonoBehaviour { - public GameObject origin; - public int count; + [FormerlySerializedAs("origin")] + [SerializeField] + private GameObject m_Origin; + + [FormerlySerializedAs("count")] + [SerializeField] + private int m_Count; private void Start() { - if (!origin) return; - origin.SetActive(false); + if (!m_Origin) return; + m_Origin.SetActive(false); - var parent = origin.transform.parent; - for (var i = 0; i < count; i++) + var parent = m_Origin.transform.parent; + for (var i = 0; i < m_Count; i++) { - var go = Instantiate(origin, parent, false); - go.name = string.Format("{0} {1}", origin.name, i + 1); + var go = Instantiate(m_Origin, parent, false); + go.name = $"{m_Origin.name} {i + 1}"; go.hideFlags = HideFlags.DontSave; go.SetActive(true); } } } -} \ No newline at end of file +} diff --git a/Samples~/Demo/Scripts/UIElementDragger.cs b/Samples~/Demo/Scripts/UIElementDragger.cs index ea0f879..9dbdeda 100644 --- a/Samples~/Demo/Scripts/UIElementDragger.cs +++ b/Samples~/Demo/Scripts/UIElementDragger.cs @@ -1,25 +1,31 @@ -using UnityEngine; +using System; +using UnityEngine; using UnityEngine.EventSystems; +using UnityEngine.Serialization; public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { - public enum Target - { - Self, - Parent, - Custom, - } + [SerializeField] + private Target m_Target; - private RectTransform rectTransform; - private Canvas canvas; - public Target m_Target; - public Transform m_CustomTarget; - public bool ex2; + [SerializeField] + private Transform m_CustomTarget; + + [FormerlySerializedAs("ex2")] + [SerializeField] + private bool m_UseCanvasScale; + + private Canvas _canvas; + private RectTransform _rectTransform; private void OnEnable() { - rectTransform = GetComponent(); - canvas = GetComponentInParent(); + _rectTransform = GetComponent(); + _canvas = GetComponentInParent(); + } + + public void OnBeginDrag(PointerEventData eventData) + { } public void OnDrag(PointerEventData eventData) @@ -29,57 +35,59 @@ public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, switch (m_Target) { case Target.Self: - rectTransform.localPosition += delta; + _rectTransform.localPosition += delta; break; case Target.Parent: - rectTransform.parent.localPosition += delta; + _rectTransform.parent.localPosition += delta; break; case Target.Custom: - rectTransform.localPosition += delta; + _rectTransform.localPosition += delta; if (m_CustomTarget) { - if (ex2) - delta.Scale(canvas.rootCanvas.transform.localScale); + if (m_UseCanvasScale) + { + delta.Scale(_canvas.rootCanvas.transform.localScale); + } + m_CustomTarget.localPosition += delta; } + break; } } - public void OnBeginDrag(PointerEventData eventData) - { - } - public void OnEndDrag(PointerEventData eventData) { } private Vector2 GetLocalDelta(Vector2 evDelta) { - switch (canvas.renderMode) + switch (_canvas.renderMode) { case RenderMode.ScreenSpaceOverlay: - { - var zero = transform.InverseTransformPoint(Vector2.zero); - var delta = transform.InverseTransformPoint(evDelta); - return delta - zero; - } + { + var zero = transform.InverseTransformPoint(Vector2.zero); + var delta = transform.InverseTransformPoint(evDelta); + return delta - zero; + } case RenderMode.ScreenSpaceCamera: - { - Vector2 zero, delta; - RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, Vector2.zero, canvas.worldCamera, out zero); - RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, evDelta, canvas.worldCamera, out delta); - return delta - zero; - } case RenderMode.WorldSpace: - { - Vector3 zero, delta; - RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, Vector2.zero, canvas.worldCamera, out zero); - RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, evDelta, canvas.worldCamera, out delta); - return delta - zero; - } + { + RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, Vector2.zero, + _canvas.worldCamera, out var zero); + RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, evDelta, + _canvas.worldCamera, out var delta); + return delta - zero; + } default: - throw new System.NotSupportedException(); + throw new NotSupportedException(); } } -} \ No newline at end of file + + private enum Target + { + Self, + Parent, + Custom + } +} diff --git a/Samples~/Demo/Scripts/UIParticle_Demo.cs b/Samples~/Demo/Scripts/UIParticle_Demo.cs index 61ee262..dca4311 100644 --- a/Samples~/Demo/Scripts/UIParticle_Demo.cs +++ b/Samples~/Demo/Scripts/UIParticle_Demo.cs @@ -1,14 +1,18 @@ using UnityEngine; +using UnityEngine.Serialization; using UnityEngine.UI; namespace Coffee.UIExtensions.Demo { public class UIParticle_Demo : MonoBehaviour { - public Canvas root; + [FormerlySerializedAs("root")] + [SerializeField] + private Canvas m_RootCanvas; - private int _width; private int _height; + private int _score; + private int _width; private void Start() { @@ -24,11 +28,18 @@ namespace Coffee.UIExtensions.Demo case RuntimePlatform.WindowsPlayer: case RuntimePlatform.LinuxPlayer: if (Screen.width == _width && Screen.height == _height) + { Screen.SetResolution(_height, _width, Screen.fullScreen); + } else if (Screen.width == _height && Screen.height == _width) + { Screen.SetResolution(Mathf.Min(_width, _height), Mathf.Min(_width, _height), Screen.fullScreen); + } else + { Screen.SetResolution(_width, _height, Screen.fullScreen); + } + break; } } @@ -38,27 +49,31 @@ namespace Coffee.UIExtensions.Demo Screen.fullScreen = !Screen.fullScreen; } - public void EnableAnimations(bool enabled) + public void EnableAnimations(bool flag) { foreach (var animator in FindObjectsOfType()) { - animator.enabled = enabled; + animator.enabled = flag; } } - public void UIParticle_MeshSharing(bool enabled) + public void UIParticle_MeshSharing(bool flag) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootCanvas.GetComponentsInChildren(true)) { - uip.meshSharing = enabled ? UIParticle.MeshSharing.Auto : UIParticle.MeshSharing.None; + uip.meshSharing = flag + ? UIParticle.MeshSharing.Auto + : UIParticle.MeshSharing.None; } } - public void UIParticle_RandomGroup(bool enabled) + public void UIParticle_RandomGroup(bool flag) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootCanvas.GetComponentsInChildren(true)) { - uip.groupMaxId = enabled ? 4 : 0; + uip.groupMaxId = flag + ? 4 + : 0; } } @@ -70,38 +85,40 @@ namespace Coffee.UIExtensions.Demo } } - public void ParticleSystem_WorldSpaseSimulation(bool enabled) + public void ParticleSystem_WorldSpaseSimulation(bool flag) { - foreach (var ps in FindObjectsOfType()) + foreach (var p in FindObjectsOfType()) { - var main = ps.main; - main.simulationSpace = enabled ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local; + var main = p.main; + main.simulationSpace = flag + ? ParticleSystemSimulationSpace.World + : ParticleSystemSimulationSpace.Local; } } - public void ParticleSystem_WorldSpaseSimulation(ParticleSystem particleSystem) + public void ParticleSystem_WorldSpaseSimulation(ParticleSystem ps) { - foreach (var ps in particleSystem.GetComponentsInChildren()) + foreach (var p in ps.GetComponentsInChildren()) { - var main = ps.main; + var main = p.main; main.simulationSpace = ParticleSystemSimulationSpace.World; - ps.Clear(); + p.Clear(); } } - public void ParticleSystem_LocalSpaseSimulation(ParticleSystem particleSystem) + public void ParticleSystem_LocalSpaseSimulation(ParticleSystem ps) { - foreach (var ps in particleSystem.GetComponentsInChildren()) + foreach (var p in ps.GetComponentsInChildren()) { - var main = ps.main; + var main = p.main; main.simulationSpace = ParticleSystemSimulationSpace.Local; - ps.Clear(); + p.Clear(); } } - public void ParticleSystem_Emit(ParticleSystem particleSystem) + public void ParticleSystem_Emit(ParticleSystem ps) { - particleSystem.Emit(5); + ps.Emit(5); } public void ParticleSystem_SetScale(float scale) @@ -127,41 +144,37 @@ namespace Coffee.UIExtensions.Demo attractor.movement = UIParticleAttractor.Movement.Sphere; } - int score = 0; public void UIParticleAttractor_OnAttract(Text scoreText) { - score++; - scoreText.text = score.ToString(); + _score++; + scoreText.text = _score.ToString(); scoreText.GetComponent().Play(0); } public void Canvas_WorldSpace(bool flag) { - if (flag) - { - var canvas = FindObjectOfType(); - canvas.renderMode = RenderMode.ScreenSpaceCamera; - canvas.renderMode = RenderMode.WorldSpace; - canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0)); - } + if (!flag) return; + + var canvas = FindObjectOfType(); + canvas.renderMode = RenderMode.ScreenSpaceCamera; + canvas.renderMode = RenderMode.WorldSpace; + canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0)); } public void Canvas_CameraSpace(bool flag) { - if (flag) - { - var canvas = FindObjectOfType(); - canvas.renderMode = RenderMode.ScreenSpaceCamera; - } + if (!flag) return; + + var canvas = FindObjectOfType(); + canvas.renderMode = RenderMode.ScreenSpaceCamera; } public void Canvas_Overlay(bool flag) { - if (flag) - { - var canvas = FindObjectOfType(); - canvas.renderMode = RenderMode.ScreenSpaceOverlay; - } + if (!flag) return; + + var canvas = FindObjectOfType(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; } } } diff --git a/Samples~/Demo/Scripts/UIParticle_Demo_UIParticleController.cs b/Samples~/Demo/Scripts/UIParticle_Demo_UIParticleController.cs index e9b0286..21730a0 100644 --- a/Samples~/Demo/Scripts/UIParticle_Demo_UIParticleController.cs +++ b/Samples~/Demo/Scripts/UIParticle_Demo_UIParticleController.cs @@ -1,30 +1,37 @@ using UnityEngine; +using UnityEngine.Serialization; namespace Coffee.UIExtensions.Demo { public class UIParticle_Demo_UIParticleController : MonoBehaviour { - public Transform root; + [FormerlySerializedAs("root")] + [SerializeField] + private Transform m_RootTransform; - public void UIParticle_MeshSharing(bool enabled) + public void UIParticle_MeshSharing(bool flag) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootTransform.GetComponentsInChildren(true)) { - uip.meshSharing = enabled ? UIParticle.MeshSharing.Auto : UIParticle.MeshSharing.None; + uip.meshSharing = flag + ? UIParticle.MeshSharing.Auto + : UIParticle.MeshSharing.None; } } - public void UIParticle_RandomGroup(bool enabled) + public void UIParticle_RandomGroup(bool flag) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootTransform.GetComponentsInChildren(true)) { - uip.groupMaxId = enabled ? 4 : 0; + uip.groupMaxId = flag + ? 4 + : 0; } } public void UIParticle_Scale(float scale) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootTransform.GetComponentsInChildren(true)) { uip.scale = scale; } diff --git a/Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf b/Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf deleted file mode 100644 index b96b919..0000000 Binary files a/Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf and /dev/null differ diff --git a/Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf b/Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf new file mode 100644 index 0000000..8e6e84b Binary files /dev/null and b/Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf differ diff --git a/Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf.meta b/Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf.meta similarity index 82% rename from Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf.meta rename to Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf.meta index c27bccc..3a1dba4 100644 --- a/Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf.meta +++ b/Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 70069a8db1df148ae8b4c8108c079acf +guid: d07e6c2670f164cf7939ab011061a9bf TrueTypeFontImporter: externalObjects: {} serializedVersion: 4 @@ -8,9 +8,9 @@ TrueTypeFontImporter: characterSpacing: 0 characterPadding: 1 includeFontData: 1 - fontName: Falstin + fontName: Share Tech Mono fontNames: - - Falstin + - Share Tech Mono fallbackFontReferences: [] customCharacters: fontRenderingMode: 1 diff --git a/Samples~/Performance Demo/NanoMonitor/Prefab/NanoMonitor.prefab b/Samples~/Performance Demo/NanoMonitor/Prefab/NanoMonitor.prefab index 29a077f..40a0258 100644 --- a/Samples~/Performance Demo/NanoMonitor/Prefab/NanoMonitor.prefab +++ b/Samples~/Performance Demo/NanoMonitor/Prefab/NanoMonitor.prefab @@ -127,7 +127,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -206,7 +206,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -285,7 +285,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -366,7 +366,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -516,7 +516,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -595,7 +595,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -736,7 +736,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 16 m_FontStyle: 0 m_BestFit: 0 @@ -889,7 +889,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 16 m_FontStyle: 0 m_BestFit: 0 @@ -1042,7 +1042,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 @@ -1206,7 +1206,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 16 m_FontStyle: 0 m_BestFit: 0 @@ -1418,7 +1418,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_Interval: 0.5 m_Precision: 2 - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_Opened: 1 m_FoldoutObject: {fileID: 8720459857733317289} m_OpenButton: {fileID: 2149219299373497733} @@ -1502,7 +1502,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 16 m_FontStyle: 0 m_BestFit: 0 @@ -1695,7 +1695,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} m_FontSize: 14 m_FontStyle: 0 m_BestFit: 0 diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/NanoMonitor.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/NanoMonitor.cs index 23cc7e1..150fa65 100644 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/NanoMonitor.cs +++ b/Samples~/Performance Demo/NanoMonitor/Scripts/NanoMonitor.cs @@ -1,10 +1,11 @@ using System; using UnityEngine; +using UnityEngine.Profiling; using UnityEngine.Serialization; using UnityEngine.UI; #if UNITY_EDITOR using UnityEditor; - +using UnityEditorInternal; #endif namespace Coffee.NanoMonitor @@ -13,24 +14,29 @@ namespace Coffee.NanoMonitor [CustomEditor(typeof(NanoMonitor))] internal class NanoMonitorEditor : Editor { - private UnityEditorInternal.ReorderableList m_MonitorItemList; + private ReorderableList _monitorItemList; private void OnEnable() { var items = serializedObject.FindProperty("m_CustomMonitorItems"); - m_MonitorItemList = new UnityEditorInternal.ReorderableList(serializedObject, items) + _monitorItemList = new ReorderableList(serializedObject, items) { draggable = false, - drawHeaderCallback = r => { EditorGUI.LabelField(r, new GUIContent("Custom Monitor Items")); }, + drawHeaderCallback = r => + { + EditorGUI.LabelField(r, new GUIContent("Custom Monitor Items")); + }, drawElementCallback = (r, i, _, __) => { - EditorGUI.LabelField(new Rect(r.x, r.y, r.width, r.height - 2), GUIContent.none, EditorStyles.textArea); + EditorGUI.LabelField(new Rect(r.x, r.y, r.width, r.height - 2), GUIContent.none, + EditorStyles.textArea); var labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 80; - EditorGUI.PropertyField(new Rect(r.x + 2, r.y + 3, r.width - 4, r.height - 4), items.GetArrayElementAtIndex(i), true); + EditorGUI.PropertyField(new Rect(r.x + 2, r.y + 3, r.width - 4, r.height - 4), + items.GetArrayElementAtIndex(i), true); EditorGUIUtility.labelWidth = labelWidth; }, - elementHeightCallback = i => EditorGUI.GetPropertyHeight(items.GetArrayElementAtIndex(i)) + 6, + elementHeightCallback = i => EditorGUI.GetPropertyHeight(items.GetArrayElementAtIndex(i)) + 6 }; } @@ -38,7 +44,7 @@ namespace Coffee.NanoMonitor { base.OnInspectorGUI(); - m_MonitorItemList.DoLayoutList(); + _monitorItemList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); } } @@ -52,38 +58,50 @@ namespace Coffee.NanoMonitor // Serialize Members. //################################ // Settings - [Header("Settings")] [SerializeField] [Range(0.01f, 2f)] + [Header("Settings")] + [SerializeField] + [Range(0.01f, 2f)] private float m_Interval = 1f; - [SerializeField] [Range(0, 3)] private int m_Precision = 2; - [SerializeField] private Font m_Font; + [SerializeField] + [Range(0, 3)] + private int m_Precision = 2; + + [SerializeField] + private Font m_Font; // Foldout - [Header("Foldout")] [SerializeField] private bool m_Opened = false; + [Header("Foldout")] + [SerializeField] + private bool m_Opened; - [FormerlySerializedAs("m_Collapse")] [SerializeField] - private GameObject m_FoldoutObject = null; + [FormerlySerializedAs("m_Collapse")] + [SerializeField] + private GameObject m_FoldoutObject; - [SerializeField] private Button m_OpenButton = null; - [SerializeField] private Button m_CloseButton = null; + [SerializeField] + private Button m_OpenButton; + + [SerializeField] + private Button m_CloseButton; // View - [Header("View")] [SerializeField] private MonitorUI m_Fps = null; - [SerializeField] private MonitorUI m_Gc = null; - [SerializeField] private MonitorUI m_MonoUsage = null; - [SerializeField] private MonitorUI m_UnityUsage = null; + [Header("View")] + [SerializeField] + private MonitorUI m_Fps; - [HideInInspector] [SerializeField] private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0]; + [SerializeField] + private MonitorUI m_Gc; + [SerializeField] + private MonitorUI m_MonoUsage; - //################################ - // Public Members. - //################################ - public void Clean() - { - Resources.UnloadUnusedAssets(); - GC.Collect(); - } + [SerializeField] + private MonitorUI m_UnityUsage; + + [HideInInspector] + [SerializeField] + private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0]; //################################ @@ -93,44 +111,75 @@ namespace Coffee.NanoMonitor private double _fpsElapsed; private int _frames; - private void Open() + private void Update() { + _frames++; + _elapsed += Time.unscaledDeltaTime; + _fpsElapsed += Time.unscaledDeltaTime; + if (_elapsed < m_Interval) return; + + if (m_Fps) + { + m_Fps.SetText("FPS: {0}", (int)(_frames / _fpsElapsed)); + } + + if (m_Gc) + { + m_Gc.SetText("GC: {0}", GC.CollectionCount(0)); + } + + if (m_MonoUsage) + { + var monoUsed = (Profiler.GetMonoUsedSizeLong() >> 10) / 1024f; + var monoTotal = (Profiler.GetMonoHeapSizeLong() >> 10) / 1024f; + if (m_Precision == 3) + { + m_MonoUsage.SetText("Mono: {0:N3}/{1:N3}MB", monoUsed, monoTotal); + } + else if (m_Precision == 2) + { + m_MonoUsage.SetText("Mono: {0:N2}/{1:N2}MB", monoUsed, monoTotal); + } + else if (m_Precision == 1) + { + m_MonoUsage.SetText("Mono: {0:N1}/{1:N1}MB", monoUsed, monoTotal); + } + else + { + m_MonoUsage.SetText("Mono: {0:N0}/{1:N0}MB", monoUsed, monoTotal); + } + } + + if (m_UnityUsage) + { + var unityUsed = (Profiler.GetTotalAllocatedMemoryLong() >> 10) / 1024f; + var unityTotal = (Profiler.GetTotalReservedMemoryLong() >> 10) / 1024f; + if (m_Precision == 3) + { + m_UnityUsage.SetText("Unity: {0:N3}/{1:N3}MB", unityUsed, unityTotal); + } + else if (m_Precision == 2) + { + m_UnityUsage.SetText("Unity: {0:N2}/{1:N2}MB", unityUsed, unityTotal); + } + else if (m_Precision == 1) + { + m_UnityUsage.SetText("Unity: {0:N1}/{1:N1}MB", unityUsed, unityTotal); + } + else + { + m_UnityUsage.SetText("Unity: {0:N0}/{1:N0}MB", unityUsed, unityTotal); + } + } + + foreach (var item in m_CustomMonitorItems) + { + item.UpdateText(); + } + _frames = 0; - _elapsed = m_Interval; + _elapsed %= m_Interval; _fpsElapsed = 0; - - if (m_FoldoutObject) - { - m_FoldoutObject.SetActive(true); - } - - if (m_CloseButton) - { - m_CloseButton.gameObject.SetActive(true); - } - - if (m_OpenButton) - { - m_OpenButton.gameObject.SetActive(false); - } - } - - private void Close() - { - if (m_FoldoutObject) - { - m_FoldoutObject.SetActive(false); - } - - if (m_CloseButton) - { - m_CloseButton.gameObject.SetActive(false); - } - - if (m_OpenButton) - { - m_OpenButton.gameObject.SetActive(true); - } } @@ -172,77 +221,6 @@ namespace Coffee.NanoMonitor } } - private void Update() - { - _frames++; - _elapsed += Time.unscaledDeltaTime; - _fpsElapsed += Time.unscaledDeltaTime; - if (_elapsed < m_Interval) return; - - if (m_Fps) - { - m_Fps.SetText("FPS: {0}", (int) (_frames / _fpsElapsed)); - } - - if (m_Gc) - { - m_Gc.SetText("GC: {0}", GC.CollectionCount(0)); - } - - if (m_MonoUsage) - { - var monoUsed = (UnityEngine.Profiling.Profiler.GetMonoUsedSizeLong() >> 10) / 1024f; - var monoTotal = (UnityEngine.Profiling.Profiler.GetMonoHeapSizeLong() >> 10) / 1024f; - if (m_Precision == 3) - { - m_MonoUsage.SetText("Mono: {0:N3}/{1:N3}MB", monoUsed, monoTotal); - } - else if (m_Precision == 2) - { - m_MonoUsage.SetText("Mono: {0:N2}/{1:N2}MB", monoUsed, monoTotal); - } - else if (m_Precision == 1) - { - m_MonoUsage.SetText("Mono: {0:N1}/{1:N1}MB", monoUsed, monoTotal); - } - else - { - m_MonoUsage.SetText("Mono: {0:N0}/{1:N0}MB", monoUsed, monoTotal); - } - } - - if (m_UnityUsage) - { - var unityUsed = (UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong() >> 10) / 1024f; - var unityTotal = (UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong() >> 10) / 1024f; - if (m_Precision == 3) - { - m_UnityUsage.SetText("Unity: {0:N3}/{1:N3}MB", unityUsed, unityTotal); - } - else if (m_Precision == 2) - { - m_UnityUsage.SetText("Unity: {0:N2}/{1:N2}MB", unityUsed, unityTotal); - } - else if (m_Precision == 1) - { - m_UnityUsage.SetText("Unity: {0:N1}/{1:N1}MB", unityUsed, unityTotal); - } - else - { - m_UnityUsage.SetText("Unity: {0:N0}/{1:N0}MB", unityUsed, unityTotal); - } - } - - foreach (var item in m_CustomMonitorItems) - { - item.UpdateText(); - } - - _frames = 0; - _elapsed %= m_Interval; - _fpsElapsed = 0; - } - #if UNITY_EDITOR private void OnValidate() { @@ -264,5 +242,55 @@ namespace Coffee.NanoMonitor } } #endif + + + //################################ + // Public Members. + //################################ + public void Clean() + { + Resources.UnloadUnusedAssets(); + GC.Collect(); + } + + private void Open() + { + _frames = 0; + _elapsed = m_Interval; + _fpsElapsed = 0; + + if (m_FoldoutObject) + { + m_FoldoutObject.SetActive(true); + } + + if (m_CloseButton) + { + m_CloseButton.gameObject.SetActive(true); + } + + if (m_OpenButton) + { + m_OpenButton.gameObject.SetActive(false); + } + } + + private void Close() + { + if (m_FoldoutObject) + { + m_FoldoutObject.SetActive(false); + } + + if (m_CloseButton) + { + m_CloseButton.gameObject.SetActive(false); + } + + if (m_OpenButton) + { + m_OpenButton.gameObject.SetActive(true); + } + } } } diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/FixedFont.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/FixedFont.cs index c78007b..e4eb044 100644 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/FixedFont.cs +++ b/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/FixedFont.cs @@ -2,14 +2,17 @@ using UnityEngine; using UnityEngine.UI; -namespace Coffee.NanoMonitor{ +namespace Coffee.NanoMonitor +{ public class FixedFont { - private readonly UIVertex[] _tmpVerts = new UIVertex[4]; - private static readonly Dictionary _fonts = new Dictionary(); - private static readonly TextGenerator _textGenerator = new TextGenerator(100); + private const string k_Characters = + "_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; - private static TextGenerationSettings _settings = new TextGenerationSettings + private static readonly Dictionary s_Fonts = new Dictionary(); + private static readonly TextGenerator s_TextGenerator = new TextGenerator(100); + + private static TextGenerationSettings s_Settings = new TextGenerationSettings { scaleFactor = 1, horizontalOverflow = HorizontalWrapMode.Overflow, @@ -19,25 +22,33 @@ namespace Coffee.NanoMonitor{ color = Color.white }; - private int _resolution = 0; private readonly Font _font; - private UIVertex[] _verts; + private readonly UIVertex[] _tmpVerts = new UIVertex[4]; private UICharInfo[] _charInfos; + private int _resolution; + private UIVertex[] _verts; + private FixedFont(Font font) { _font = font; } - public int fontSize => _font.dynamic ? 32 : _font.fontSize; + public int fontSize + { + get + { + return _font.dynamic ? 32 : _font.fontSize; + } + } public static FixedFont GetOrCreate(Font font) { if (font == null) return null; - if (_fonts.TryGetValue(font, out var data)) return data; + if (s_Fonts.TryGetValue(font, out var data)) return data; data = new FixedFont(font); - _fonts.Add(font, data); + s_Fonts.Add(font, data); return data; } @@ -61,18 +72,20 @@ namespace Coffee.NanoMonitor{ if (_resolution == currentResolution) return; _resolution = currentResolution; - _settings.font = _font; - _textGenerator.Invalidate(); - _textGenerator.Populate("_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", _settings); + s_Settings.font = _font; + s_TextGenerator.Invalidate(); + s_TextGenerator.Populate(k_Characters, s_Settings); - _verts = _textGenerator.GetVerticesArray(); - _charInfos = _textGenerator.GetCharactersArray(); + _verts = s_TextGenerator.GetVerticesArray(); + _charInfos = s_TextGenerator.GetCharactersArray(); float offsetX = 0; for (var i = 0; i < _verts.Length; i++) { if ((i & 3) == 0) + { offsetX = _verts[i].position.x; + } var v = _verts[i]; v.position -= new Vector3(offsetX, 0); @@ -118,18 +131,27 @@ namespace Coffee.NanoMonitor{ for (var i = 0; i < 4; i++) { - _tmpVerts[i] = new UIVertex(); - _tmpVerts[i].uv0 = uv; - _tmpVerts[i].color = color; + _tmpVerts[i] = new UIVertex + { + uv0 = uv, + color = color + }; - if (i == 0) - _tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset; - else if (i == 1) - _tmpVerts[i].position = new Vector2(-size.x, size.y) + offset; - else if (i == 2) - _tmpVerts[i].position = new Vector2(size.x, size.y) + offset; - else - _tmpVerts[i].position = new Vector2(size.x, -size.y) + offset; + switch (i) + { + case 0: + _tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset; + break; + case 1: + _tmpVerts[i].position = new Vector2(-size.x, size.y) + offset; + break; + case 2: + _tmpVerts[i].position = new Vector2(size.x, size.y) + offset; + break; + case 3: + _tmpVerts[i].position = new Vector2(size.x, -size.y) + offset; + break; + } } toFill.AddUIVertexQuad(_tmpVerts); diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/MonitorUI.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/MonitorUI.cs index 64300ff..00dad86 100644 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/MonitorUI.cs +++ b/Samples~/Performance Demo/NanoMonitor/Scripts/ProfilerUI/MonitorUI.cs @@ -1,50 +1,46 @@ using System.Text; +using UnityEditor; using UnityEngine; using UnityEngine.UI; -namespace Coffee.NanoMonitor{ +namespace Coffee.NanoMonitor +{ #if UNITY_EDITOR - using UnityEditor; - [CustomEditor(typeof(MonitorUI))] public class MonitorTextEditor : Editor { - private SerializedProperty m_Mode; - private SerializedProperty m_TextAnchor; - private SerializedProperty m_FontSize; - private SerializedProperty m_Font; - private SerializedProperty m_Text; - private SerializedProperty m_Color; + private SerializedProperty _color; + private SerializedProperty _font; + private SerializedProperty _fontSize; + private SerializedProperty _mode; + private SerializedProperty _text; + private SerializedProperty _textAnchor; private void OnEnable() { - m_Mode = serializedObject.FindProperty("m_Mode"); - - m_Text = serializedObject.FindProperty("m_Text"); - m_Color = serializedObject.FindProperty("m_Color"); + _mode = serializedObject.FindProperty("m_Mode"); + _text = serializedObject.FindProperty("m_Text"); + _color = serializedObject.FindProperty("m_Color"); var fontData = serializedObject.FindProperty("m_FontData"); - m_FontSize = fontData.FindPropertyRelative("m_FontSize"); - m_Font = fontData.FindPropertyRelative("m_Font"); - m_TextAnchor = serializedObject.FindProperty("m_TextAnchor"); + _fontSize = fontData.FindPropertyRelative("m_FontSize"); + _font = fontData.FindPropertyRelative("m_Font"); + _textAnchor = serializedObject.FindProperty("m_TextAnchor"); } public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(m_Mode); - if ((MonitorUI.Mode) m_Mode.intValue == MonitorUI.Mode.Text) + EditorGUILayout.PropertyField(_mode); + if ((MonitorUI.Mode)_mode.intValue == MonitorUI.Mode.Text) { - EditorGUILayout.PropertyField(m_Text); - EditorGUILayout.PropertyField(m_FontSize); - EditorGUILayout.PropertyField(m_TextAnchor); - - //EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.PropertyField(m_Font); - //EditorGUI.EndDisabledGroup(); + EditorGUILayout.PropertyField(_text); + EditorGUILayout.PropertyField(_fontSize); + EditorGUILayout.PropertyField(_textAnchor); + EditorGUILayout.PropertyField(_font); } - EditorGUILayout.PropertyField(m_Color); + EditorGUILayout.PropertyField(_color); serializedObject.ApplyModifiedProperties(); } @@ -56,7 +52,7 @@ namespace Coffee.NanoMonitor{ public enum Mode { Text, - Fill, + Fill } public enum TextAnchor @@ -74,26 +70,38 @@ namespace Coffee.NanoMonitor{ [SerializeField] private TextAnchor m_TextAnchor; + //################################ + // Private Members. + //################################ + private readonly StringBuilder _sb = new StringBuilder(64); + + //################################ // Public Members. //################################ public override string text { - get => m_StringBuilder.ToString(); + get + { + return _sb.ToString(); + } set { m_Text = value; - if (m_StringBuilder.IsEqual(m_Text)) return; + if (_sb.IsEqual(m_Text)) return; - m_StringBuilder.Length = 0; - m_StringBuilder.Append(m_Text); + _sb.Length = 0; + _sb.Append(m_Text); SetVerticesDirty(); } } public TextAnchor textAnchor { - get => m_TextAnchor; + get + { + return m_TextAnchor; + } set { if (m_TextAnchor == value) return; @@ -105,44 +113,11 @@ namespace Coffee.NanoMonitor{ public override bool raycastTarget { - get => m_Mode == Mode.Fill; - set { } - } - - public void SetText(string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0) - { - m_StringBuilder.Length = 0; - m_StringBuilder.AppendFormatNoAlloc(format, arg0, arg1, arg2, arg3); - SetVerticesDirty(); - } - - public void SetText(StringBuilder builder) - { - m_StringBuilder.Length = 0; - m_StringBuilder.Append(builder); - SetVerticesDirty(); - } - - - //################################ - // Private Members. - //################################ - private readonly StringBuilder m_StringBuilder = new StringBuilder(64); - - private void UpdateFont() - { - //var globalFont = NNanoMonitorttings.Instance.font; - //if (globalFont) - //{ - // font = globalFont; - //} - - var fontData = FixedFont.GetOrCreate(font); - if (fontData != null) + get { - fontData.Invalidate(); - fontData.UpdateFont(); + return m_Mode == Mode.Fill; } + set { } } @@ -151,19 +126,17 @@ namespace Coffee.NanoMonitor{ //################################ protected override void OnEnable() { - //NaNanoMonitortings.Instance.onFontChanged += UpdateFont; RegisterDirtyMaterialCallback(UpdateFont); base.OnEnable(); raycastTarget = false; maskable = false; - m_StringBuilder.Length = 0; - m_StringBuilder.Append(m_Text); + _sb.Length = 0; + _sb.Append(m_Text); } protected override void OnDisable() { - //NanNanoMonitorings.Instance.onFontChanged -= UpdateFont; UnregisterDirtyMaterialCallback(UpdateFont); base.OnDisable(); @@ -174,14 +147,38 @@ namespace Coffee.NanoMonitor{ { base.OnValidate(); - if (!m_StringBuilder.IsEqual(m_Text)) + if (!_sb.IsEqual(m_Text)) { - m_StringBuilder.Length = 0; - m_StringBuilder.Append(m_Text); + _sb.Length = 0; + _sb.Append(m_Text); } } #endif + public void SetText(string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0) + { + _sb.Length = 0; + _sb.AppendFormatNoAlloc(format, arg0, arg1, arg2, arg3); + SetVerticesDirty(); + } + + public void SetText(StringBuilder builder) + { + _sb.Length = 0; + _sb.Append(builder); + SetVerticesDirty(); + } + + private void UpdateFont() + { + var fontData = FixedFont.GetOrCreate(font); + if (fontData != null) + { + fontData.Invalidate(); + fontData.UpdateFont(); + } + } + protected override void OnPopulateMesh(VertexHelper toFill) { toFill.Clear(); @@ -197,7 +194,7 @@ namespace Coffee.NanoMonitor{ return; } - var scale = (float) fontSize / fontData.fontSize; + var scale = (float)fontSize / fontData.fontSize; float offset = 0; switch (textAnchor) { @@ -205,20 +202,26 @@ namespace Coffee.NanoMonitor{ offset = rectTransform.rect.xMin; break; case TextAnchor.Center: - for (var i = 0; i < m_StringBuilder.Length; i++) - offset = fontData.Layout(m_StringBuilder[i], offset, scale); + for (var i = 0; i < _sb.Length; i++) + { + offset = fontData.Layout(_sb[i], offset, scale); + } + offset = -offset / 2; break; case TextAnchor.Right: - for (var i = 0; i < m_StringBuilder.Length; i++) - offset = fontData.Layout(m_StringBuilder[i], offset, scale); + for (var i = 0; i < _sb.Length; i++) + { + offset = fontData.Layout(_sb[i], offset, scale); + } + offset = rectTransform.rect.xMax - offset; break; } - for (var i = 0; i < m_StringBuilder.Length; i++) + for (var i = 0; i < _sb.Length; i++) { - offset = fontData.Append(toFill, m_StringBuilder[i], offset, scale, color); + offset = fontData.Append(toFill, _sb[i], offset, scale, color); } } diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs deleted file mode 100644 index d72823c..0000000 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Linq; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Coffee.MiniProfiler -{ - internal class MiniProfilerSettings : ScriptableSettings - { - [Header("UI")] - [SerializeField] private Font m_Font = null; - - [Header("Instantiate On Boot")] - [SerializeField] private GameObject miniProfilerPrefab = null; - [SerializeField] private string[] m_SceneNames = new string[0]; - - public Font font => m_Font; - public event Action onFontChanged; - - protected override void OnBoot() - { - SceneManager.sceneLoaded -= OnSceneLoaded; - SceneManager.sceneLoaded += OnSceneLoaded; - } - - public void OnSceneLoaded(Scene scene, LoadSceneMode __) - { - SceneManager.sceneLoaded -= OnSceneLoaded; - if (!miniProfilerPrefab || !m_SceneNames.Contains(scene.name)) return; - - var go = Instantiate(miniProfilerPrefab); - if (Application.isPlaying) - DontDestroyOnLoad(go); - } - - protected override bool bootOnPlayMode => true; - protected override bool bootOnEditorMode => false; - -#if UNITY_EDITOR - protected override void OnValidate() - { - onFontChanged?.Invoke(); - base.OnValidate(); - } - - private void Reset() - { - m_Font = UnityEngine.Resources.GetBuiltinResource("Arial.ttf"); - } - - [UnityEditor.SettingsProvider] - private static UnityEditor.SettingsProvider CreateSettingsProvider() => new ScriptableSettingsProvider(); -#endif - } -} diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs.meta b/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs.meta deleted file mode 100644 index 1ef5cb1..0000000 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs.meta +++ /dev/null @@ -1,13 +0,0 @@ -fileFormatVersion: 2 -guid: 647dad4f8226a49b9874b68b79413d64 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: - - miniProfilerPrefab: {fileID: 7211429669315726685, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs deleted file mode 100644 index 88efa98..0000000 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs +++ /dev/null @@ -1,280 +0,0 @@ -using UnityEngine; -using System; -using System.Linq; -#if UNITY_EDITOR -using UnityEditor; - -#endif - -namespace Coffee.MiniProfiler -{ - internal abstract class ScriptableSettings : ScriptableObject - { -#if UNITY_EDITOR - public virtual string GetSettingPath() - { - return GetSettingPath(GetType()); - } - - internal static string GetSettingPath(Type type) - { - return $"Project/{ObjectNames.NicifyVariableName(type.Name.Replace("ProjectSettings", ""))}"; - } -#endif - - public virtual string GetDefaultAssetPath() - { - return $"Assets/ProjectSettings/{GetType().Name}.asset"; - } - } - - internal abstract class ScriptableSettings : ScriptableSettings - where T : ScriptableSettings - { - //################################ - // Public Members. - //################################ - public static T Instance => _instance ? _instance : _instance = GetOrCreate(); - - private static T _instance; - - protected virtual bool bootOnEditorMode => true; - protected virtual bool bootOnPlayMode => true; - - protected abstract void OnBoot(); - -#if UNITY_EDITOR - //################################ - // Private Members. - //################################ - private bool enabled; - - private static T GetOrCreate() - { - return PlayerSettings.GetPreloadedAssets() - .OfType() - .FirstOrDefault() ?? CreateInstance(); - } - - private void OnPlayModeStateChanged(PlayModeStateChange state) - { - switch (state) - { - case PlayModeStateChange.EnteredEditMode: - enabled = true; - Boot(); - break; - case PlayModeStateChange.ExitingEditMode: - case PlayModeStateChange.ExitingPlayMode: - enabled = false; - break; - } - } - - private void Boot() - { - var preloadedAssets = PlayerSettings.GetPreloadedAssets(); - var assets = preloadedAssets.OfType().ToArray(); - var first = assets.FirstOrDefault() ?? this as T; - - // If there are no preloaded assets, registry the first asset. - // If there are multiple preloaded assets, unregisters all but the first one. - if (assets.Length != 1) - { - // The first asset is not saved. - if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(first))) - { - if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings")) - AssetDatabase.CreateFolder("Assets", "ProjectSettings"); - - var assetName = ObjectNames.NicifyVariableName(first.GetType().Name.Replace("ProjectSettings", "")); - var assetPath = AssetDatabase.GenerateUniqueAssetPath($"Assets/ProjectSettings/{assetName}.asset"); - AssetDatabase.CreateAsset(first, assetPath); - } - - PlayerSettings.SetPreloadedAssets(preloadedAssets - .Where(x => x) - .Except(assets) - .Concat(new[] {first}) - .ToArray()); - } - - // Another asset is registered as a preload asset. - if (first != this) - { - UnityEngine.Debug.LogError($"Another asset '{first}' is registered as a preload '{typeof(T).Name}' asset." + - $"\nThis instance ('{this}') will be ignored. Check 'Project Settings > Player > Preload Assets'", this); - return; - } - - _instance = first; - - // Do nothing on editor mode. - if (!bootOnEditorMode && !EditorApplication.isPlayingOrWillChangePlaymode) - { - return; - } - - // Do nothing on play mode. - if (!bootOnPlayMode && EditorApplication.isPlayingOrWillChangePlaymode) - { - return; - } - - OnBoot(); - } - - - //################################ - // Unity Callbacks. - //################################ - private void OnEnable() - { - enabled = true; - Boot(); - EditorApplication.playModeStateChanged += OnPlayModeStateChanged; - } - - private void OnDisable() - { - EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; - } - - protected virtual void OnValidate() - { - if (enabled) - Boot(); - } -#else - private static T GetOrCreate() - { - return CreateInstance(); - } - - private void OnEnable() - { - if (!bootOnPlayMode) return; - - _instance = this as T; - OnBoot(); - } -#endif - } - - [CustomEditor(typeof(ScriptablePreferenceSettings<>), true)] - internal class ScriptablePreferenceSettingsEditor : Editor - { - private static readonly GUIContent _button = new GUIContent("Open Project Settings"); - - public override void OnInspectorGUI() - { - if (GUILayout.Button(_button)) - { - SettingsService.OpenProjectSettings(((ScriptableSettings) target).GetSettingPath()); - } - } - } - - internal abstract class ScriptablePreferenceSettings : ScriptableSingleton - where T : ScriptablePreferenceSettings - { - } - -#if UNITY_EDITOR - [CustomEditor(typeof(ScriptableSettings), true)] - internal class ScriptableSettingsEditor : Editor - { - private static readonly GUIContent _button = new GUIContent("Open Project Settings"); - - public override void OnInspectorGUI() - { - if (GUILayout.Button(_button)) - { - SettingsService.OpenProjectSettings(((ScriptableSettings) target).GetSettingPath()); - } - } - } - - internal class ScriptableSettingsProvider : SettingsProvider where T : ScriptableSettings - { - public ScriptableSettingsProvider(string path) : base(path) - { - } - - public ScriptableSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T))) - { - } - - protected SerializedObject serializedObject { get; private set; } - protected ScriptableSettings target { get; private set; } - - public sealed override void OnGUI(string searchContext) - { - if (!target) - { - target = ScriptableSettings.Instance; - serializedObject = new SerializedObject(target); - } - - OnGUI(); - } - - protected virtual void OnGUI() - { - serializedObject.UpdateIfRequiredOrScript(); - var iterator = serializedObject.GetIterator(); - var enterChildren = true; - while (iterator.NextVisible(enterChildren)) - { - if (iterator.propertyPath != "m_Script") - EditorGUILayout.PropertyField(iterator, true); - - enterChildren = false; - } - - serializedObject.ApplyModifiedProperties(); - } - } - - internal class ScriptablePreferenceSettingsProvider : SettingsProvider where T : ScriptableSettings - { - public ScriptablePreferenceSettingsProvider(string path) : base(path, SettingsScope.User) - { - } - - public ScriptablePreferenceSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T)), SettingsScope.User) - { - } - - protected SerializedObject serializedObject { get; private set; } - protected ScriptableSettings target { get; private set; } - - public sealed override void OnGUI(string searchContext) - { - if (!target) - { - target = ScriptableSettings.Instance; - serializedObject = new SerializedObject(target); - } - - OnGUI(); - } - - protected virtual void OnGUI() - { - serializedObject.UpdateIfRequiredOrScript(); - var iterator = serializedObject.GetIterator(); - var enterChildren = true; - while (iterator.NextVisible(enterChildren)) - { - if (iterator.propertyPath != "m_Script") - EditorGUILayout.PropertyField(iterator, true); - - enterChildren = false; - } - - serializedObject.ApplyModifiedProperties(); - } - } -#endif -} diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs.meta b/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs.meta deleted file mode 100644 index 2b0d84a..0000000 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6ea9606f69cee413e9f96f52de99fa5e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/CustomProfilerItem.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/CustomProfilerItem.cs index 877ea3e..f6765f0 100644 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/CustomProfilerItem.cs +++ b/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/CustomProfilerItem.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System; +using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif @@ -11,12 +12,17 @@ namespace Coffee.NanoMonitor { public override void OnGUI(Rect p, SerializedProperty property, GUIContent label) { - EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 0, p.width, 16), property.FindPropertyRelative("m_Text")); - EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 1, p.width, 16), property.FindPropertyRelative("m_Format")); + var pos = new Rect(p.x, p.y + 18 * 0, p.width, 16); + EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Text")); + pos.y += 18; + EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Format")); + pos.y += 18; EditorGUI.indentLevel++; - EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 2, p.width, 16), property.FindPropertyRelative("m_Arg0")); - EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 3, p.width, 16), property.FindPropertyRelative("m_Arg1")); - EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 4, p.width, 16), property.FindPropertyRelative("m_Arg2")); + EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg0")); + pos.y += 18; + EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg1")); + pos.y += 18; + EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg2")); EditorGUI.indentLevel--; property.serializedObject.ApplyModifiedProperties(); @@ -29,19 +35,21 @@ namespace Coffee.NanoMonitor } #endif - [System.Serializable] + [Serializable] public class CustomMonitorItem { - [SerializeField] private MonitorUI m_Text = null; + [SerializeField] private MonitorUI m_Text; [SerializeField] private string m_Format = ""; - [SerializeField] private NumericProperty m_Arg0 = null; - [SerializeField] private NumericProperty m_Arg1 = null; - [SerializeField] private NumericProperty m_Arg2 = null; + [SerializeField] private NumericProperty m_Arg0; + [SerializeField] private NumericProperty m_Arg1; + [SerializeField] private NumericProperty m_Arg2; public void UpdateText() { if (m_Text) + { m_Text.SetText(m_Format, m_Arg0.Get(), m_Arg1.Get(), m_Arg2.Get()); + } } } } diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/NumericProperty.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/NumericProperty.cs index cc81e9c..f2652b7 100644 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/NumericProperty.cs +++ b/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/NumericProperty.cs @@ -2,12 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using UnityEngine; -using UnityEngine.Serialization; -#if UNITY_EDITOR using UnityEditor; - -#endif +using UnityEngine; namespace Coffee.NanoMonitor { @@ -20,39 +16,45 @@ namespace Coffee.NanoMonitor private static readonly Dictionary s_SupportedTypes = new Dictionary { - {typeof(bool), "bool"}, - {typeof(sbyte), "sbyte"}, - {typeof(short), "short"}, - {typeof(int), "int"}, - {typeof(long), "long"}, - {typeof(byte), "byte"}, - {typeof(ushort), "ushort"}, - {typeof(uint), "uint"}, - {typeof(ulong), "ulong"}, - {typeof(float), "float"}, - {typeof(double), "double"}, - {typeof(decimal), "decimal"}, + { typeof(bool), "bool" }, + { typeof(sbyte), "sbyte" }, + { typeof(short), "short" }, + { typeof(int), "int" }, + { typeof(long), "long" }, + { typeof(byte), "byte" }, + { typeof(ushort), "ushort" }, + { typeof(uint), "uint" }, + { typeof(ulong), "ulong" }, + { typeof(float), "float" }, + { typeof(double), "double" }, + { typeof(decimal), "decimal" } }; private static void Init() { if (s_PropertyMenu != null) return; + const BindingFlags bindingFlags = BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Static + | BindingFlags.GetProperty; var properties = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) - .SelectMany(type => type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty)) + .SelectMany(type => type.GetProperties(bindingFlags)) .Where(pi => pi.GetMethod != null && s_SupportedTypes.ContainsKey(pi.PropertyType)) .OrderBy(pi => ConvertToMenuItem(pi, false)) .ToArray(); s_PropertyMenu = new GenericMenu(); - s_PropertyMenu.AddItem(new GUIContent("No Property"), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null); - s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, ()=>{}); + s_PropertyMenu.AddItem(new GUIContent("No Property"), false, + arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null); + s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, () => { }); s_PropertyMenu.AddSeparator(""); foreach (var pi in properties) { - s_PropertyMenu.AddItem(new GUIContent(ConvertToMenuItem(pi, true)), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), pi); + s_PropertyMenu.AddItem(new GUIContent(ConvertToMenuItem(pi, true)), false, + arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), pi); } } @@ -60,11 +62,17 @@ namespace Coffee.NanoMonitor { var type = p.DeclaringType; if (type == null) return ""; - var category = p.GetMethod.IsPublic && type.IsPublic ? "" : "(Non Public Properties)/"; + + var category = p.GetMethod.IsPublic && type.IsPublic + ? "" + : "(Non Public Properties)/"; var typeName = type.FullName; var asmName = type.Assembly.GetName().Name; if (asmName == "UnityEngine.CoreModule") + { asmName = "UnityEngine"; + } + return propertyType ? $"{category}{asmName}/{typeName}/{s_SupportedTypes[p.PropertyType]} {p.Name}" : $"{category}{asmName}/{typeName}/{p.Name}"; @@ -84,7 +92,9 @@ namespace Coffee.NanoMonitor { s_OnMenuSelected = p => { - path.stringValue = p == null ? "" : $"{p.DeclaringType?.FullName}, {p.DeclaringType?.Assembly.GetName().Name};{p.Name}"; + path.stringValue = p == null + ? "" + : $"{p.DeclaringType?.FullName}, {p.DeclaringType?.Assembly.GetName().Name};{p.Name}"; property.serializedObject.ApplyModifiedProperties(); }; s_PropertyMenu.DropDown(position); @@ -104,6 +114,22 @@ namespace Coffee.NanoMonitor [SerializeField] private string m_Path = ""; + //################################ + // Private Members. + //################################ + private Func _get; + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + var pInfo = GetPropertyInfo(m_Path); + _get = CreateFunc(pInfo?.GetMethod); + } + + //################################ // Public Members. //################################ @@ -112,12 +138,6 @@ namespace Coffee.NanoMonitor return _get?.Invoke() ?? -1; } - - //################################ - // Private Members. - //################################ - private Func _get = null; - private static PropertyInfo GetPropertyInfo(string path) { var p = path.Split(';'); @@ -126,14 +146,14 @@ namespace Coffee.NanoMonitor var type = Type.GetType(p[0]); if (type == null) { - UnityEngine.Debug.LogException(new Exception($"Type '{p[0]}' is not found")); + Debug.LogException(new Exception($"Type '{p[0]}' is not found")); return null; } var pInfo = type.GetProperty(p[1], BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static); if (pInfo == null) { - UnityEngine.Debug.LogException(new Exception($"Member '{p[1]}' is not found in type '{type}'")); + Debug.LogException(new Exception($"Member '{p[1]}' is not found in type '{type}'")); } return pInfo; @@ -145,55 +165,72 @@ namespace Coffee.NanoMonitor switch (Type.GetTypeCode(mInfo.ReturnType)) { case TypeCode.Boolean: - var f_bool = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_bool() ? 1 : 0; + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func() ? 1 : 0; + } case TypeCode.Byte: - var f_byte = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_byte(); + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func(); + } case TypeCode.SByte: - var f_sbyte = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_sbyte(); + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func(); + } case TypeCode.UInt16: - var f_ushort = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_ushort(); + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func(); + } case TypeCode.UInt32: - var f_uint = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_uint(); + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func(); + } case TypeCode.UInt64: - var f_ulong = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_ulong(); + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func(); + } case TypeCode.Int16: - var f_short = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_short(); + { + var func = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => func(); + } case TypeCode.Int32: - var f_int = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_int(); + { + var f = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => f(); + } case TypeCode.Int64: - var f_long = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_long(); + { + var f = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => f(); + } case TypeCode.Decimal: - var f_decimal = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => (double) f_decimal(); + { + var f = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => (double)f(); + } case TypeCode.Double: - var f_double = (Func) mInfo.CreateDelegate(typeof(Func)); - return f_double; + { + var f = (Func)mInfo.CreateDelegate(typeof(Func)); + return f; + } case TypeCode.Single: - var f_float = (Func) mInfo.CreateDelegate(typeof(Func)); - return () => f_float(); + { + var f = (Func)mInfo.CreateDelegate(typeof(Func)); + return () => f(); + } default: - UnityEngine.Debug.LogException(new Exception(string.Format("Method '{1}.{0}' is not supported.", mInfo.Name, mInfo.DeclaringType))); + { + var message = $"Method '{mInfo.DeclaringType}.{mInfo.Name} ({mInfo.ReturnType})' is not supported."; + Debug.LogException(new Exception(message)); return null; + } } } - - void ISerializationCallbackReceiver.OnBeforeSerialize() - { - } - - void ISerializationCallbackReceiver.OnAfterDeserialize() - { - var pInfo = GetPropertyInfo(m_Path); - _get = CreateFunc(pInfo?.GetMethod); - } } } diff --git a/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/StringBuilderExtensions.cs b/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/StringBuilderExtensions.cs index 10321aa..bf9e242 100644 --- a/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/StringBuilderExtensions.cs +++ b/Samples~/Performance Demo/NanoMonitor/Scripts/Utilities/StringBuilderExtensions.cs @@ -21,7 +21,8 @@ namespace Coffee.NanoMonitor return true; } - public static void AppendFormatNoAlloc(this StringBuilder sb, string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0) + public static void AppendFormatNoAlloc(this StringBuilder sb, string format, double arg0 = 0, double arg1 = 0, + double arg2 = 0, double arg3 = 0) { for (var i = 0; i < format.Length; i++) { @@ -56,7 +57,7 @@ namespace Coffee.NanoMonitor } } - internal static void AppendInteger(this StringBuilder sb, double number, int padding, int precision, int alignment) + private static void AppendInteger(this StringBuilder sb, double number, int padding, int alignment) { number = Math.Truncate(number); var sign = number < 0; @@ -68,8 +69,8 @@ namespace Coffee.NanoMonitor var n = Math.Truncate(number % 10); number /= 10; - sb.Append((char) (n + 48)); - } while (1 <= number || (sb.Length - startIndex) < padding); + sb.Append((char)(n + 48)); + } while (1 <= number || sb.Length - startIndex < padding); if (sign) { @@ -82,11 +83,12 @@ namespace Coffee.NanoMonitor sb.Alignment(alignment, startIndex, endIndex); } - internal static void AppendDouble(this StringBuilder sb, double number, int padding, int precision, int alignment) + private static void AppendDouble(this StringBuilder sb, double number, int padding, int precision, + int alignment) { var integer = Math.Truncate(number); var startIndex = sb.Length; - sb.AppendInteger(integer, padding, precision, 0); + sb.AppendInteger(integer, padding, 0); if (0 < precision) { @@ -96,8 +98,8 @@ namespace Coffee.NanoMonitor for (var p = 0; p < precision; p++) { number *= 10; - integer = (long) number; - sb.Append((char) (integer + 48)); + integer = (long)number; + sb.Append((char)(integer + 48)); number -= integer; number = Math.Round(number, precision); } @@ -106,20 +108,18 @@ namespace Coffee.NanoMonitor sb.Alignment(alignment, startIndex, sb.Length - 1); } - internal static void Reverse(this StringBuilder sb, int start, int end) + private static void Reverse(this StringBuilder sb, int start, int end) { while (start < end) { - var c = sb[start]; - sb[start] = sb[end]; - sb[end] = c; - + // swap + (sb[start], sb[end]) = (sb[end], sb[start]); start++; end--; } } - internal static void Alignment(this StringBuilder sb, int alignment, int start, int end) + private static void Alignment(this StringBuilder sb, int alignment, int start, int end) { if (alignment == 0) return; @@ -129,9 +129,8 @@ namespace Coffee.NanoMonitor sb.Append(' ', alignment - len); for (var i = 0; i < len; i++) { - var c = sb[end - i]; - sb[end - i] = sb[start + alignment - i - 1]; - sb[start + alignment - i - 1] = c; + // swap + (sb[end - i], sb[start + alignment - i - 1]) = (sb[start + alignment - i - 1], sb[end - i]); } } else if (alignment < 0 && len < -alignment) @@ -140,7 +139,8 @@ namespace Coffee.NanoMonitor } } - internal static int GetFormat(string format, int i, out int argIndex, out int padding, out int precision, out int alignment) + private static int GetFormat(string format, int i, out int argIndex, out int padding, out int precision, + out int alignment) { argIndex = -1; padding = 0; diff --git a/Samples~/Performance Demo/Scripts/UIParticle_PerformanceDemo.cs b/Samples~/Performance Demo/Scripts/UIParticle_PerformanceDemo.cs index 6d39bc8..ee9fc18 100644 --- a/Samples~/Performance Demo/Scripts/UIParticle_PerformanceDemo.cs +++ b/Samples~/Performance Demo/Scripts/UIParticle_PerformanceDemo.cs @@ -1,26 +1,35 @@ using UnityEngine; +using UnityEngine.Serialization; namespace Coffee.UIExtensions.Demo { public class UIParticle_PerformanceDemo : MonoBehaviour { - public GameObject copyOrigin; - public int copyCount; - public Canvas root; + [FormerlySerializedAs("copyOrigin")] + [SerializeField] + private GameObject m_CopyOrigin; + + [FormerlySerializedAs("copyCount")] + [SerializeField] + public int m_CopyCount; + + [FormerlySerializedAs("root")] + [SerializeField] + public Canvas m_RootCanvas; private void Start() { Application.targetFrameRate = 60; - if (copyOrigin) + if (m_CopyOrigin) { - copyOrigin.SetActive(false); + m_CopyOrigin.SetActive(false); - var parent = copyOrigin.transform.parent; - for (var i = 0; i < copyCount; i++) + var parent = m_CopyOrigin.transform.parent; + for (var i = 0; i < m_CopyCount; i++) { - var go = GameObject.Instantiate(copyOrigin, parent, false); - go.name = string.Format("{0} {1}", copyOrigin.name, i + 1); + var go = Instantiate(m_CopyOrigin, parent, false); + go.name = string.Format("{0} {1}", m_CopyOrigin.name, i + 1); go.hideFlags = HideFlags.DontSave; go.SetActive(true); @@ -28,32 +37,14 @@ namespace Coffee.UIExtensions.Demo } } - public void ChangeScreenSize() + public void UIParticle_Enable(bool flag) { - if (Screen.width == 400 && Screen.height == 720) - Screen.SetResolution(720, 720, false); - else if (Screen.width == 720 && Screen.height == 720) - Screen.SetResolution(720, 400, false); - else - Screen.SetResolution(400, 720, false); - } - - public void EnableAnimations(bool enabled) - { - foreach (var animator in FindObjectsOfType()) + foreach (var uip in m_RootCanvas.GetComponentsInChildren(true)) { - animator.enabled = enabled; + uip.enabled = flag; } - } - public void UIParticle_Enable(bool enabled) - { - - foreach (var uip in root.GetComponentsInChildren(true)) - { - uip.enabled = enabled; - } - if (!enabled) + if (!flag) { foreach (var ps in FindObjectsOfType()) { @@ -62,36 +53,23 @@ namespace Coffee.UIExtensions.Demo } } - public void UIParticle_MeshSharing(bool enabled) + public void UIParticle_MeshSharing(bool flag) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootCanvas.GetComponentsInChildren(true)) { - uip.meshSharing = enabled ? UIParticle.MeshSharing.Auto : UIParticle.MeshSharing.None; + uip.meshSharing = flag + ? UIParticle.MeshSharing.Auto + : UIParticle.MeshSharing.None; } } - public void UIParticle_RandomGroup(bool enabled) + public void UIParticle_RandomGroup(bool flag) { - foreach (var uip in root.GetComponentsInChildren(true)) + foreach (var uip in m_RootCanvas.GetComponentsInChildren(true)) { - uip.groupMaxId = enabled ? 4 : 0; - } - } - - public void UIParticle_Scale(float scale) - { - foreach (var uip in FindObjectsOfType()) - { - uip.scale = scale; - } - } - - public void ParticleSystem_WorldSpaseSimulation(bool enabled) - { - foreach (var ps in FindObjectsOfType()) - { - var main = ps.main; - main.simulationSpace = enabled ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local; + uip.groupMaxId = flag + ? 4 + : 0; } } @@ -102,34 +80,5 @@ namespace Coffee.UIExtensions.Demo ps.transform.localScale = new Vector3(scale, scale, scale); } } - - public void Canvas_WorldSpace(bool flag) - { - if (flag) - { - var canvas = FindObjectOfType(); - canvas.renderMode = RenderMode.ScreenSpaceCamera; - canvas.renderMode = RenderMode.WorldSpace; - canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0)); - } - } - - public void Canvas_CameraSpace(bool flag) - { - if (flag) - { - var canvas = FindObjectOfType(); - canvas.renderMode = RenderMode.ScreenSpaceCamera; - } - } - - public void Canvas_Overlay(bool flag) - { - if (flag) - { - var canvas = FindObjectOfType(); - canvas.renderMode = RenderMode.ScreenSpaceOverlay; - } - } } } diff --git a/Samples~/Performance Demo/UIParticle_PerformanceDemo.unity b/Samples~/Performance Demo/UIParticle_PerformanceDemo.unity index a4551cb..36ae222 100644 --- a/Samples~/Performance Demo/UIParticle_PerformanceDemo.unity +++ b/Samples~/Performance Demo/UIParticle_PerformanceDemo.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.12731704, g: 0.13414726, b: 0.1210787, a: 1} + m_IndirectSpecularColor: {r: 0.12731689, g: 0.13414702, b: 0.1210784, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -757,85 +757,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &455490117 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 455490120} - - component: {fileID: 455490119} - - component: {fileID: 455490118} - m_Layer: 5 - m_Name: Custom 1 - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &455490118 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 455490117} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b0e08c6080a2e4d8186f97c60518830f, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 0 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_FontData: - m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} - m_FontSize: 14 - m_FontStyle: 0 - m_BestFit: 0 - m_MinSize: 1 - m_MaxSize: 40 - m_Alignment: 0 - m_AlignByGeometry: 0 - m_RichText: 1 - m_HorizontalOverflow: 0 - m_VerticalOverflow: 0 - m_LineSpacing: 1 - m_Text: 'UIParticle: 888' - m_Mode: 0 - m_TextAnchor: 0 ---- !u!222 &455490119 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 455490117} - m_CullTransparentMesh: 0 ---- !u!224 &455490120 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 455490117} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1002673088} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 251.8711, y: -10} - m_SizeDelta: {x: 247.8711, y: 20} - m_Pivot: {x: 0, y: 0.5} --- !u!1 &496349153 GameObject: m_ObjectHideFlags: 0 @@ -972,12 +893,12 @@ PrefabInstance: - target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} propertyPath: m_AnchoredPosition.x - value: 240.00002 + value: 240 objectReference: {fileID: 0} - target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} propertyPath: m_AnchoredPosition.y - value: -179.99998 + value: -180 objectReference: {fileID: 0} - target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} @@ -1160,6 +1081,85 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 608849065} m_CullTransparentMesh: 0 +--- !u!1 &733597319 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 733597322} + - component: {fileID: 733597321} + - component: {fileID: 733597320} + m_Layer: 5 + m_Name: Custom 1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &733597320 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733597319} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b0e08c6080a2e4d8186f97c60518830f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Screen: 8888x8888 Time: 8888.88' + m_Mode: 0 + m_TextAnchor: 0 +--- !u!222 &733597321 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733597319} + m_CullTransparentMesh: 0 +--- !u!224 &733597322 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733597319} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1002673088} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 251.8711, y: -10} + m_SizeDelta: {x: 247.8711, y: 20} + m_Pivot: {x: 0, y: 0.5} --- !u!1 &879285143 GameObject: m_ObjectHideFlags: 0 @@ -1287,9 +1287,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3a595cf9cf93f4e0686f247a5e7e19ce, type: 3} m_Name: m_EditorClassIdentifier: - copyOrigin: {fileID: 1581241706} - copyCount: 266 - root: {fileID: 919637305} + m_CopyOrigin: {fileID: 1581241706} + m_CopyCount: 266 + m_RootCanvas: {fileID: 919637305} --- !u!4 &903906985 Transform: m_ObjectHideFlags: 0 @@ -1505,11 +1505,6 @@ PrefabInstance: propertyPath: m_SizeDelta.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 151878254403844079, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - propertyPath: m_TargetGraphic - value: - objectReference: {fileID: 1002673091} - target: {fileID: 323826319202443003, guid: 784696794bc6345bc80bf49623581c2e, type: 3} propertyPath: m_AnchorMin.y @@ -1530,11 +1525,6 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 1087632561348207336, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - propertyPath: m_TargetGraphic - value: - objectReference: {fileID: 1002673092} - target: {fileID: 1458366075964155596, guid: 784696794bc6345bc80bf49623581c2e, type: 3} propertyPath: m_AnchorMin.y @@ -1564,7 +1554,7 @@ PrefabInstance: type: 3} propertyPath: m_CustomMonitorItems.Array.data[1].m_Text value: - objectReference: {fileID: 455490118} + objectReference: {fileID: 733597320} - target: {fileID: 4567906826058368312, guid: 784696794bc6345bc80bf49623581c2e, type: 3} propertyPath: m_CustomMonitorItems.Array.data[1].m_Format @@ -1630,16 +1620,6 @@ PrefabInstance: propertyPath: m_SizeDelta.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 5526675317024915317, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - propertyPath: m_TargetGraphic - value: - objectReference: {fileID: 1002673089} - - target: {fileID: 5526675317129615258, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - propertyPath: m_TargetGraphic - value: - objectReference: {fileID: 1002673090} - target: {fileID: 5758968653464739090, guid: 784696794bc6345bc80bf49623581c2e, type: 3} propertyPath: m_SizeDelta.y @@ -1803,54 +1783,6 @@ RectTransform: type: 3} m_PrefabInstance: {fileID: 1002673087} m_PrefabAsset: {fileID: 0} ---- !u!114 &1002673089 stripped -MonoBehaviour: - m_CorrespondingSourceObject: {fileID: 5526675317024915314, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - m_PrefabInstance: {fileID: 1002673087} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b0e08c6080a2e4d8186f97c60518830f, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!114 &1002673090 stripped -MonoBehaviour: - m_CorrespondingSourceObject: {fileID: 5526675317129615259, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - m_PrefabInstance: {fileID: 1002673087} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b0e08c6080a2e4d8186f97c60518830f, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!114 &1002673091 stripped -MonoBehaviour: - m_CorrespondingSourceObject: {fileID: 6638879077379268485, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - m_PrefabInstance: {fileID: 1002673087} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b0e08c6080a2e4d8186f97c60518830f, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!114 &1002673092 stripped -MonoBehaviour: - m_CorrespondingSourceObject: {fileID: 6720252555115459274, guid: 784696794bc6345bc80bf49623581c2e, - type: 3} - m_PrefabInstance: {fileID: 1002673087} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b0e08c6080a2e4d8186f97c60518830f, type: 3} - m_Name: - m_EditorClassIdentifier: --- !u!1 &1023851109 GameObject: m_ObjectHideFlags: 0 @@ -3632,6 +3564,11 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 1924051224} m_Modifications: + - target: {fileID: 864895764861262036, guid: a4669dfbba654429bbcddf0c9b79fb8b, + type: 3} + propertyPath: m_IgnoreCanvasScaler + value: 1 + objectReference: {fileID: 0} - target: {fileID: 864895765507486433, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} propertyPath: m_AnchorMax.x @@ -3790,17 +3727,17 @@ PrefabInstance: - target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} propertyPath: m_LocalScale.x - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} propertyPath: m_LocalScale.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} propertyPath: m_LocalScale.z - value: 0 + value: 1 objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} diff --git a/Scripts/AnimatableProperty.cs b/Scripts/AnimatableProperty.cs index 4273db4..c4d0c08 100644 --- a/Scripts/AnimatableProperty.cs +++ b/Scripts/AnimatableProperty.cs @@ -1,8 +1,9 @@ -using UnityEngine; +using System; +using UnityEngine; namespace Coffee.UIExtensions { - [System.Serializable] + [Serializable] public class AnimatableProperty : ISerializationCallbackReceiver { public enum ShaderPropertyType @@ -11,11 +12,11 @@ namespace Coffee.UIExtensions Vector, Float, Range, - Texture, + Texture } - [SerializeField] string m_Name = ""; - [SerializeField] ShaderPropertyType m_Type = ShaderPropertyType.Vector; + [SerializeField] private string m_Name = ""; + [SerializeField] private ShaderPropertyType m_Type = ShaderPropertyType.Vector; public int id { get; private set; } public ShaderPropertyType type @@ -23,6 +24,15 @@ namespace Coffee.UIExtensions get { return m_Type; } } + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + id = Shader.PropertyToID(m_Name); + } + public void UpdateMaterialProperties(Material material, MaterialPropertyBlock mpb) { if (!material.HasProperty(id)) return; @@ -31,35 +41,38 @@ namespace Coffee.UIExtensions { case ShaderPropertyType.Color: var color = mpb.GetColor(id); - if (color != default(Color)) + if (color != default) + { material.SetColor(id, color); + } + break; case ShaderPropertyType.Vector: var vector = mpb.GetVector(id); - if (vector != default(Vector4)) + if (vector != default) + { material.SetVector(id, vector); + } + break; case ShaderPropertyType.Float: case ShaderPropertyType.Range: var value = mpb.GetFloat(id); - if (value != default(float)) + if (!Mathf.Approximately(value, 0)) + { material.SetFloat(id, value); + } + break; case ShaderPropertyType.Texture: var tex = mpb.GetTexture(id); if (tex != default(Texture)) + { material.SetTexture(id, tex); + } + break; } } - - public void OnBeforeSerialize() - { - } - - public void OnAfterDeserialize() - { - id = Shader.PropertyToID(m_Name); - } } } diff --git a/Scripts/Editor/AnimatablePropertyEditor.cs b/Scripts/Editor/AnimatablePropertyEditor.cs new file mode 100644 index 0000000..036e308 --- /dev/null +++ b/Scripts/Editor/AnimatablePropertyEditor.cs @@ -0,0 +1,143 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace Coffee.UIExtensions +{ + internal static class AnimatablePropertyEditor + { + private static readonly GUIContent s_ContentNothing = new GUIContent("Nothing"); + private static readonly List s_ActiveNames = new List(); + private static readonly StringBuilder s_Sb = new StringBuilder(); + private static readonly HashSet s_Names = new HashSet(); + + private static string CollectActiveNames(SerializedProperty sp, List result) + { + result.Clear(); + for (var i = 0; i < sp.arraySize; i++) + { + var spName = sp.GetArrayElementAtIndex(i).FindPropertyRelative("m_Name"); + if (spName == null) continue; + + result.Add(spName.stringValue); + } + + s_Sb.Length = 0; + if (result.Count == 0) + { + s_Sb.Append("Nothing"); + } + else + { + result.Aggregate(s_Sb, (a, b) => s_Sb.AppendFormat("{0}, ", b)); + s_Sb.Length -= 2; + } + + return s_Sb.ToString(); + } + + public static void Draw(SerializedProperty sp, Material[] mats) + { + bool isClicked; + using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false))) + { + var pos = EditorGUILayout.GetControlRect(true); + var label = new GUIContent(sp.displayName, sp.tooltip); + var rect = EditorGUI.PrefixLabel(pos, label); + var text = sp.hasMultipleDifferentValues + ? "-" + : CollectActiveNames(sp, s_ActiveNames); + isClicked = GUI.Button(rect, text, EditorStyles.popup); + } + + if (!isClicked) return; + + var gm = new GenericMenu(); + gm.AddItem(s_ContentNothing, s_ActiveNames.Count == 0, () => + { + sp.ClearArray(); + sp.serializedObject.ApplyModifiedProperties(); + }); + + if (!sp.hasMultipleDifferentValues) + { + for (var i = 0; i < sp.arraySize; i++) + { + var p = sp.GetArrayElementAtIndex(i); + var name = p.FindPropertyRelative("m_Name").stringValue; + var type = (AnimatableProperty.ShaderPropertyType)p.FindPropertyRelative("m_Type").intValue; + AddMenu(gm, sp, new ShaderProperty(name, type), false); + } + } + + s_Names.Clear(); + for (var j = 0; j < mats.Length; j++) + { + var mat = mats[j]; + if (!mat || !mat.shader) continue; + + for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++) + { + var name = ShaderUtil.GetPropertyName(mat.shader, i); + var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i); + if (s_Names.Contains(name)) continue; + s_Names.Add(name); + + AddMenu(gm, sp, new ShaderProperty(name, type), true); + + if (type != AnimatableProperty.ShaderPropertyType.Texture) continue; + + AddMenu(gm, sp, new ShaderProperty($"{name}_ST"), true); + AddMenu(gm, sp, new ShaderProperty($"{name}_HDR"), true); + AddMenu(gm, sp, new ShaderProperty($"{name}_TexelSize"), true); + } + } + + gm.ShowAsContext(); + } + + private static void AddMenu(GenericMenu menu, SerializedProperty sp, ShaderProperty prop, bool add) + { + if (add && s_ActiveNames.Contains(prop.name)) return; + + var label = new GUIContent($"{prop.name} ({prop.type})"); + menu.AddItem(label, s_ActiveNames.Contains(prop.name), () => + { + var index = s_ActiveNames.IndexOf(prop.name); + if (0 <= index) + { + sp.DeleteArrayElementAtIndex(index); + } + else + { + sp.InsertArrayElementAtIndex(sp.arraySize); + var p = sp.GetArrayElementAtIndex(sp.arraySize - 1); + p.FindPropertyRelative("m_Name").stringValue = prop.name; + p.FindPropertyRelative("m_Type").intValue = (int)prop.type; + } + + sp.serializedObject.ApplyModifiedProperties(); + }); + } + + private struct ShaderProperty + { + public readonly string name; + public readonly AnimatableProperty.ShaderPropertyType type; + + public ShaderProperty(string name) + { + this.name = name; + type = AnimatableProperty.ShaderPropertyType.Vector; + } + + public ShaderProperty(string name, AnimatableProperty.ShaderPropertyType type) + { + this.name = name; + this.type = type; + } + } + } +} diff --git a/Scripts/Editor/AnimatedPropertiesEditor.cs.meta b/Scripts/Editor/AnimatablePropertyEditor.cs.meta similarity index 100% rename from Scripts/Editor/AnimatedPropertiesEditor.cs.meta rename to Scripts/Editor/AnimatablePropertyEditor.cs.meta diff --git a/Scripts/Editor/AnimatedPropertiesEditor.cs b/Scripts/Editor/AnimatedPropertiesEditor.cs deleted file mode 100644 index fab0e83..0000000 --- a/Scripts/Editor/AnimatedPropertiesEditor.cs +++ /dev/null @@ -1,123 +0,0 @@ -using UnityEditor; -using UnityEngine; -using System.Collections.Generic; -using System.Linq; -using ShaderPropertyType = Coffee.UIExtensions.AnimatableProperty.ShaderPropertyType; - -namespace Coffee.UIExtensions -{ - internal class AnimatedPropertiesEditor - { - private static readonly List s_ActiveNames = new List(); - private static readonly System.Text.StringBuilder s_Sb = new System.Text.StringBuilder(); - private static readonly HashSet s_Names = new HashSet(); - - private string _name; - private ShaderPropertyType _type; - - static string CollectActiveNames(SerializedProperty sp, List result) - { - result.Clear(); - for (var i = 0; i < sp.arraySize; i++) - { - var spName = sp.GetArrayElementAtIndex(i).FindPropertyRelative("m_Name"); - if (spName == null) continue; - - result.Add(spName.stringValue); - } - - s_Sb.Length = 0; - if (result.Count == 0) - { - s_Sb.Append("Nothing"); - } - else - { - result.Aggregate(s_Sb, (a, b) => s_Sb.AppendFormat("{0}, ", b)); - s_Sb.Length -= 2; - } - - return s_Sb.ToString(); - } - - public static void DrawAnimatableProperties(SerializedProperty sp, Material[] mats) - { - bool isClicked; - using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false))) - { - var r = EditorGUI.PrefixLabel(EditorGUILayout.GetControlRect(true), new GUIContent(sp.displayName, sp.tooltip)); - var text = sp.hasMultipleDifferentValues ? "-" : CollectActiveNames(sp, s_ActiveNames); - isClicked = GUI.Button(r, text, EditorStyles.popup); - } - - if (!isClicked) return; - - var gm = new GenericMenu(); - gm.AddItem(new GUIContent("Nothing"), s_ActiveNames.Count == 0, () => - { - sp.ClearArray(); - sp.serializedObject.ApplyModifiedProperties(); - }); - - - if (!sp.hasMultipleDifferentValues) - { - for (var i = 0; i < sp.arraySize; i++) - { - var p = sp.GetArrayElementAtIndex(i); - var name = p.FindPropertyRelative("m_Name").stringValue; - var type = (ShaderPropertyType) p.FindPropertyRelative("m_Type").intValue; - AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = name, _type = type}, false); - } - } - - s_Names.Clear(); - foreach (var mat in mats) - { - if (!mat || !mat.shader) continue; - - for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++) - { - var pName = ShaderUtil.GetPropertyName(mat.shader, i); - var type = (ShaderPropertyType) ShaderUtil.GetPropertyType(mat.shader, i); - var name = string.Format("{0} ({1})", pName, type); - if (s_Names.Contains(name)) continue; - s_Names.Add(name); - - AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName, _type = type}, true); - - if (type != ShaderPropertyType.Texture) continue; - - AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_ST", _type = ShaderPropertyType.Vector}, true); - AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_HDR", _type = ShaderPropertyType.Vector}, true); - AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_TexelSize", _type = ShaderPropertyType.Vector}, true); - } - } - - gm.ShowAsContext(); - } - - private static void AddMenu(GenericMenu menu, SerializedProperty sp, AnimatedPropertiesEditor property, bool add) - { - if (add && s_ActiveNames.Contains(property._name)) return; - - menu.AddItem(new GUIContent(string.Format("{0} ({1})", property._name, property._type)), s_ActiveNames.Contains(property._name), () => - { - var index = s_ActiveNames.IndexOf(property._name); - if (0 <= index) - { - sp.DeleteArrayElementAtIndex(index); - } - else - { - sp.InsertArrayElementAtIndex(sp.arraySize); - var p = sp.GetArrayElementAtIndex(sp.arraySize - 1); - p.FindPropertyRelative("m_Name").stringValue = property._name; - p.FindPropertyRelative("m_Type").intValue = (int) property._type; - } - - sp.serializedObject.ApplyModifiedProperties(); - }); - } - } -} diff --git a/Scripts/Editor/ImportSampleMenu.cs b/Scripts/Editor/ImportSampleMenu.cs index c8011e3..1920c6c 100644 --- a/Scripts/Editor/ImportSampleMenu.cs +++ b/Scripts/Editor/ImportSampleMenu.cs @@ -32,11 +32,16 @@ namespace Coffee.UIExtensions private static void ImportSample(string jsonGuid, string sampleName) { var jsonPath = AssetDatabase.GUIDToAssetPath(jsonGuid); - var packageRoot = Path.GetDirectoryName(jsonPath).Replace('\\', '/'); + if (string.IsNullOrEmpty(jsonPath)) return; + + var jsonDir = Path.GetDirectoryName(jsonPath); + if (string.IsNullOrEmpty(jsonDir)) return; + + var packageRoot = jsonDir.Replace('\\', '/'); var json = File.ReadAllText(jsonPath); var version = Regex.Match(json, "\"version\"\\s*:\\s*\"([^\"]+)\"").Groups[1].Value; - var src = string.Format("{0}/Samples~/{1}", packageRoot, sampleName); - var dst = string.Format("Assets/Samples/{0}/{1}/{2}", k_DisplayName, version, sampleName); + var src = $"{packageRoot}/Samples~/{sampleName}"; + var dst = $"Assets/Samples/{k_DisplayName}/{version}/{sampleName}"; var previousPath = GetPreviousSamplePath(k_DisplayName, sampleName); // Remove the previous sample directory. @@ -46,33 +51,45 @@ namespace Coffee.UIExtensions + previousPath + "\n\nIt will be deleted when you update. Are you sure you want to continue?"; if (!EditorUtility.DisplayDialog("Sample Importer", msg, "OK", "Cancel")) + { return; + } FileUtil.DeleteFileOrDirectory(previousPath); var metaFile = previousPath + ".meta"; if (File.Exists(metaFile)) + { FileUtil.DeleteFileOrDirectory(metaFile); + } } if (!Directory.Exists(dst)) + { FileUtil.DeleteFileOrDirectory(dst); + } var dstDir = Path.GetDirectoryName(dst); - if (!Directory.Exists(dstDir)) + if (!string.IsNullOrEmpty(dstDir) && !Directory.Exists(dstDir)) + { Directory.CreateDirectory(dstDir); + } if (Directory.Exists(src)) + { FileUtil.CopyFileOrDirectory(src, dst); + } else + { throw new DirectoryNotFoundException(src); + } AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive); } private static string GetPreviousSamplePath(string displayName, string sampleName) { - var sampleRoot = string.Format("Assets/Samples/{0}", displayName); + var sampleRoot = $"Assets/Samples/{displayName}"; var sampleRootInfo = new DirectoryInfo(sampleRoot); if (!sampleRootInfo.Exists) return null; diff --git a/Scripts/Editor/UIParticleEditor.cs b/Scripts/Editor/UIParticleEditor.cs index 7a2c41a..d179333 100644 --- a/Scripts/Editor/UIParticleEditor.cs +++ b/Scripts/Editor/UIParticleEditor.cs @@ -1,19 +1,22 @@ -#if UNITY_2019_3_11 || UNITY_2019_3_12 || UNITY_2019_3_13 || UNITY_2019_3_14 || UNITY_2019_3_15 || UNITY_2019_4_OR_NEWER -#define SERIALIZE_FIELD_MASKABLE -#endif -using UnityEditor; -using UnityEditor.UI; -using UnityEngine; -using System.Collections.Generic; -using System.Linq; -using UnityEditorInternal; -using UnityEngine.UI; -using System; #if UNITY_2021_2_OR_NEWER using UnityEditor.Overlays; #else using System.Reflection; #endif +#if UNITY_2021_2_OR_NEWER +using UnityEditor.SceneManagement; +#elif UNITY_2018_3_OR_NEWER +using UnityEditor.Experimental.SceneManagement; +#endif +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.UI; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.UI; +using Object = UnityEngine.Object; namespace Coffee.UIExtensions { @@ -23,7 +26,10 @@ namespace Coffee.UIExtensions { #if UNITY_2021_2_OR_NEWER #if UNITY_2022_1_OR_NEWER - [Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true, defaultDockPosition = DockPosition.Bottom, defaultDockZone = DockZone.Floating, defaultLayout = Layout.Panel)] + [Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true, + defaultDockPosition = DockPosition.Bottom, + defaultDockZone = DockZone.Floating, + defaultLayout = Layout.Panel)] #else [Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true)] #endif @@ -52,27 +58,28 @@ namespace Coffee.UIExtensions private static readonly GUIContent s_Content3D = new GUIContent("3D"); private static readonly GUIContent s_ContentRandom = new GUIContent("Random"); private static readonly GUIContent s_ContentScale = new GUIContent("Scale"); - private static readonly GUIContent s_ContentAutoScaling = new GUIContent("Auto Scaling", "Transform.lossyScale (=world scale) is automatically set to (1, 1, 1), to prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem."); + + private static readonly GUIContent s_ContentAutoScaling = new GUIContent("Auto Scaling", + "Transform.lossyScale (=world scale) is automatically set to (1, 1, 1)," + + " to prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem."); + private static SerializedObject s_SerializedObject; + private static bool s_XYZMode; -#if !SERIALIZE_FIELD_MASKABLE - private SerializedProperty m_Maskable; -#endif - private SerializedProperty m_Scale3D; - private SerializedProperty m_AnimatableProperties; - private SerializedProperty m_MeshSharing; - private SerializedProperty m_GroupId; - private SerializedProperty m_GroupMaxId; - private SerializedProperty m_AbsoluteMode; - private SerializedProperty m_IgnoreCanvasScaler; - - + private SerializedProperty _maskable; + private SerializedProperty _scale3D; + private SerializedProperty _animatableProperties; + private SerializedProperty _meshSharing; + private SerializedProperty _groupId; + private SerializedProperty _groupMaxId; + private SerializedProperty _absoluteMode; + private SerializedProperty _ignoreCanvasScaler; private ReorderableList _ro; - static private bool _xyzMode; private bool _showMax; private static readonly HashSet s_Shaders = new HashSet(); private static readonly List s_Streams = new List(); + private static readonly List s_MaskablePropertyNames = new List { "_Stencil", @@ -80,21 +87,20 @@ namespace Coffee.UIExtensions "_StencilOp", "_StencilWriteMask", "_StencilReadMask", - "_ColorMask", + "_ColorMask" }; - [InitializeOnLoadMethod] - static void Init() + private static void Init() { #if !UNITY_2021_2_OR_NEWER var miSceneViewOverlayWindow = Type.GetType("UnityEditor.SceneViewOverlay, UnityEditor") - .GetMethods(BindingFlags.Public | BindingFlags.Static) + ?.GetMethods(BindingFlags.Public | BindingFlags.Static) .First(x => x.Name == "Window" && 5 <= x.GetParameters().Length); - var windowFunction = (Action)WindowFunction; + var windowFunction = (Action)WindowFunction; var windowFunctionType = Type.GetType("UnityEditor.SceneViewOverlay+WindowFunction, UnityEditor"); var windowFunctionDelegate = Delegate.CreateDelegate(windowFunctionType, windowFunction.Method); - var windowTitle = new GUIContent(ObjectNames.NicifyVariableName(typeof(UIParticle).Name)); + var windowTitle = new GUIContent(ObjectNames.NicifyVariableName(nameof(UIParticle))); #if UNITY_2019_2_OR_NEWER //public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option, EditorWindow window = null) var sceneViewArgs = new object[] { windowTitle, windowFunctionDelegate, 599, null, 2, null }; @@ -104,7 +110,7 @@ namespace Coffee.UIExtensions #endif #if UNITY_2019_1_OR_NEWER - SceneView.duringSceneGui += _ => { if (s_SerializedObject != null) miSceneViewOverlayWindow.Invoke(null, sceneViewArgs); }; + SceneView.duringSceneGui += _ => #else SceneView.onSceneGUIDelegate += _ => #endif @@ -116,25 +122,21 @@ namespace Coffee.UIExtensions }; #endif - Func createSerializeObject = () => + SerializedObject CreateSerializeObject() { - var uiParticles = Selection.gameObjects - .Select(x => x.GetComponent()) - .Where(x => x) - .Select(x => x.GetComponentInParent()) - .Where(x => x && x.canvas) - .Concat( - Selection.gameObjects - .Select(x => x.GetComponent()) - .Where(x => x && x.canvas) - ) - .Distinct() - .ToArray(); + var uiParticles = Selection.gameObjects.Select(x => x.GetComponent()) + .Where(x => x) + .Select(x => x.GetComponentInParent()) + .Where(x => x && x.canvas) + .Concat(Selection.gameObjects.Select(x => x.GetComponent()) + .Where(x => x && x.canvas)) + .Distinct() + .ToArray(); return 0 < uiParticles.Length ? new SerializedObject(uiParticles) : null; - }; + } - s_SerializedObject = createSerializeObject(); - Selection.selectionChanged += () => s_SerializedObject = createSerializeObject(); + s_SerializedObject = CreateSerializeObject(); + Selection.selectionChanged += () => s_SerializedObject = CreateSerializeObject(); } //################################ @@ -147,64 +149,71 @@ namespace Coffee.UIExtensions { base.OnEnable(); - m_Maskable = serializedObject.FindProperty("m_Maskable"); - m_Scale3D = serializedObject.FindProperty("m_Scale3D"); - m_AnimatableProperties = serializedObject.FindProperty("m_AnimatableProperties"); - m_MeshSharing = serializedObject.FindProperty("m_MeshSharing"); - m_GroupId = serializedObject.FindProperty("m_GroupId"); - m_GroupMaxId = serializedObject.FindProperty("m_GroupMaxId"); - m_AbsoluteMode = serializedObject.FindProperty("m_AbsoluteMode"); - m_IgnoreCanvasScaler = serializedObject.FindProperty("m_IgnoreCanvasScaler"); + _maskable = serializedObject.FindProperty("m_Maskable"); + _scale3D = serializedObject.FindProperty("m_Scale3D"); + _animatableProperties = serializedObject.FindProperty("m_AnimatableProperties"); + _meshSharing = serializedObject.FindProperty("m_MeshSharing"); + _groupId = serializedObject.FindProperty("m_GroupId"); + _groupMaxId = serializedObject.FindProperty("m_GroupMaxId"); + _absoluteMode = serializedObject.FindProperty("m_AbsoluteMode"); + _ignoreCanvasScaler = serializedObject.FindProperty("m_IgnoreCanvasScaler"); var sp = serializedObject.FindProperty("m_Particles"); - _ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true); - _ro.elementHeight = (EditorGUIUtility.singleLineHeight * 3) + 4; - _ro.elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2); - _ro.drawElementCallback = (rect, index, _, __) => + _ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true) { - EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues); - rect.y += 1; - rect.height = EditorGUIUtility.singleLineHeight; - var p = sp.GetArrayElementAtIndex(index); - EditorGUI.ObjectField(rect, p, GUIContent.none); - rect.x += 15; - rect.width -= 15; - var ps = p.objectReferenceValue as ParticleSystem; - var materials = ps - ? new SerializedObject(ps.GetComponent()).FindProperty("m_Materials") - : null; - rect.y += rect.height + 1; - MaterialField(rect, s_ContentMaterial, materials, 0); - rect.y += rect.height + 1; - MaterialField(rect, s_ContentTrailMaterial, materials, 1); - EditorGUI.EndDisabledGroup(); - if (materials != null && materials.serializedObject.hasModifiedProperties) + elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4, + elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2), + drawElementCallback = (rect, index, _, __) => { - materials.serializedObject.ApplyModifiedProperties(); - } - }; - _ro.drawHeaderCallback = rect => - { -#if !UNITY_2019_3_OR_NEWER - rect.y -= 1; -#endif - EditorGUI.LabelField(new Rect(rect.x, rect.y, 150, rect.height), s_ContentRenderingOrder); - - if (GUI.Button(new Rect(rect.width - 35, rect.y, 60, rect.height), s_ContentRefresh, EditorStyles.miniButton)) - { - foreach (UIParticle t in targets) + EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues); + rect.y += 1; + rect.height = EditorGUIUtility.singleLineHeight; + var p = sp.GetArrayElementAtIndex(index); + EditorGUI.ObjectField(rect, p, GUIContent.none); + rect.x += 15; + rect.width -= 15; + var ps = p.objectReferenceValue as ParticleSystem; + var materials = ps + ? new SerializedObject(ps.GetComponent()).FindProperty("m_Materials") + : null; + rect.y += rect.height + 1; + MaterialField(rect, s_ContentMaterial, materials, 0); + rect.y += rect.height + 1; + MaterialField(rect, s_ContentTrailMaterial, materials, 1); + EditorGUI.EndDisabledGroup(); + if (materials != null && materials.serializedObject.hasModifiedProperties) { - t.RefreshParticles(); - EditorUtility.SetDirty(t); + materials.serializedObject.ApplyModifiedProperties(); + } + }, + drawHeaderCallback = rect => + { +#if !UNITY_2019_3_OR_NEWER + rect.y -= 1; +#endif + var pos = new Rect(rect.x, rect.y, 150, rect.height); + EditorGUI.LabelField(pos, s_ContentRenderingOrder); + + pos = new Rect(rect.width - 35, rect.y, 60, rect.height); + if (GUI.Button(pos, s_ContentRefresh, EditorStyles.miniButton)) + { + foreach (var uip in targets.OfType()) + { + uip.RefreshParticles(); + EditorUtility.SetDirty(uip); + } } } }; // On select UIParticle, refresh particles. - foreach (UIParticle t in targets) + if (!Application.isPlaying) { - if (Application.isPlaying || PrefabUtility.GetPrefabAssetType(t) != PrefabAssetType.NotAPrefab) continue; - t.RefreshParticles(t.particles); + foreach (var uip in targets.OfType()) + { + if (PrefabUtility.GetPrefabAssetType(uip) != PrefabAssetType.NotAPrefab) continue; + uip.RefreshParticles(uip.particles); + } } } @@ -233,11 +242,11 @@ namespace Coffee.UIExtensions serializedObject.Update(); // Maskable - EditorGUILayout.PropertyField(m_Maskable); + EditorGUILayout.PropertyField(_maskable); // Scale - EditorGUI.BeginDisabledGroup(!m_MeshSharing.hasMultipleDifferentValues && m_MeshSharing.intValue == 4); - _xyzMode = DrawFloatOrVector3Field(m_Scale3D, _xyzMode); + EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4); + s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode); EditorGUI.EndDisabledGroup(); // AnimatableProperties @@ -247,12 +256,11 @@ namespace Coffee.UIExtensions .Where(x => x) .ToArray(); - // Animated properties - AnimatedPropertiesEditor.DrawAnimatableProperties(m_AnimatableProperties, mats); + AnimatablePropertyEditor.Draw(_animatableProperties, mats); // Mesh sharing EditorGUI.BeginChangeCheck(); - _showMax = DrawMeshSharing(m_MeshSharing, m_GroupId, m_GroupMaxId, _showMax); + _showMax = DrawMeshSharing(_meshSharing, _groupId, _groupMaxId, _showMax); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); @@ -263,10 +271,10 @@ namespace Coffee.UIExtensions } // Absolute Mode - EditorGUILayout.PropertyField(m_AbsoluteMode); + EditorGUILayout.PropertyField(_absoluteMode); // Auto Scaling - DrawInversedToggle(m_IgnoreCanvasScaler, s_ContentAutoScaling, () => + DrawInversedToggle(_ignoreCanvasScaler, s_ContentAutoScaling, () => { foreach (var uip in targets.OfType()) { @@ -292,6 +300,7 @@ namespace Coffee.UIExtensions } // Does the shader support UI masks? + if (current.maskable && current.GetComponentInParent()) { foreach (var mat in current.materials) @@ -304,15 +313,19 @@ namespace Coffee.UIExtensions { if (mat.HasProperty(propName)) continue; - EditorGUILayout.HelpBox(string.Format("Shader '{0}' doesn't have '{1}' property. This graphic cannot be masked.", shader.name, propName), MessageType.Warning); + EditorGUILayout.HelpBox( + $"Shader '{shader.name}' doesn't have '{propName}' property. This graphic cannot be masked.", + MessageType.Warning); break; } } } + s_Shaders.Clear(); // UIParticle for trail should be removed. - if (FixButton(current.m_IsTrail, "This UIParticle component should be removed. The UIParticle for trails is no longer needed.")) + var label = "This UIParticle component should be removed. The UIParticle for trails is no longer needed."; + if (FixButton(current.m_IsTrail, label)) { DestroyUIParticle(current); } @@ -328,7 +341,9 @@ namespace Coffee.UIExtensions { var so = new SerializedObject(allPsRenderers); var sp = so.FindProperty("m_ApplyActiveColorSpace"); - if (FixButton(sp.boolValue || sp.hasMultipleDifferentValues, "When using linear color space, the particle colors are not output correctly.\nTo fix, set 'Apply Active Color Space' in renderer module to false.")) + label = "When using linear color space, the particle colors are not output correctly.\n" + + "To fix, set 'Apply Active Color Space' in renderer module to false."; + if (FixButton(sp.boolValue || sp.hasMultipleDifferentValues, label)) { sp.boolValue = false; so.ApplyModifiedProperties(); @@ -343,8 +358,13 @@ namespace Coffee.UIExtensions if (2 < s_Streams.Select(GetUsedComponentCount).Sum()) { - EditorGUILayout.HelpBox(string.Format("ParticleSystem '{0}' uses 'TEXCOORD*.zw' components as custom vertex stream.\nUIParticle does not support it (See README.md).", psr.name), MessageType.Warning); + EditorGUILayout.HelpBox( + $"ParticleSystem '{psr.name}' uses 'TEXCOORD*.zw' components as custom vertex stream.\n" + + "UIParticle does not support it (See README.md).", + MessageType.Warning); } + + s_Streams.Clear(); } } } @@ -404,10 +424,12 @@ namespace Coffee.UIExtensions case ParticleSystemVertexStream.Custom2XYZW: return 4; } + return 3; } - private static bool DrawMeshSharing(SerializedProperty spMeshSharing, SerializedProperty spGroupId, SerializedProperty spGroupMaxId, bool showMax) + private static bool DrawMeshSharing(SerializedProperty spMeshSharing, SerializedProperty spGroupId, + SerializedProperty spGroupMaxId, bool showMax) { showMax |= spGroupId.intValue != spGroupMaxId.intValue || spGroupId.hasMultipleDifferentValues || @@ -419,7 +441,10 @@ namespace Coffee.UIExtensions EditorGUI.BeginChangeCheck(); showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60)); if (EditorGUI.EndChangeCheck() && !showMax) + { spGroupMaxId.intValue = spGroupId.intValue; + } + EditorGUILayout.EndHorizontal(); EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0); @@ -432,23 +457,25 @@ namespace Coffee.UIExtensions else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4) { EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.ObjectField("Primary", UIParticleUpdater.GetPrimary(spGroupId.intValue), typeof(UIParticle), false); + var obj = UIParticleUpdater.GetPrimary(spGroupId.intValue); + EditorGUILayout.ObjectField("Primary", obj, typeof(UIParticle), false); EditorGUI.EndDisabledGroup(); } + EditorGUI.indentLevel--; EditorGUI.EndDisabledGroup(); return showMax; } - private static void DrawInversedToggle(SerializedProperty inversedProperty, GUIContent label, Action onChanged) + private static void DrawInversedToggle(SerializedProperty sp, GUIContent label, Action onChanged) { - EditorGUI.showMixedValue = inversedProperty.hasMultipleDifferentValues; - var autoScaling = !inversedProperty.boolValue; + EditorGUI.showMixedValue = sp.hasMultipleDifferentValues; + var autoScaling = !sp.boolValue; EditorGUI.BeginChangeCheck(); if (autoScaling != EditorGUILayout.Toggle(label, autoScaling)) { - inversedProperty.boolValue = autoScaling; + sp.boolValue = autoScaling; } if (EditorGUI.EndChangeCheck()) @@ -459,7 +486,7 @@ namespace Coffee.UIExtensions EditorGUI.showMixedValue = false; } - private static void WindowFunction(UnityEngine.Object target, SceneView sceneView) + private static void WindowFunction(Object target, SceneView sceneView) { try { @@ -472,48 +499,45 @@ namespace Coffee.UIExtensions var labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 100; EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_Enabled")); - _xyzMode = DrawFloatOrVector3Field(s_SerializedObject.FindProperty("m_Scale3D"), _xyzMode); + s_XYZMode = DrawFloatOrVector3Field(s_SerializedObject.FindProperty("m_Scale3D"), s_XYZMode); EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_AbsoluteMode")); - DrawInversedToggle(s_SerializedObject.FindProperty("m_IgnoreCanvasScaler"), s_ContentAutoScaling, + DrawInversedToggle(s_SerializedObject.FindProperty("m_IgnoreCanvasScaler"), + s_ContentAutoScaling, () => { - foreach (var uip in s_SerializedObject.targetObjects.OfType()) - { - if (uip && !uip.autoScaling) - { - uip.transform.localScale = Vector3.one; - } - } + s_SerializedObject.targetObjects + .OfType() + .Where(x => x && !x.autoScaling) + .ToList() + .ForEach(x => x.transform.localScale = Vector3.one); }); EditorGUIUtility.labelWidth = labelWidth; } + s_SerializedObject.ApplyModifiedProperties(); } catch { + // ignored } } private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false) { - if (!p || ignoreCurrent && target == p) return; + if (!p || (ignoreCurrent && target == p)) return; var cr = p.canvasRenderer; DestroyImmediate(p); DestroyImmediate(cr); -#if UNITY_2021_2_OR_NEWER - var stage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); -#elif UNITY_2018_3_OR_NEWER - var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); -#endif #if UNITY_2018_3_OR_NEWER + var stage = PrefabStageUtility.GetCurrentPrefabStage(); if (stage != null && stage.scene.isLoaded) { #if UNITY_2020_1_OR_NEWER string prefabAssetPath = stage.assetPath; #else - string prefabAssetPath = stage.prefabAssetPath; + var prefabAssetPath = stage.prefabAssetPath; #endif PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath); } @@ -562,7 +586,10 @@ namespace Coffee.UIExtensions EditorGUI.BeginChangeCheck(); showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30)); if (EditorGUI.EndChangeCheck() && !showXyz) + { z.floatValue = y.floatValue = x.floatValue; + } + EditorGUILayout.EndHorizontal(); return showXyz; diff --git a/Scripts/ModifiedMaterial.cs b/Scripts/ModifiedMaterial.cs index e31df9c..ecc4e30 100644 --- a/Scripts/ModifiedMaterial.cs +++ b/Scripts/ModifiedMaterial.cs @@ -10,7 +10,7 @@ namespace Coffee.UIParticleExtensions public static Material Add(Material baseMat, Texture texture, int id) { MatEntry e; - for (var i = 0; i < s_Entries.Count; ++i) + for (var i = 0; i < s_Entries.Count; i++) { e = s_Entries[i]; if (e.baseMat != baseMat || e.texture != texture || e.id != id) continue; @@ -18,15 +18,19 @@ namespace Coffee.UIParticleExtensions return e.customMat; } - e = new MatEntry(); - e.count = 1; - e.baseMat = baseMat; - e.texture = texture; - e.id = id; - e.customMat = new Material(baseMat); - e.customMat.hideFlags = HideFlags.HideAndDontSave; - if (texture) - e.customMat.mainTexture = texture; + e = new MatEntry + { + count = 1, + baseMat = baseMat, + texture = texture, + id = id, + customMat = new Material(baseMat) + { + name = $"{baseMat.name}_{id}", + hideFlags = HideFlags.HideAndDontSave, + mainTexture = texture ? texture : null + } + }; s_Entries.Add(e); //Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id); return e.customMat; @@ -43,7 +47,8 @@ namespace Coffee.UIParticleExtensions if (--e.count == 0) { //Debug.LogFormat(">>>> ModifiedMaterial.Remove -> count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count - 1, e.customMat, e.texture, e.id); - DestroyImmediate(e.customMat); + Misc.DestroyImmediate(e.customMat); + e.customMat = null; e.baseMat = null; e.texture = null; s_Entries.RemoveAt(i); @@ -53,22 +58,13 @@ namespace Coffee.UIParticleExtensions } } - private static void DestroyImmediate(Object obj) - { - if (!obj) return; - if (Application.isEditor) - Object.DestroyImmediate(obj); - else - Object.Destroy(obj); - } - private class MatEntry { public Material baseMat; - public Material customMat; public int count; - public Texture texture; + public Material customMat; public int id; + public Texture texture; } } } diff --git a/Scripts/UIParticle.cs b/Scripts/UIParticle.cs index 1cdd2d6..b522214 100644 --- a/Scripts/UIParticle.cs +++ b/Scripts/UIParticle.cs @@ -2,7 +2,6 @@ #define SERIALIZE_FIELD_MASKABLE #endif using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using Coffee.UIParticleExtensions; using UnityEngine; @@ -28,16 +27,19 @@ namespace Coffee.UIExtensions Auto, Primary, PrimarySimulator, - Replica, + Replica } - [HideInInspector][SerializeField] internal bool m_IsTrail = false; + [HideInInspector] + [SerializeField] + internal bool m_IsTrail; [Tooltip("Particle effect scale")] [SerializeField] private Vector3 m_Scale3D = new Vector3(10, 10, 10); - [Tooltip("Animatable material properties. If you want to change the material properties of the ParticleSystem in Animation, enable it.")] + [Tooltip("Animatable material properties.\n" + + "If you want to change the material properties of the ParticleSystem in Animation, enable it.")] [SerializeField] internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0]; @@ -45,40 +47,49 @@ namespace Coffee.UIExtensions [SerializeField] private List m_Particles = new List(); - [Tooltip("Mesh sharing.None: disable mesh sharing.\nAuto: automatically select Primary/Replica.\nPrimary: provides particle simulation results to the same group.\nPrimary Simulator: Primary, but do not render the particle (simulation only).\nReplica: render simulation results provided by the primary.")] + [Tooltip("Mesh sharing.\n" + + "None: disable mesh sharing.\n" + + "Auto: automatically select Primary/Replica.\n" + + "Primary: provides particle simulation results to the same group.\n" + + "Primary Simulator: Primary, but do not render the particle (simulation only).\n" + + "Replica: render simulation results provided by the primary.")] [SerializeField] private MeshSharing m_MeshSharing = MeshSharing.None; - [Tooltip("Mesh sharing group ID. If non-zero is specified, particle simulation results are shared within the group.")] + [Tooltip("Mesh sharing group ID.\n" + + "If non-zero is specified, particle simulation results are shared within the group.")] [SerializeField] - private int m_GroupId = 0; + private int m_GroupId; [SerializeField] - private int m_GroupMaxId = 0; + private int m_GroupMaxId; [SerializeField] - [Tooltip("The particles will be emitted at the ParticleSystem position.\nMove the UIParticle/ParticleSystem to move the particle.")] + [Tooltip("Particle position mode.\n" + + "Absolute Mode: The particles will be emitted from the ParticleSystem position.\n" + + " Move the UIParticle or ParticleSystem to move the particle.\n" + + "Relative Mode: The particles will be emitted from the scaled ParticleSystem position.\n" + + " Move the UIParticle to move the particle.")] private bool m_AbsoluteMode = false; /// /// This field uses the inverted value as "AutoScaling". /// - [SerializeField] [FormerlySerializedAs("m_IgnoreParent")] - private bool m_IgnoreCanvasScaler = false; - - private List m_Renderers = new List(); + [SerializeField] + private bool m_IgnoreCanvasScaler; #if !SERIALIZE_FIELD_MASKABLE - [SerializeField] private bool m_Maskable = true; + [SerializeField] + private bool m_Maskable = true; #endif - - private DrivenRectTransformTracker _tracker; - private Camera _orthoCamera; + private readonly List _renderers = new List(); private int _groupId; + private Camera _orthoCamera; + private DrivenRectTransformTracker _tracker; /// - /// Should this graphic be considered a target for raycasting? + /// Should this graphic be considered a target for ray-casting? /// public override bool raycastTarget { @@ -87,7 +98,8 @@ namespace Coffee.UIExtensions } /// - /// Mesh sharing.None: disable mesh sharing. + /// Mesh sharing. + /// None: disable mesh sharing. /// Auto: automatically select Primary/Replica. /// Primary: provides particle simulation results to the same group. /// Primary Simulator: Primary, but do not render the particle (simulation only). @@ -100,7 +112,8 @@ namespace Coffee.UIExtensions } /// - /// Mesh sharing group ID. If non-zero is specified, particle simulation results are shared within the group. + /// Mesh sharing group ID. + /// If non-zero is specified, particle simulation results are shared within the group. /// public int groupId { @@ -110,7 +123,9 @@ namespace Coffee.UIExtensions if (m_GroupId == value) return; m_GroupId = value; if (m_GroupId != m_GroupMaxId) + { ResetGroupId(); + } } } @@ -126,9 +141,11 @@ namespace Coffee.UIExtensions } /// - /// Absolute particle position mode. - /// The particles will be emitted at the ParticleSystem position. - /// Move the UIParticle/ParticleSystem to move the particle. + /// Particle position mode. + /// Absolute Mode: The particles will be emitted from the ParticleSystem position. + /// Move the UIParticle or ParticleSystem to move the particle. + /// Relative Mode: The particles will be emitted from the scaled ParticleSystem position. + /// Move the UIParticle to move the particle. /// public bool absoluteMode { @@ -136,6 +153,11 @@ namespace Coffee.UIExtensions set { m_AbsoluteMode = value; } } + /// + /// Transform.lossyScale (=world scale) is automatically set to (1, 1, 1). + /// It prevents the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem. + /// Note: This option works in reverse of ’IgnoreCanvasScaler’ option in v3.x. + /// public bool autoScaling { get { return !m_IgnoreCanvasScaler; } @@ -154,17 +176,33 @@ namespace Coffee.UIExtensions internal bool isPrimary { - get { return m_MeshSharing == MeshSharing.Primary || m_MeshSharing == MeshSharing.PrimarySimulator; } + get + { + return m_MeshSharing == MeshSharing.Primary + || m_MeshSharing == MeshSharing.PrimarySimulator; + } } internal bool canSimulate { - get { return m_MeshSharing == MeshSharing.None || m_MeshSharing == MeshSharing.Auto || m_MeshSharing == MeshSharing.Primary || m_MeshSharing == MeshSharing.PrimarySimulator; } + get + { + return m_MeshSharing == MeshSharing.None + || m_MeshSharing == MeshSharing.Auto + || m_MeshSharing == MeshSharing.Primary + || m_MeshSharing == MeshSharing.PrimarySimulator; + } } internal bool canRender { - get { return m_MeshSharing == MeshSharing.None || m_MeshSharing == MeshSharing.Auto || m_MeshSharing == MeshSharing.Primary || m_MeshSharing == MeshSharing.Replica; } + get + { + return m_MeshSharing == MeshSharing.None + || m_MeshSharing == MeshSharing.Auto + || m_MeshSharing == MeshSharing.Primary + || m_MeshSharing == MeshSharing.Replica; + } } /// @@ -197,12 +235,12 @@ namespace Coffee.UIExtensions { get { - for (var i = 0; i < m_Renderers.Count; i++) + for (var i = 0; i < _renderers.Count; i++) { - if (!m_Renderers[i] || !m_Renderers[i].material) continue; - yield return m_Renderers[i].material; + var r = _renderers[i]; + if (!r || !r.material) continue; + yield return r.material; } - yield break; } } @@ -214,10 +252,60 @@ namespace Coffee.UIExtensions /// /// Paused. /// - public bool isPaused { get; internal set; } + public bool isPaused { get; private set; } public Vector3 parentScale { get; private set; } + protected override void OnEnable() + { +#if !SERIALIZE_FIELD_MASKABLE + maskable = m_Maskable; +#endif + ResetGroupId(); + UpdateTracker(); + UIParticleUpdater.Register(this); + RegisterDirtyMaterialCallback(UpdateRendererMaterial); + + if (0 < particles.Count) + { + RefreshParticles(particles); + } + else + { + RefreshParticles(); + } + + base.OnEnable(); + } + + /// + /// This function is called when the behaviour becomes disabled. + /// + protected override void OnDisable() + { + UpdateTracker(); + UIParticleUpdater.Unregister(this); + _renderers.ForEach(r => r.Reset()); + UnregisterDirtyMaterialCallback(UpdateRendererMaterial); + + base.OnDisable(); + } + + /// + /// Callback for when properties have been changed by animation. + /// + protected override void OnDidApplyAnimationProperties() + { + } + +#if UNITY_EDITOR + protected override void OnValidate() + { + base.OnValidate(); + UpdateTracker(); + } +#endif + public void Play() { particles.Exec(p => p.Simulate(0, false, true)); @@ -240,7 +328,7 @@ namespace Coffee.UIExtensions particles.Exec(p => p.Stop()); isPaused = true; } - + public void StartEmission() { particles.Exec(p => @@ -249,7 +337,7 @@ namespace Coffee.UIExtensions emission.enabled = true; }); } - + public void StopEmission() { particles.Exec(p => @@ -278,14 +366,10 @@ namespace Coffee.UIExtensions { var go = child.gameObject; go.SetActive(false); - if (!destroyOldParticles) continue; - -#if UNITY_EDITOR - if (!Application.isPlaying) - DestroyImmediate(go); - else -#endif - Destroy(go); + if (destroyOldParticles) + { + Misc.Destroy(go); + } } var tr = instance.transform; @@ -313,11 +397,14 @@ namespace Coffee.UIExtensions root.GetComponentsInChildren(particles); particles.RemoveAll(x => x.GetComponentInParent() != this); - foreach (var ps in particles) + for (var i = 0; i < particles.Count; i++) { + var ps = particles[i]; var tsa = ps.textureSheetAnimation; if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0) + { tsa.uvChannelMask = UVChannelFlags.UV0; + } } RefreshParticles(particles); @@ -326,30 +413,31 @@ namespace Coffee.UIExtensions public void RefreshParticles(List particles) { // #246: Nullptr exceptions when using nested UIParticle components in hierarchy - m_Renderers.Clear(); + _renderers.Clear(); foreach (Transform child in transform) { var uiParticleRenderer = child.GetComponent(); if (uiParticleRenderer != null) { - m_Renderers.Add(uiParticleRenderer); + _renderers.Add(uiParticleRenderer); } } - for (var i = 0; i < m_Renderers.Count; i++) + for (var i = 0; i < _renderers.Count; i++) { - m_Renderers[i].Reset(i); + _renderers[i].Reset(i); } var j = 0; for (var i = 0; i < particles.Count; i++) { - if (!particles[i]) continue; - GetRenderer(j++).Set(this, particles[i], false); - if (particles[i].trails.enabled) + var ps = particles[i]; + if (!ps) continue; + GetRenderer(j++).Set(this, ps, false); + if (ps.trails.enabled) { - GetRenderer(j++).Set(this, particles[i], true); + GetRenderer(j++).Set(this, ps, true); } } } @@ -370,9 +458,10 @@ namespace Coffee.UIExtensions { if (!isActiveAndEnabled) return; - foreach (var rend in m_Renderers) + for (var i = 0; i < _renderers.Count; i++) { - if (!rend) + var r = _renderers[i]; + if (!r) { RefreshParticles(particles); break; @@ -380,67 +469,29 @@ namespace Coffee.UIExtensions } var bakeCamera = GetBakeCamera(); - for (var i = 0; i < m_Renderers.Count; i++) + for (var i = 0; i < _renderers.Count; i++) { - if (!m_Renderers[i]) continue; - m_Renderers[i].UpdateMesh(bakeCamera); + var r = _renderers[i]; + if (!r) continue; + r.UpdateMesh(bakeCamera); } } internal void UpdateParticleCount() { - for (var i = 0; i < m_Renderers.Count; i++) + for (var i = 0; i < _renderers.Count; i++) { - if (!m_Renderers[i]) continue; - m_Renderers[i].UpdateParticleCount(); + var r = _renderers[i]; + if (!r) continue; + r.UpdateParticleCount(); } } - protected override void OnEnable() - { -#if !SERIALIZE_FIELD_MASKABLE - maskable = m_Maskable; -#endif - ResetGroupId(); - UpdateTracker(); - UIParticleUpdater.Register(this); - RegisterDirtyMaterialCallback(UpdateRendererMaterial); - - if (0 < particles.Count) - { - RefreshParticles(particles); - } - else - { - RefreshParticles(); - } - - base.OnEnable(); - } - internal void ResetGroupId() { - if (m_GroupId == m_GroupMaxId) - { - _groupId = m_GroupId; - } - else - { - _groupId = Random.Range(m_GroupId, m_GroupMaxId + 1); - } - } - - /// - /// This function is called when the behaviour becomes disabled. - /// - protected override void OnDisable() - { - UpdateTracker(); - UIParticleUpdater.Unregister(this); - m_Renderers.ForEach(r => r.Reset()); - UnregisterDirtyMaterialCallback(UpdateRendererMaterial); - - base.OnDisable(); + _groupId = m_GroupId == m_GroupMaxId + ? m_GroupId + : Random.Range(m_GroupId, m_GroupMaxId + 1); } protected override void UpdateMaterial() @@ -454,43 +505,42 @@ namespace Coffee.UIExtensions { } - /// - /// Callback for when properties have been changed by animation. - /// - protected override void OnDidApplyAnimationProperties() - { - } - private void UpdateRendererMaterial() { - for (var i = 0; i < m_Renderers.Count; i++) + for (var i = 0; i < _renderers.Count; i++) { - if (!m_Renderers[i]) continue; - m_Renderers[i].maskable = maskable; - m_Renderers[i].SetMaterialDirty(); + var r = _renderers[i]; + if (!r) continue; + r.maskable = maskable; + r.SetMaterialDirty(); } } internal UIParticleRenderer GetRenderer(int index) { - if (m_Renderers.Count <= index) + if (_renderers.Count <= index) { - m_Renderers.Add(UIParticleRenderer.AddRenderer(this, index)); + _renderers.Add(UIParticleRenderer.AddRenderer(this, index)); } - if (!m_Renderers[index]) + + if (!_renderers[index]) { - m_Renderers[index] = UIParticleRenderer.AddRenderer(this, index); + _renderers[index] = UIParticleRenderer.AddRenderer(this, index); } - return m_Renderers[index]; + + return _renderers[index]; } private Camera GetBakeCamera() { if (!canvas) return Camera.main; - // World camera. + // Render mode is not ScreenSpaceOverlay, use world camera. var root = canvas.rootCanvas; - if (root.renderMode != RenderMode.ScreenSpaceOverlay) return root.worldCamera ? root.worldCamera : Camera.main; + if (root.renderMode != RenderMode.ScreenSpaceOverlay) + { + return root.worldCamera ? root.worldCamera : Camera.main; + } // Create ortho-camera. if (!_orthoCamera) @@ -498,10 +548,7 @@ namespace Coffee.UIExtensions _orthoCamera = GetComponentInChildren(); if (!_orthoCamera) { - var go = new GameObject("UIParticleOverlayCamera") - { - hideFlags = HideFlags.DontSave, - }; + var go = new GameObject("UIParticleOverlayCamera") { hideFlags = HideFlags.DontSave }; go.SetActive(false); go.transform.SetParent(transform, false); _orthoCamera = go.AddComponent(); @@ -509,7 +556,7 @@ namespace Coffee.UIExtensions } } - // + // var size = ((RectTransform)root.transform).rect.size; _orthoCamera.orthographicSize = Mathf.Max(size.x, size.y) * root.scaleFactor; _orthoCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity); @@ -530,13 +577,5 @@ namespace Coffee.UIExtensions _tracker.Add(this, rectTransform, DrivenTransformProperties.Scale); } } - -#if UNITY_EDITOR - protected override void OnValidate() - { - base.OnValidate(); - UpdateTracker(); - } -#endif } } diff --git a/Scripts/UIParticleAttractor.cs b/Scripts/UIParticleAttractor.cs index ab3c128..59e85a9 100644 --- a/Scripts/UIParticleAttractor.cs +++ b/Scripts/UIParticleAttractor.cs @@ -1,7 +1,7 @@ -using UnityEngine; +using System; using Coffee.UIParticleExtensions; +using UnityEngine; using UnityEngine.Events; -using System; namespace Coffee.UIExtensions { @@ -12,13 +12,13 @@ namespace Coffee.UIExtensions { Linear, Smooth, - Sphere, + Sphere } - + public enum UpdateMode { Normal, - UnscaledTime, + UnscaledTime } [SerializeField] @@ -30,7 +30,7 @@ namespace Coffee.UIExtensions [Range(0f, 0.95f)] [SerializeField] - private float m_DelayRate = 0; + private float m_DelayRate; [Range(0.001f, 100f)] [SerializeField] @@ -45,84 +45,51 @@ namespace Coffee.UIExtensions [SerializeField] private UnityEvent m_OnAttracted; + private UIParticle _uiParticle; + public float destinationRadius { - get - { - return m_DestinationRadius; - } - set - { - m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f); - } + get { return m_DestinationRadius; } + set { m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f); } } public float delay { - get - { - return m_DelayRate; - } - set - { - m_DelayRate = value; - } + get { return m_DelayRate; } + set { m_DelayRate = value; } } public float maxSpeed { - get - { - return m_MaxSpeed; - } - set - { - m_MaxSpeed = value; - } + get { return m_MaxSpeed; } + set { m_MaxSpeed = value; } } public Movement movement { - get - { - return m_Movement; - } - set - { - m_Movement = value; - } + get { return m_Movement; } + set { m_Movement = value; } } public UpdateMode updateMode { - get - { - return m_UpdateMode; - } - set - { - m_UpdateMode = value; - } + get { return m_UpdateMode; } + set { m_UpdateMode = value; } } public UnityEvent onAttracted { - get - { - return m_OnAttracted; - } - set - { - m_OnAttracted = value; - } + get { return m_OnAttracted; } + set { m_OnAttracted = value; } } +#if UNITY_EDITOR + public new ParticleSystem particleSystem +#else public ParticleSystem particleSystem +#endif { - get - { - return m_ParticleSystem; - } + get { return m_ParticleSystem; } set { m_ParticleSystem = value; @@ -130,8 +97,6 @@ namespace Coffee.UIExtensions } } - private UIParticle _uiParticle; - private void OnEnable() { ApplyParticleSystem(); @@ -207,7 +172,7 @@ namespace Coffee.UIExtensions var psPos = m_ParticleSystem.transform.position; var attractorPos = transform.position; var dstPos = attractorPos; - var isLocalSpace = m_ParticleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local; + var isLocalSpace = m_ParticleSystem.IsLocalSpace(); if (isLocalSpace) { @@ -251,6 +216,7 @@ namespace Coffee.UIExtensions speed *= 60 * Time.unscaledDeltaTime; break; } + switch (m_Movement) { case Movement.Linear: @@ -278,6 +244,7 @@ namespace Coffee.UIExtensions { Debug.LogError("No particle system attached to particle attractor script", this); } + return; } @@ -288,4 +255,4 @@ namespace Coffee.UIExtensions } } } -} \ No newline at end of file +} diff --git a/Scripts/UIParticleRenderer.cs b/Scripts/UIParticleRenderer.cs index 583ba32..3c260a2 100644 --- a/Scripts/UIParticleRenderer.cs +++ b/Scripts/UIParticleRenderer.cs @@ -1,9 +1,10 @@ -using UnityEngine; -using UnityEngine.UI; +using System; +using System.Collections.Generic; using Coffee.UIParticleExtensions; +using UnityEngine; using UnityEngine.Profiling; using UnityEngine.Rendering; -using System.Collections.Generic; +using UnityEngine.UI; namespace Coffee.UIExtensions { @@ -13,41 +14,34 @@ namespace Coffee.UIExtensions [AddComponentMenu("")] internal class UIParticleRenderer : MaskableGraphic { - private static readonly CombineInstance[] s_CombineInstances = new CombineInstance[] { new CombineInstance() }; + private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() }; private static readonly List s_Materials = new List(2); private static MaterialPropertyBlock s_Mpb; private static readonly List s_Renderers = new List(); private static readonly Vector3[] s_Corners = new Vector3[4]; - - private ParticleSystemRenderer _renderer; - private ParticleSystem _particleSystem; - private int _prevParticleCount = 0; - private UIParticle _parent; + private Material _currentMaterialForRendering; + private bool _delay; private int _index; private bool _isTrail; - private Material _modifiedMaterial; - private Vector3 _prevScale; - private Vector3 _prevPsPos; - private Vector2Int _prevScreenSize; - private bool _delay = false; - private bool _prewarm = false; - private Material _currentMaterialForRendering; private Bounds _lastBounds; + private Material _modifiedMaterial; + private UIParticle _parent; + private ParticleSystem _particleSystem; + private int _prevParticleCount; + private Vector3 _prevPsPos; + private Vector3 _prevScale; + private Vector2Int _prevScreenSize; + private bool _prewarm; + private ParticleSystemRenderer _renderer; public override Texture mainTexture { - get - { - return _isTrail ? null : _particleSystem.GetTextureForSprite(); - } + get { return _isTrail ? null : _particleSystem.GetTextureForSprite(); } } public override bool raycastTarget { - get - { - return false; - } + get { return false; } } private Rect rootCanvasRect @@ -62,32 +56,103 @@ namespace Coffee.UIExtensions { var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix; for (var i = 0; i < 4; ++i) + { s_Corners[i] = worldToLocalMatrix.MultiplyPoint(s_Corners[i]); + } } - var corner1 = (Vector2) s_Corners[0]; - var corner2 = (Vector2) s_Corners[0]; + + var corner1 = (Vector2)s_Corners[0]; + var corner2 = (Vector2)s_Corners[0]; for (var i = 1; i < 4; ++i) { if (s_Corners[i].x < corner1.x) + { corner1.x = s_Corners[i].x; + } else if (s_Corners[i].x > corner2.x) + { corner2.x = s_Corners[i].x; + } + if (s_Corners[i].y < corner1.y) + { corner1.y = s_Corners[i].y; + } else if (s_Corners[i].y > corner2.y) + { corner2.y = s_Corners[i].y; + } } + return new Rect(corner1, corner2 - corner1); } } + public void Reset(int index = -1) + { + if (_renderer) + { + _renderer.enabled = true; + } + + _parent = null; + _particleSystem = null; + _renderer = null; + _prevParticleCount = 0; + if (0 <= index) + { + _index = index; + } + + //_emitter = null; + if (this && isActiveAndEnabled) + { + material = null; + workerMesh.Clear(); + canvasRenderer.SetMesh(workerMesh); + _lastBounds = new Bounds(); + enabled = false; + } + else + { + ModifiedMaterial.Remove(_modifiedMaterial); + _modifiedMaterial = null; + _currentMaterialForRendering = null; + } + } + + protected override void OnEnable() + { + base.OnEnable(); + + if (!s_CombineInstances[0].mesh) + { + s_CombineInstances[0].mesh = new Mesh + { + name = "[UIParticleRenderer] Combine Instance Mesh", + hideFlags = HideFlags.HideAndDontSave + }; + } + + _currentMaterialForRendering = null; + } + + protected override void OnDisable() + { + base.OnDisable(); + + ModifiedMaterial.Remove(_modifiedMaterial); + _modifiedMaterial = null; + _currentMaterialForRendering = null; + } + public static UIParticleRenderer AddRenderer(UIParticle parent, int index) { // Create renderer object. var go = new GameObject("UIParticleRenderer", typeof(UIParticleRenderer)) { hideFlags = HideFlags.DontSave, - layer = parent.gameObject.layer, + layer = parent.gameObject.layer }; // Set parent. @@ -139,45 +204,14 @@ namespace Coffee.UIExtensions return modifiedMaterial; } - public void Reset(int index = -1) - { - if (_renderer) - { - _renderer.enabled = true; - } - _parent = null; - _particleSystem = null; - _renderer = null; - _prevParticleCount = 0; - if (0 <= index) - { - _index = index; - } - //_emitter = null; - if (this && isActiveAndEnabled) - { - material = null; - workerMesh.Clear(); - canvasRenderer.SetMesh(workerMesh); - _lastBounds = new Bounds(); - enabled = false; - } - else - { - ModifiedMaterial.Remove(_modifiedMaterial); - _modifiedMaterial = null; - _currentMaterialForRendering = null; - } - } - - public void Set(UIParticle parent, ParticleSystem particleSystem, bool isTrail) + public void Set(UIParticle parent, ParticleSystem ps, bool isTrail) { _parent = parent; maskable = parent.maskable; gameObject.layer = parent.gameObject.layer; - _particleSystem = particleSystem; + _particleSystem = ps; _prewarm = _particleSystem.main.prewarm; #if UNITY_EDITOR @@ -191,7 +225,7 @@ namespace Coffee.UIExtensions } } - _renderer = particleSystem.GetComponent(); + _renderer = ps.GetComponent(); _renderer.enabled = false; //_emitter = emitter; @@ -202,9 +236,11 @@ namespace Coffee.UIExtensions s_Materials.Clear(); // Support sprite. - var tsa = particleSystem.textureSheetAnimation; + var tsa = ps.textureSheetAnimation; if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0) + { tsa.uvChannelMask = UVChannelFlags.UV0; + } _prevScale = GetWorldScale(); _prevPsPos = _particleSystem.transform.position; @@ -221,15 +257,17 @@ namespace Coffee.UIExtensions { // No particle to render: Clear mesh. if ( - !isActiveAndEnabled || !_particleSystem || !_parent || !canvasRenderer || !canvas || !bakeCamera + !isActiveAndEnabled || !_particleSystem || !_parent + || !canvasRenderer || !canvas || !bakeCamera || _parent.meshSharing == UIParticle.MeshSharing.Replica - || !transform.lossyScale.GetScaled(_parent.scale3D).IsVisible() // Scale is not visible. - || (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle. - || (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled. + || !transform.lossyScale.GetScaled(_parent.scale3D).IsVisible() // Scale is not visible. + || (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle. + || (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled. #if UNITY_2018_3_OR_NEWER - || canvasRenderer.GetInheritedAlpha() < 0.01f // #102: Do not bake particle system to mesh when the alpha is zero. + || canvasRenderer.GetInheritedAlpha() < + 0.01f // #102: Do not bake particle system to mesh when the alpha is zero. #endif - ) + ) { Profiler.BeginSample("[UIParticleRenderer] Clear Mesh"); workerMesh.Clear(); @@ -265,15 +303,20 @@ namespace Coffee.UIExtensions } // When the ParticleSystem simulation is complete, stop it. - if (!main.loop && main.duration <= _particleSystem.time && (_particleSystem.IsAlive() || _particleSystem.particleCount == 0)) + if (!main.loop + && main.duration <= _particleSystem.time + && (_particleSystem.IsAlive() || _particleSystem.particleCount == 0) + ) { _particleSystem.Stop(false); } } + _prevScale = scale; _prevPsPos = psPos; _delay = false; } + Profiler.EndSample(); // Bake mesh. @@ -295,7 +338,7 @@ namespace Coffee.UIExtensions if (65535 <= s_CombineInstances[0].mesh.vertexCount) { s_CombineInstances[0].mesh.Clear(false); - UnityEngine.Debug.LogErrorFormat(this, + Debug.LogErrorFormat(this, "Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)", _index, _isTrail, @@ -303,6 +346,7 @@ namespace Coffee.UIExtensions ); s_CombineInstances[0].mesh.Clear(false); } + Profiler.EndSample(); // Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local) @@ -311,13 +355,19 @@ namespace Coffee.UIExtensions { if (_parent.absoluteMode) { - s_CombineInstances[0].transform = canvasRenderer.transform.worldToLocalMatrix * GetWorldMatrix(psPos, scale); + s_CombineInstances[0].transform = + canvasRenderer.transform.worldToLocalMatrix + * GetWorldMatrix(psPos, scale); } else { var diff = _particleSystem.transform.position - _parent.transform.position; - s_CombineInstances[0].transform = canvasRenderer.transform.worldToLocalMatrix * Matrix4x4.Translate(diff.GetScaled(scale - Vector3.one)) * GetWorldMatrix(psPos, scale); + s_CombineInstances[0].transform = + canvasRenderer.transform.worldToLocalMatrix + * Matrix4x4.Translate(diff.GetScaled(scale - Vector3.one)) + * GetWorldMatrix(psPos, scale); } + workerMesh.CombineMeshes(s_CombineInstances, true, true); workerMesh.RecalculateBounds(); @@ -331,6 +381,7 @@ namespace Coffee.UIExtensions workerMesh.bounds = bounds; _lastBounds = bounds; } + Profiler.EndSample(); @@ -343,7 +394,7 @@ namespace Coffee.UIExtensions // Set mesh to the CanvasRenderer. Profiler.BeginSample("[UIParticleRenderer] Set Mesh"); - for (int i = 0; i < s_Renderers.Count; i++) + for (var i = 0; i < s_Renderers.Count; i++) { if (s_Renderers[i] == this) continue; s_Renderers[i].canvasRenderer.SetMesh(workerMesh); @@ -354,6 +405,7 @@ namespace Coffee.UIExtensions { workerMesh.Clear(); } + canvasRenderer.SetMesh(workerMesh); Profiler.EndSample(); @@ -366,7 +418,8 @@ namespace Coffee.UIExtensions { _currentMaterialForRendering = materialForRendering; } - for (int i = 0; i < s_Renderers.Count; i++) + + for (var i = 0; i < s_Renderers.Count; i++) { if (s_Renderers[i] == this) continue; @@ -374,6 +427,7 @@ namespace Coffee.UIExtensions s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0); } } + Profiler.EndSample(); s_Renderers.Clear(); @@ -385,30 +439,6 @@ namespace Coffee.UIExtensions _prevParticleCount = _particleSystem.particleCount; } - protected override void OnEnable() - { - base.OnEnable(); - - if (!s_CombineInstances[0].mesh) - { - s_CombineInstances[0].mesh = new Mesh() - { - name = "[UIParticleRenderer] Combine Instance Mesh", - hideFlags = HideFlags.HideAndDontSave, - }; - } - _currentMaterialForRendering = null; - } - - protected override void OnDisable() - { - base.OnDisable(); - - ModifiedMaterial.Remove(_modifiedMaterial); - _modifiedMaterial = null; - _currentMaterialForRendering = null; - } - /// /// Call to update the geometry of the Graphic onto the CanvasRenderer. /// @@ -418,7 +448,9 @@ namespace Coffee.UIExtensions public override void Cull(Rect clipRect, bool validRect) { - var cull = _lastBounds.extents == Vector3.zero || !validRect || !clipRect.Overlaps(rootCanvasRect, true); + var cull = _lastBounds.extents == Vector3.zero + || !validRect + || !clipRect.Overlaps(rootCanvasRect, true); if (canvasRenderer.cull == cull) return; canvasRenderer.cull = cull; @@ -450,8 +482,8 @@ namespace Coffee.UIExtensions { case ParticleSystemSimulationSpace.World: return Matrix4x4.Translate(psPos) - * Matrix4x4.Scale(scale) - * Matrix4x4.Translate(-psPos); + * Matrix4x4.Scale(scale) + * Matrix4x4.Translate(-psPos); } } #endif @@ -460,17 +492,17 @@ namespace Coffee.UIExtensions { case ParticleSystemSimulationSpace.Local: return Matrix4x4.Translate(psPos) - * Matrix4x4.Scale(scale); + * Matrix4x4.Scale(scale); case ParticleSystemSimulationSpace.World: return Matrix4x4.Scale(scale); case ParticleSystemSimulationSpace.Custom: return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale)) - //* Matrix4x4.Translate(wpos) - * Matrix4x4.Scale(scale) + //* Matrix4x4.Translate(wpos) + * Matrix4x4.Scale(scale) //* Matrix4x4.Translate(-wpos) ; default: - throw new System.NotSupportedException(); + throw new NotSupportedException(); } } @@ -482,8 +514,9 @@ namespace Coffee.UIExtensions private void ResolveResolutionChange(Vector3 psPos, Vector3 scale) { var screenSize = new Vector2Int(Screen.width, Screen.height); - //if ((_prevScreenSize != screenSize || _prevScale != scale) && _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World && _parent.uiScaling) - if ((_prevScreenSize != screenSize || _prevScale != scale) && _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World) + var isWorldSpace = _particleSystem.IsWorldSpace(); + var resolutionChanged = _prevScreenSize != screenSize || _prevScale != scale; + if (resolutionChanged && isWorldSpace) { // Update particle array size and get particles. var size = _particleSystem.particleCount; @@ -492,13 +525,17 @@ namespace Coffee.UIExtensions // Resolusion resolver: // (psPos / scale) / (prevPsPos / prevScale) -> psPos * scale.inv * prevPsPos.inv * prevScale - var modifier = psPos.GetScaled(scale.Inverse(), _prevPsPos.Inverse(), _prevScale); + var modifier = psPos.GetScaled( + scale.Inverse(), + _prevPsPos.Inverse(), + _prevScale); for (var i = 0; i < size; i++) { var particle = particles[i]; particle.position = particle.position.GetScaled(modifier); particles[i] = particle; } + _particleSystem.SetParticles(particles, size); // Delay: Do not progress in the frame where the resolution has been changed. @@ -506,6 +543,7 @@ namespace Coffee.UIExtensions _prevScale = scale; _prevPsPos = psPos; } + _prevScreenSize = screenSize; } @@ -548,13 +586,14 @@ namespace Coffee.UIExtensions var psTransform = _particleSystem.transform; var originWorldPosition = psTransform.position; var originWorldRotation = psTransform.rotation; - var emission = _particleSystem.emission; - var rateOverDistance = emission.enabled && 0 < emission.rateOverDistance.constant && 0 < emission.rateOverDistanceMultiplier; + var rateOverDistance = emission.enabled + && 0 < emission.rateOverDistance.constant + && 0 < emission.rateOverDistanceMultiplier; if (rateOverDistance) { // (For rate-over-distance emission,) Move to previous scaled position, simulate (delta = 0). - Vector3 prevScaledPos = _prevPsPos.GetScaled(_prevScale.Inverse()); + var prevScaledPos = _prevPsPos.GetScaled(_prevScale.Inverse()); psTransform.SetPositionAndRotation(prevScaledPos, originWorldRotation); _particleSystem.Simulate(0, false, false, false); } @@ -570,7 +609,8 @@ namespace Coffee.UIExtensions private void SimulateForEditor(Vector3 diffPos, Vector3 scale) { // Extra world simulation. - if (_particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < Vector3.SqrMagnitude(diffPos)) + var isWorldSpace = _particleSystem.IsWorldSpace(); + if (isWorldSpace && 0 < Vector3.SqrMagnitude(diffPos)) { Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation"); diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x); @@ -598,7 +638,9 @@ namespace Coffee.UIExtensions if (_parent.m_AnimatableProperties.Length == 0) return; if (s_Mpb == null) + { s_Mpb = new MaterialPropertyBlock(); + } _renderer.GetPropertyBlock(s_Mpb); if (s_Mpb.isEmpty) return; @@ -606,8 +648,9 @@ namespace Coffee.UIExtensions // #41: Copy the value from MaterialPropertyBlock to CanvasRenderer if (!_modifiedMaterial) return; - foreach (var ap in _parent.m_AnimatableProperties) + for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++) { + var ap = _parent.m_AnimatableProperties[i]; ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb); } diff --git a/Scripts/UIParticleUpdater.cs b/Scripts/UIParticleUpdater.cs index b90dc41..7a191f0 100644 --- a/Scripts/UIParticleUpdater.cs +++ b/Scripts/UIParticleUpdater.cs @@ -1,21 +1,19 @@ using System.Collections.Generic; +using UnityEditor; using UnityEngine; namespace Coffee.UIExtensions { internal static class UIParticleUpdater { - static readonly List s_ActiveParticles = new List(); - static readonly List s_ActiveAttractors = new List(); - static readonly HashSet s_UpdatedGroupIds = new HashSet(); - private static int frameCount = 0; + private static readonly List s_ActiveParticles = new List(); + private static readonly List s_ActiveAttractors = new List(); + private static readonly HashSet s_UpdatedGroupIds = new HashSet(); + private static int s_FrameCount; public static int uiParticleCount { - get - { - return s_ActiveParticles.Count; - } + get { return s_ActiveParticles.Count; } } public static void Register(UIParticle particle) @@ -43,7 +41,7 @@ namespace Coffee.UIExtensions } #if UNITY_EDITOR - [UnityEditor.InitializeOnLoadMethod] + [InitializeOnLoadMethod] #endif [RuntimeInitializeOnLoadMethod] private static void InitializeOnLoad() @@ -55,8 +53,8 @@ namespace Coffee.UIExtensions private static void Refresh() { // Do not allow it to be called in the same frame. - if (frameCount == Time.frameCount) return; - frameCount = Time.frameCount; + if (s_FrameCount == Time.frameCount) return; + s_FrameCount = Time.frameCount; // Simulate -> Primary for (var i = 0; i < s_ActiveParticles.Count; i++) @@ -129,6 +127,7 @@ namespace Coffee.UIExtensions if (uip.isPrimary) return uip; if (!primary && uip.canSimulate) primary = uip; } + return primary; } } diff --git a/Scripts/Utils.cs b/Scripts/Utils.cs index d091089..dda1b19 100644 --- a/Scripts/Utils.cs +++ b/Scripts/Utils.cs @@ -46,11 +46,11 @@ namespace Coffee.UIParticleExtensions internal static class SpriteExtensions { #if UNITY_EDITOR - private static Type tSpriteEditorExtension = + private static readonly Type s_SpriteEditorExtensionType = Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor") ?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor"); - private static MethodInfo miGetActiveAtlasTexture = tSpriteEditorExtension + private static readonly MethodInfo s_GetActiveAtlasTextureMethodInfo = s_SpriteEditorExtensionType .GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic); public static Texture2D GetActualTexture(this Sprite self) @@ -58,8 +58,10 @@ namespace Coffee.UIParticleExtensions if (!self) return null; if (Application.isPlaying) return self.texture; - var ret = miGetActiveAtlasTexture.Invoke(null, new[] { self }) as Texture2D; - return ret ? ret : self.texture; + var ret = s_GetActiveAtlasTextureMethodInfo.Invoke(null, new object[] { self }) as Texture2D; + return ret + ? ret + : self.texture; } #else internal static Texture2D GetActualTexture(this Sprite self) @@ -77,12 +79,14 @@ namespace Coffee.UIParticleExtensions { if (s_TmpParticles.Length < size) { - while(s_TmpParticles.Length < size) + while (s_TmpParticles.Length < size) { size = Mathf.NextPowerOfTwo(size); } + s_TmpParticles = new ParticleSystem.Particle[size]; } + return s_TmpParticles; } @@ -102,47 +106,69 @@ namespace Coffee.UIParticleExtensions var main = self.main; var space = main.simulationSpace; if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace) + { space = ParticleSystemSimulationSpace.Local; + } return space; } + public static bool IsLocalSpace(this ParticleSystem self) + { + return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.Local; + } + + public static bool IsWorldSpace(this ParticleSystem self) + { + return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.World; + } + public static void SortForRendering(this List self, Transform transform, bool sortByMaterial) { self.Sort((a, b) => { - var tr = transform; var aRenderer = a.GetComponent(); var bRenderer = b.GetComponent(); // Render queue: ascending - var aMat = aRenderer.sharedMaterial ?? aRenderer.trailMaterial; - var bMat = bRenderer.sharedMaterial ?? bRenderer.trailMaterial; + var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial; + var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial; if (!aMat && !bMat) return 0; if (!aMat) return -1; if (!bMat) return 1; if (sortByMaterial) + { return aMat.GetInstanceID() - bMat.GetInstanceID(); + } if (aMat.renderQueue != bMat.renderQueue) + { return aMat.renderQueue - bMat.renderQueue; + } // Sorting layer: ascending if (aRenderer.sortingLayerID != bRenderer.sortingLayerID) - return SortingLayer.GetLayerValueFromID(aRenderer.sortingLayerID) - SortingLayer.GetLayerValueFromID(bRenderer.sortingLayerID); + { + return SortingLayer.GetLayerValueFromID(aRenderer.sortingLayerID) - + SortingLayer.GetLayerValueFromID(bRenderer.sortingLayerID); + } // Sorting order: ascending if (aRenderer.sortingOrder != bRenderer.sortingOrder) + { return aRenderer.sortingOrder - bRenderer.sortingOrder; + } // Z position & sortingFudge: descending var aTransform = a.transform; var bTransform = b.transform; - var aPos = tr.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge; - var bPos = tr.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge; + var aPos = transform.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge; + var bPos = transform.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge; if (!Mathf.Approximately(aPos, bPos)) + { return (int)Mathf.Sign(bPos - aPos); + } return (int)Mathf.Sign(GetIndex(self, a) - GetIndex(self, b)); }); @@ -152,7 +178,10 @@ namespace Coffee.UIParticleExtensions { for (var i = 0; i < list.Count; i++) { - if (list[i].GetInstanceID() == ps.GetInstanceID()) return i; + if (list[i].GetInstanceID() == ps.GetInstanceID()) + { + return i; + } } return 0; @@ -183,4 +212,37 @@ namespace Coffee.UIParticleExtensions self.ForEach(action); } } + + internal static class Misc + { + public static void Destroy(Object obj) + { + if (!obj) return; +#if UNITY_EDITOR + if (!Application.isPlaying) + { + Object.DestroyImmediate(obj); + } + else +#endif + { + Object.Destroy(obj); + } + } + + public static void DestroyImmediate(Object obj) + { + if (!obj) return; +#if UNITY_EDITOR + if (Application.isEditor) + { + Object.DestroyImmediate(obj); + } + else +#endif + { + Object.Destroy(obj); + } + } + } }