From 7e248e51043d6fd784915749b23a92bcbe89d83d Mon Sep 17 00:00:00 2001 From: mob-sakai Date: Thu, 17 Aug 2023 09:43:02 +0900 Subject: [PATCH] resharp --- .../CFX_Demo_With_UIParticle.cs | 136 ++++---- Samples~/Demo/Scripts/CopyItemOnStart.cs | 24 +- Samples~/Demo/Scripts/UIElementDragger.cs | 94 ++--- Samples~/Demo/Scripts/UIParticle_Demo.cs | 101 +++--- .../UIParticle_Demo_UIParticleController.cs | 23 +- .../NanoMonitor/Fonts/FalstinRegular.ttf | Bin 30332 -> 0 bytes .../NanoMonitor/Fonts/ShareTechMono.ttf | Bin 0 -> 23976 bytes ...egular.ttf.meta => ShareTechMono.ttf.meta} | 6 +- .../NanoMonitor/Prefab/NanoMonitor.prefab | 26 +- .../NanoMonitor/Scripts/NanoMonitor.cs | 298 ++++++++-------- .../Scripts/ProfilerUI/FixedFont.cs | 74 ++-- .../Scripts/ProfilerUI/MonitorUI.cs | 167 ++++----- .../ProjectSettings~/MiniProfilerSettings.cs | 55 --- .../MiniProfilerSettings.cs.meta | 13 - .../ProjectSettings~/ScriptableSettings.cs | 280 --------------- .../ScriptableSettings.cs.meta | 11 - .../Scripts/Utilities/CustomProfilerItem.cs | 30 +- .../Scripts/Utilities/NumericProperty.cs | 169 +++++---- .../Utilities/StringBuilderExtensions.cs | 36 +- .../Scripts/UIParticle_PerformanceDemo.cs | 115 ++---- .../UIParticle_PerformanceDemo.unity | 251 +++++--------- Scripts/AnimatableProperty.cs | 47 ++- Scripts/Editor/AnimatablePropertyEditor.cs | 143 ++++++++ ....meta => AnimatablePropertyEditor.cs.meta} | 0 Scripts/Editor/AnimatedPropertiesEditor.cs | 123 ------- Scripts/Editor/ImportSampleMenu.cs | 27 +- Scripts/Editor/UIParticleEditor.cs | 293 +++++++++------- Scripts/ModifiedMaterial.cs | 40 +-- Scripts/UIParticle.cs | 326 ++++++++++-------- Scripts/UIParticleAttractor.cs | 91 ++--- Scripts/UIParticleRenderer.cs | 287 ++++++++------- Scripts/UIParticleUpdater.cs | 21 +- Scripts/Utils.cs | 86 ++++- 33 files changed, 1618 insertions(+), 1775 deletions(-) delete mode 100644 Samples~/Performance Demo/NanoMonitor/Fonts/FalstinRegular.ttf create mode 100644 Samples~/Performance Demo/NanoMonitor/Fonts/ShareTechMono.ttf rename Samples~/Performance Demo/NanoMonitor/Fonts/{FalstinRegular.ttf.meta => ShareTechMono.ttf.meta} (82%) delete mode 100644 Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs delete mode 100644 Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/MiniProfilerSettings.cs.meta delete mode 100644 Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs delete mode 100644 Samples~/Performance Demo/NanoMonitor/Scripts/ProjectSettings~/ScriptableSettings.cs.meta create mode 100644 Scripts/Editor/AnimatablePropertyEditor.cs rename Scripts/Editor/{AnimatedPropertiesEditor.cs.meta => AnimatablePropertyEditor.cs.meta} (100%) delete mode 100644 Scripts/Editor/AnimatedPropertiesEditor.cs 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 b96b91925cd196410eaddee2e49afa1637c576bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30332 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

}S~vPrlJ;R9w2J&P-*c$lrr7sR;9-9^@B#R?5>$ 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%0D=Y*YZm%rp;@_wgN^kbBFRBzIu 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 literal 0 HcmV?d00001 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..14240f3 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,95 +122,98 @@ 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(); } //################################ // Public/Protected Members. //################################ ///

- /// This function is called when the object becomes enabled and active. + /// This function is called when the object becomes enabled and active. /// protected override void OnEnable() { 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); + } } } @@ -223,7 +232,7 @@ namespace Coffee.UIExtensions } /// - /// Implement this function to make a custom inspector. + /// Implement this function to make a custom inspector. /// public override void OnInspectorGUI() { @@ -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 5d8e8a1..8e2bc30 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; @@ -15,7 +14,7 @@ using UnityEngine.UI; namespace Coffee.UIExtensions { /// - /// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas. + /// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas. /// [ExecuteAlways] [RequireComponent(typeof(RectTransform))] @@ -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 = true; /// - /// This field uses the inverted value as "AutoScaling". + /// 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,11 +98,12 @@ namespace Coffee.UIExtensions } /// - /// 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). - /// Replica: render simulation results provided by the primary. + /// 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). + /// Replica: render simulation results provided by the primary. /// public MeshSharing meshSharing { @@ -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,12 @@ 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,21 +177,37 @@ 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; + } } /// - /// Particle effect scale. + /// Particle effect scale. /// public float scale { @@ -177,7 +216,7 @@ namespace Coffee.UIExtensions } /// - /// Particle effect scale. + /// Particle effect scale. /// public Vector3 scale3D { @@ -191,18 +230,18 @@ namespace Coffee.UIExtensions } /// - /// Get all base materials to render. + /// Get all base materials to render. /// public IEnumerable materials { 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; } } @@ -212,12 +251,62 @@ namespace Coffee.UIExtensions } /// - /// Paused. + /// 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 +329,7 @@ namespace Coffee.UIExtensions particles.Exec(p => p.Stop()); isPaused = true; } - + public void StartEmission() { particles.Exec(p => @@ -249,7 +338,7 @@ namespace Coffee.UIExtensions emission.enabled = true; }); } - + public void StopEmission() { particles.Exec(p => @@ -278,14 +367,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 +398,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 +414,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 +459,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 +470,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() @@ -448,49 +500,48 @@ namespace Coffee.UIExtensions } /// - /// Call to update the geometry of the Graphic onto the CanvasRenderer. + /// Call to update the geometry of the Graphic onto the CanvasRenderer. /// protected override void UpdateGeometry() { } - /// - /// 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 +549,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 +557,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 +578,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 0091735..360aacb 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,43 +14,36 @@ 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 { get @@ -62,32 +56,101 @@ 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, + hideFlags = HideFlags.DontSave, layer = parent.gameObject.layer }; // Set parent. @@ -106,7 +169,7 @@ namespace Coffee.UIExtensions } /// - /// Perform material modification in this function. + /// Perform material modification in this function. /// public override Material GetModifiedMaterial(Material baseMaterial) { @@ -121,7 +184,7 @@ namespace Coffee.UIExtensions var modifiedMaterial = base.GetModifiedMaterial(baseMaterial); - // + // var texture = mainTexture; if (texture == null && _parent.m_AnimatableProperties.Length == 0) { @@ -139,45 +202,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 +223,7 @@ namespace Coffee.UIExtensions } } - _renderer = particleSystem.GetComponent(); + _renderer = ps.GetComponent(); _renderer.enabled = false; //_emitter = emitter; @@ -202,9 +234,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 +255,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 +301,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,13 +336,14 @@ 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, s_CombineInstances[0].mesh.vertexCount ); } + Profiler.EndSample(); // Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local) @@ -310,13 +352,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(); @@ -330,6 +378,7 @@ namespace Coffee.UIExtensions workerMesh.bounds = bounds; _lastBounds = bounds; } + Profiler.EndSample(); @@ -342,7 +391,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); @@ -353,6 +402,7 @@ namespace Coffee.UIExtensions { workerMesh.Clear(); } + canvasRenderer.SetMesh(workerMesh); Profiler.EndSample(); @@ -365,7 +415,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; @@ -373,6 +424,7 @@ namespace Coffee.UIExtensions s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0); } } + Profiler.EndSample(); s_Renderers.Clear(); @@ -384,42 +436,20 @@ 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. + /// Call to update the geometry of the Graphic onto the CanvasRenderer. /// protected override void UpdateGeometry() { } - + 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; UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this); onCullStateChanged.Invoke(cull); @@ -449,8 +479,8 @@ namespace Coffee.UIExtensions { case ParticleSystemSimulationSpace.World: return Matrix4x4.Translate(psPos) - * Matrix4x4.Scale(scale) - * Matrix4x4.Translate(-psPos); + * Matrix4x4.Scale(scale) + * Matrix4x4.Translate(-psPos); } } #endif @@ -459,30 +489,31 @@ 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(); } } /// - /// For world simulation, interpolate particle positions when the screen size is changed. + /// For world simulation, interpolate particle positions when the screen size is changed. /// /// /// 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; @@ -491,13 +522,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. @@ -505,6 +540,7 @@ namespace Coffee.UIExtensions _prevScale = scale; _prevPsPos = psPos; } + _prevScreenSize = screenSize; } @@ -517,7 +553,7 @@ namespace Coffee.UIExtensions ? Time.unscaledDeltaTime : Time.deltaTime; - // Prewarm: + // Prewarm: if (0 < deltaTime && _prewarm) { deltaTime += main.duration; @@ -547,13 +583,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); } @@ -569,7 +606,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); @@ -597,7 +635,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; @@ -605,12 +645,13 @@ 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); } s_Mpb.Clear(); } } -} \ No newline at end of file +} 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); + } + } + } }