pull/289/head
mob-sakai 2023-08-17 09:43:02 +09:00
parent 35325c8899
commit 3df190382a
33 changed files with 1596 additions and 1752 deletions

View File

@ -1,85 +1,87 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Coffee.UIExtensions;
using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;
using Object = UnityEngine.Object; using Object = UnityEngine.Object;
public class CFX_Demo_With_UIParticle : MonoBehaviour namespace Coffee.UIExtensions.Demo
{ {
private UIParticle UiParticle; public class CFX_Demo_With_UIParticle : MonoBehaviour
private Toggle spawnOnUI;
private MonoBehaviour demo;
// Start is called before the first frame update
private void Start()
{ {
UiParticle = GetComponentInChildren<UIParticle>(); private MonoBehaviour _demo;
spawnOnUI = GetComponentInChildren<Toggle>(); private Toggle _spawnOnUI;
private UIParticle _uiParticle;
demo = FindObjectOfType("CFX_Demo_New") as MonoBehaviour // Start is called before the first frame update
?? FindObjectOfType("WFX_Demo_New") as MonoBehaviour; private void Start()
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)
{ {
Destroy(child.gameObject); _uiParticle = GetComponentInChildren<UIParticle>();
_spawnOnUI = GetComponentInChildren<Toggle>();
_demo = FindObjectOfType("CFX_Demo_New") as MonoBehaviour
?? FindObjectOfType("WFX_Demo_New") as MonoBehaviour;
SetCanvasWidth(800);
SetCanvasRenderOverlay(true);
} }
var particle = demo.GetType() // Update is called once per frame
.GetMethod("spawnParticle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) private void Update()
.Invoke(demo, new object[0]) as GameObject;
particle.transform.localScale = Vector3.one;
UiParticle.SetParticleSystemInstance(particle);
}
public void SetCanvasWidth(int width)
{
var scaler = GetComponentInParent<CanvasScaler>();
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<Canvas>();
if (enable)
{ {
canvas.renderMode = RenderMode.ScreenSpaceOverlay; if (!_spawnOnUI.isOn || !_demo || !Input.GetMouseButtonDown(0)) return;
}
else
{
canvas.worldCamera = Camera.main;
canvas.renderMode = RenderMode.ScreenSpaceCamera;
canvas.planeDistance = 5;
}
}
public void LoadScene(string scene) foreach (Transform child in _uiParticle.transform)
{ {
SceneManager.LoadScene(scene); Destroy(child.gameObject);
}
var particle = _demo.GetType()
.GetMethod("spawnParticle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
?.Invoke(_demo, Array.Empty<object>()) 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<CanvasScaler>();
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<Canvas>();
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);
}
} }
} }

View File

@ -1,25 +1,31 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
namespace Coffee.UIExtensions.Demo namespace Coffee.UIExtensions.Demo
{ {
public class CopyItemOnStart : MonoBehaviour public class CopyItemOnStart : MonoBehaviour
{ {
public GameObject origin; [FormerlySerializedAs("origin")]
public int count; [SerializeField]
private GameObject m_Origin;
[FormerlySerializedAs("count")]
[SerializeField]
private int m_Count;
private void Start() private void Start()
{ {
if (!origin) return; if (!m_Origin) return;
origin.SetActive(false); m_Origin.SetActive(false);
var parent = origin.transform.parent; var parent = m_Origin.transform.parent;
for (var i = 0; i < count; i++) for (var i = 0; i < m_Count; i++)
{ {
var go = Instantiate(origin, parent, false); var go = Instantiate(m_Origin, parent, false);
go.name = string.Format("{0} {1}", origin.name, i + 1); go.name = $"{m_Origin.name} {i + 1}";
go.hideFlags = HideFlags.DontSave; go.hideFlags = HideFlags.DontSave;
go.SetActive(true); go.SetActive(true);
} }
} }
} }
} }

View File

@ -1,25 +1,31 @@
using UnityEngine; using System;
using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.Serialization;
public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{ {
public enum Target [SerializeField]
{ private Target m_Target;
Self,
Parent,
Custom,
}
private RectTransform rectTransform; [SerializeField]
private Canvas canvas; private Transform m_CustomTarget;
public Target m_Target;
public Transform m_CustomTarget; [FormerlySerializedAs("ex2")]
public bool ex2; [SerializeField]
private bool m_UseCanvasScale;
private Canvas _canvas;
private RectTransform _rectTransform;
private void OnEnable() private void OnEnable()
{ {
rectTransform = GetComponent<RectTransform>(); _rectTransform = GetComponent<RectTransform>();
canvas = GetComponentInParent<Canvas>(); _canvas = GetComponentInParent<Canvas>();
}
public void OnBeginDrag(PointerEventData eventData)
{
} }
public void OnDrag(PointerEventData eventData) public void OnDrag(PointerEventData eventData)
@ -29,57 +35,59 @@ public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler,
switch (m_Target) switch (m_Target)
{ {
case Target.Self: case Target.Self:
rectTransform.localPosition += delta; _rectTransform.localPosition += delta;
break; break;
case Target.Parent: case Target.Parent:
rectTransform.parent.localPosition += delta; _rectTransform.parent.localPosition += delta;
break; break;
case Target.Custom: case Target.Custom:
rectTransform.localPosition += delta; _rectTransform.localPosition += delta;
if (m_CustomTarget) if (m_CustomTarget)
{ {
if (ex2) if (m_UseCanvasScale)
delta.Scale(canvas.rootCanvas.transform.localScale); {
delta.Scale(_canvas.rootCanvas.transform.localScale);
}
m_CustomTarget.localPosition += delta; m_CustomTarget.localPosition += delta;
} }
break; break;
} }
} }
public void OnBeginDrag(PointerEventData eventData)
{
}
public void OnEndDrag(PointerEventData eventData) public void OnEndDrag(PointerEventData eventData)
{ {
} }
private Vector2 GetLocalDelta(Vector2 evDelta) private Vector2 GetLocalDelta(Vector2 evDelta)
{ {
switch (canvas.renderMode) switch (_canvas.renderMode)
{ {
case RenderMode.ScreenSpaceOverlay: case RenderMode.ScreenSpaceOverlay:
{ {
var zero = transform.InverseTransformPoint(Vector2.zero); var zero = transform.InverseTransformPoint(Vector2.zero);
var delta = transform.InverseTransformPoint(evDelta); var delta = transform.InverseTransformPoint(evDelta);
return delta - zero; return delta - zero;
} }
case RenderMode.ScreenSpaceCamera: 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: case RenderMode.WorldSpace:
{ {
Vector3 zero, delta; RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, Vector2.zero,
RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, Vector2.zero, canvas.worldCamera, out zero); _canvas.worldCamera, out var zero);
RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, evDelta, canvas.worldCamera, out delta); RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, evDelta,
return delta - zero; _canvas.worldCamera, out var delta);
} return delta - zero;
}
default: default:
throw new System.NotSupportedException(); throw new NotSupportedException();
} }
} }
}
private enum Target
{
Self,
Parent,
Custom
}
}

View File

@ -1,14 +1,18 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI; using UnityEngine.UI;
namespace Coffee.UIExtensions.Demo namespace Coffee.UIExtensions.Demo
{ {
public class UIParticle_Demo : MonoBehaviour public class UIParticle_Demo : MonoBehaviour
{ {
public Canvas root; [FormerlySerializedAs("root")]
[SerializeField]
private Canvas m_RootCanvas;
private int _width;
private int _height; private int _height;
private int _score;
private int _width;
private void Start() private void Start()
{ {
@ -24,11 +28,18 @@ namespace Coffee.UIExtensions.Demo
case RuntimePlatform.WindowsPlayer: case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.LinuxPlayer: case RuntimePlatform.LinuxPlayer:
if (Screen.width == _width && Screen.height == _height) if (Screen.width == _width && Screen.height == _height)
{
Screen.SetResolution(_height, _width, Screen.fullScreen); Screen.SetResolution(_height, _width, Screen.fullScreen);
}
else if (Screen.width == _height && Screen.height == _width) else if (Screen.width == _height && Screen.height == _width)
{
Screen.SetResolution(Mathf.Min(_width, _height), Mathf.Min(_width, _height), Screen.fullScreen); Screen.SetResolution(Mathf.Min(_width, _height), Mathf.Min(_width, _height), Screen.fullScreen);
}
else else
{
Screen.SetResolution(_width, _height, Screen.fullScreen); Screen.SetResolution(_width, _height, Screen.fullScreen);
}
break; break;
} }
} }
@ -38,27 +49,31 @@ namespace Coffee.UIExtensions.Demo
Screen.fullScreen = !Screen.fullScreen; Screen.fullScreen = !Screen.fullScreen;
} }
public void EnableAnimations(bool enabled) public void EnableAnimations(bool flag)
{ {
foreach (var animator in FindObjectsOfType<Animator>()) foreach (var animator in FindObjectsOfType<Animator>())
{ {
animator.enabled = enabled; animator.enabled = flag;
} }
} }
public void UIParticle_MeshSharing(bool enabled) public void UIParticle_MeshSharing(bool flag)
{ {
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true)) foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(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<UIParticle>(true)) foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(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<ParticleSystem>()) foreach (var p in FindObjectsOfType<ParticleSystem>())
{ {
var main = ps.main; var main = p.main;
main.simulationSpace = enabled ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local; 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<ParticleSystem>()) foreach (var p in ps.GetComponentsInChildren<ParticleSystem>())
{ {
var main = ps.main; var main = p.main;
main.simulationSpace = ParticleSystemSimulationSpace.World; 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<ParticleSystem>()) foreach (var p in ps.GetComponentsInChildren<ParticleSystem>())
{ {
var main = ps.main; var main = p.main;
main.simulationSpace = ParticleSystemSimulationSpace.Local; 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) public void ParticleSystem_SetScale(float scale)
@ -127,41 +144,37 @@ namespace Coffee.UIExtensions.Demo
attractor.movement = UIParticleAttractor.Movement.Sphere; attractor.movement = UIParticleAttractor.Movement.Sphere;
} }
int score = 0;
public void UIParticleAttractor_OnAttract(Text scoreText) public void UIParticleAttractor_OnAttract(Text scoreText)
{ {
score++; _score++;
scoreText.text = score.ToString(); scoreText.text = _score.ToString();
scoreText.GetComponent<Animator>().Play(0); scoreText.GetComponent<Animator>().Play(0);
} }
public void Canvas_WorldSpace(bool flag) public void Canvas_WorldSpace(bool flag)
{ {
if (flag) if (!flag) return;
{
var canvas = FindObjectOfType<Canvas>(); var canvas = FindObjectOfType<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceCamera; canvas.renderMode = RenderMode.ScreenSpaceCamera;
canvas.renderMode = RenderMode.WorldSpace; canvas.renderMode = RenderMode.WorldSpace;
canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0)); canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0));
}
} }
public void Canvas_CameraSpace(bool flag) public void Canvas_CameraSpace(bool flag)
{ {
if (flag) if (!flag) return;
{
var canvas = FindObjectOfType<Canvas>(); var canvas = FindObjectOfType<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceCamera; canvas.renderMode = RenderMode.ScreenSpaceCamera;
}
} }
public void Canvas_Overlay(bool flag) public void Canvas_Overlay(bool flag)
{ {
if (flag) if (!flag) return;
{
var canvas = FindObjectOfType<Canvas>(); var canvas = FindObjectOfType<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.renderMode = RenderMode.ScreenSpaceOverlay;
}
} }
} }
} }

View File

@ -1,30 +1,37 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
namespace Coffee.UIExtensions.Demo namespace Coffee.UIExtensions.Demo
{ {
public class UIParticle_Demo_UIParticleController : MonoBehaviour 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<UIParticle>(true)) foreach (var uip in m_RootTransform.GetComponentsInChildren<UIParticle>(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<UIParticle>(true)) foreach (var uip in m_RootTransform.GetComponentsInChildren<UIParticle>(true))
{ {
uip.groupMaxId = enabled ? 4 : 0; uip.groupMaxId = flag
? 4
: 0;
} }
} }
public void UIParticle_Scale(float scale) public void UIParticle_Scale(float scale)
{ {
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true)) foreach (var uip in m_RootTransform.GetComponentsInChildren<UIParticle>(true))
{ {
uip.scale = scale; uip.scale = scale;
} }

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 70069a8db1df148ae8b4c8108c079acf guid: d07e6c2670f164cf7939ab011061a9bf
TrueTypeFontImporter: TrueTypeFontImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 4 serializedVersion: 4
@ -8,9 +8,9 @@ TrueTypeFontImporter:
characterSpacing: 0 characterSpacing: 0
characterPadding: 1 characterPadding: 1
includeFontData: 1 includeFontData: 1
fontName: Falstin fontName: Share Tech Mono
fontNames: fontNames:
- Falstin - Share Tech Mono
fallbackFontReferences: [] fallbackFontReferences: []
customCharacters: customCharacters:
fontRenderingMode: 1 fontRenderingMode: 1

View File

@ -127,7 +127,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -206,7 +206,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -285,7 +285,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -366,7 +366,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -516,7 +516,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -595,7 +595,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -736,7 +736,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 16 m_FontSize: 16
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -889,7 +889,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 16 m_FontSize: 16
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -1042,7 +1042,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -1206,7 +1206,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 16 m_FontSize: 16
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -1418,7 +1418,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Interval: 0.5 m_Interval: 0.5
m_Precision: 2 m_Precision: 2
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_Opened: 1 m_Opened: 1
m_FoldoutObject: {fileID: 8720459857733317289} m_FoldoutObject: {fileID: 8720459857733317289}
m_OpenButton: {fileID: 2149219299373497733} m_OpenButton: {fileID: 2149219299373497733}
@ -1502,7 +1502,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 16 m_FontSize: 16
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0
@ -1695,7 +1695,7 @@ MonoBehaviour:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_FontData: m_FontData:
m_Font: {fileID: 12800000, guid: 70069a8db1df148ae8b4c8108c079acf, type: 3} m_Font: {fileID: 12800000, guid: d07e6c2670f164cf7939ab011061a9bf, type: 3}
m_FontSize: 14 m_FontSize: 14
m_FontStyle: 0 m_FontStyle: 0
m_BestFit: 0 m_BestFit: 0

View File

@ -1,10 +1,11 @@
using System; using System;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Serialization; using UnityEngine.Serialization;
using UnityEngine.UI; using UnityEngine.UI;
#if UNITY_EDITOR #if UNITY_EDITOR
using UnityEditor; using UnityEditor;
using UnityEditorInternal;
#endif #endif
namespace Coffee.NanoMonitor namespace Coffee.NanoMonitor
@ -13,24 +14,29 @@ namespace Coffee.NanoMonitor
[CustomEditor(typeof(NanoMonitor))] [CustomEditor(typeof(NanoMonitor))]
internal class NanoMonitorEditor : Editor internal class NanoMonitorEditor : Editor
{ {
private UnityEditorInternal.ReorderableList m_MonitorItemList; private ReorderableList _monitorItemList;
private void OnEnable() private void OnEnable()
{ {
var items = serializedObject.FindProperty("m_CustomMonitorItems"); var items = serializedObject.FindProperty("m_CustomMonitorItems");
m_MonitorItemList = new UnityEditorInternal.ReorderableList(serializedObject, items) _monitorItemList = new ReorderableList(serializedObject, items)
{ {
draggable = false, 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, _, __) => 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; var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 80; 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; 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(); base.OnInspectorGUI();
m_MonitorItemList.DoLayoutList(); _monitorItemList.DoLayoutList();
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
} }
} }
@ -52,38 +58,50 @@ namespace Coffee.NanoMonitor
// Serialize Members. // Serialize Members.
//################################ //################################
// Settings // Settings
[Header("Settings")] [SerializeField] [Range(0.01f, 2f)] [Header("Settings")]
[SerializeField]
[Range(0.01f, 2f)]
private float m_Interval = 1f; private float m_Interval = 1f;
[SerializeField] [Range(0, 3)] private int m_Precision = 2; [SerializeField]
[SerializeField] private Font m_Font; [Range(0, 3)]
private int m_Precision = 2;
[SerializeField]
private Font m_Font;
// Foldout // Foldout
[Header("Foldout")] [SerializeField] private bool m_Opened = false; [Header("Foldout")]
[SerializeField]
private bool m_Opened;
[FormerlySerializedAs("m_Collapse")] [SerializeField] [FormerlySerializedAs("m_Collapse")]
private GameObject m_FoldoutObject = null; [SerializeField]
private GameObject m_FoldoutObject;
[SerializeField] private Button m_OpenButton = null; [SerializeField]
[SerializeField] private Button m_CloseButton = null; private Button m_OpenButton;
[SerializeField]
private Button m_CloseButton;
// View // View
[Header("View")] [SerializeField] private MonitorUI m_Fps = null; [Header("View")]
[SerializeField] private MonitorUI m_Gc = null; [SerializeField]
[SerializeField] private MonitorUI m_MonoUsage = null; private MonitorUI m_Fps;
[SerializeField] private MonitorUI m_UnityUsage = null;
[HideInInspector] [SerializeField] private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0]; [SerializeField]
private MonitorUI m_Gc;
[SerializeField]
private MonitorUI m_MonoUsage;
//################################ [SerializeField]
// Public Members. private MonitorUI m_UnityUsage;
//################################
public void Clean() [HideInInspector]
{ [SerializeField]
Resources.UnloadUnusedAssets(); private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0];
GC.Collect();
}
//################################ //################################
@ -93,44 +111,75 @@ namespace Coffee.NanoMonitor
private double _fpsElapsed; private double _fpsElapsed;
private int _frames; 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; _frames = 0;
_elapsed = m_Interval; _elapsed %= m_Interval;
_fpsElapsed = 0; _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 #if UNITY_EDITOR
private void OnValidate() private void OnValidate()
{ {
@ -264,5 +242,55 @@ namespace Coffee.NanoMonitor
} }
} }
#endif #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);
}
}
} }
} }

View File

@ -2,14 +2,17 @@
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace Coffee.NanoMonitor{ namespace Coffee.NanoMonitor
{
public class FixedFont public class FixedFont
{ {
private readonly UIVertex[] _tmpVerts = new UIVertex[4]; private const string k_Characters =
private static readonly Dictionary<Font, FixedFont> _fonts = new Dictionary<Font, FixedFont>(); "_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
private static readonly TextGenerator _textGenerator = new TextGenerator(100);
private static TextGenerationSettings _settings = new TextGenerationSettings private static readonly Dictionary<Font, FixedFont> s_Fonts = new Dictionary<Font, FixedFont>();
private static readonly TextGenerator s_TextGenerator = new TextGenerator(100);
private static TextGenerationSettings s_Settings = new TextGenerationSettings
{ {
scaleFactor = 1, scaleFactor = 1,
horizontalOverflow = HorizontalWrapMode.Overflow, horizontalOverflow = HorizontalWrapMode.Overflow,
@ -19,25 +22,33 @@ namespace Coffee.NanoMonitor{
color = Color.white color = Color.white
}; };
private int _resolution = 0;
private readonly Font _font; private readonly Font _font;
private UIVertex[] _verts; private readonly UIVertex[] _tmpVerts = new UIVertex[4];
private UICharInfo[] _charInfos; private UICharInfo[] _charInfos;
private int _resolution;
private UIVertex[] _verts;
private FixedFont(Font font) private FixedFont(Font font)
{ {
_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) public static FixedFont GetOrCreate(Font font)
{ {
if (font == null) return null; 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); data = new FixedFont(font);
_fonts.Add(font, data); s_Fonts.Add(font, data);
return data; return data;
} }
@ -61,18 +72,20 @@ namespace Coffee.NanoMonitor{
if (_resolution == currentResolution) return; if (_resolution == currentResolution) return;
_resolution = currentResolution; _resolution = currentResolution;
_settings.font = _font; s_Settings.font = _font;
_textGenerator.Invalidate(); s_TextGenerator.Invalidate();
_textGenerator.Populate("_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", _settings); s_TextGenerator.Populate(k_Characters, s_Settings);
_verts = _textGenerator.GetVerticesArray(); _verts = s_TextGenerator.GetVerticesArray();
_charInfos = _textGenerator.GetCharactersArray(); _charInfos = s_TextGenerator.GetCharactersArray();
float offsetX = 0; float offsetX = 0;
for (var i = 0; i < _verts.Length; i++) for (var i = 0; i < _verts.Length; i++)
{ {
if ((i & 3) == 0) if ((i & 3) == 0)
{
offsetX = _verts[i].position.x; offsetX = _verts[i].position.x;
}
var v = _verts[i]; var v = _verts[i];
v.position -= new Vector3(offsetX, 0); v.position -= new Vector3(offsetX, 0);
@ -118,18 +131,27 @@ namespace Coffee.NanoMonitor{
for (var i = 0; i < 4; i++) for (var i = 0; i < 4; i++)
{ {
_tmpVerts[i] = new UIVertex(); _tmpVerts[i] = new UIVertex
_tmpVerts[i].uv0 = uv; {
_tmpVerts[i].color = color; uv0 = uv,
color = color
};
if (i == 0) switch (i)
_tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset; {
else if (i == 1) case 0:
_tmpVerts[i].position = new Vector2(-size.x, size.y) + offset; _tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset;
else if (i == 2) break;
_tmpVerts[i].position = new Vector2(size.x, size.y) + offset; case 1:
else _tmpVerts[i].position = new Vector2(-size.x, size.y) + offset;
_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); toFill.AddUIVertexQuad(_tmpVerts);

View File

@ -1,50 +1,46 @@
using System.Text; using System.Text;
using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace Coffee.NanoMonitor{ namespace Coffee.NanoMonitor
{
#if UNITY_EDITOR #if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(MonitorUI))] [CustomEditor(typeof(MonitorUI))]
public class MonitorTextEditor : Editor public class MonitorTextEditor : Editor
{ {
private SerializedProperty m_Mode; private SerializedProperty _color;
private SerializedProperty m_TextAnchor; private SerializedProperty _font;
private SerializedProperty m_FontSize; private SerializedProperty _fontSize;
private SerializedProperty m_Font; private SerializedProperty _mode;
private SerializedProperty m_Text; private SerializedProperty _text;
private SerializedProperty m_Color; private SerializedProperty _textAnchor;
private void OnEnable() private void OnEnable()
{ {
m_Mode = serializedObject.FindProperty("m_Mode"); _mode = serializedObject.FindProperty("m_Mode");
_text = serializedObject.FindProperty("m_Text");
m_Text = serializedObject.FindProperty("m_Text"); _color = serializedObject.FindProperty("m_Color");
m_Color = serializedObject.FindProperty("m_Color");
var fontData = serializedObject.FindProperty("m_FontData"); var fontData = serializedObject.FindProperty("m_FontData");
m_FontSize = fontData.FindPropertyRelative("m_FontSize"); _fontSize = fontData.FindPropertyRelative("m_FontSize");
m_Font = fontData.FindPropertyRelative("m_Font"); _font = fontData.FindPropertyRelative("m_Font");
m_TextAnchor = serializedObject.FindProperty("m_TextAnchor"); _textAnchor = serializedObject.FindProperty("m_TextAnchor");
} }
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
serializedObject.Update(); serializedObject.Update();
EditorGUILayout.PropertyField(m_Mode); EditorGUILayout.PropertyField(_mode);
if ((MonitorUI.Mode) m_Mode.intValue == MonitorUI.Mode.Text) if ((MonitorUI.Mode)_mode.intValue == MonitorUI.Mode.Text)
{ {
EditorGUILayout.PropertyField(m_Text); EditorGUILayout.PropertyField(_text);
EditorGUILayout.PropertyField(m_FontSize); EditorGUILayout.PropertyField(_fontSize);
EditorGUILayout.PropertyField(m_TextAnchor); EditorGUILayout.PropertyField(_textAnchor);
EditorGUILayout.PropertyField(_font);
//EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.PropertyField(m_Font);
//EditorGUI.EndDisabledGroup();
} }
EditorGUILayout.PropertyField(m_Color); EditorGUILayout.PropertyField(_color);
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
} }
@ -56,7 +52,7 @@ namespace Coffee.NanoMonitor{
public enum Mode public enum Mode
{ {
Text, Text,
Fill, Fill
} }
public enum TextAnchor public enum TextAnchor
@ -74,26 +70,38 @@ namespace Coffee.NanoMonitor{
[SerializeField] private TextAnchor m_TextAnchor; [SerializeField] private TextAnchor m_TextAnchor;
//################################
// Private Members.
//################################
private readonly StringBuilder _sb = new StringBuilder(64);
//################################ //################################
// Public Members. // Public Members.
//################################ //################################
public override string text public override string text
{ {
get => m_StringBuilder.ToString(); get
{
return _sb.ToString();
}
set set
{ {
m_Text = value; m_Text = value;
if (m_StringBuilder.IsEqual(m_Text)) return; if (_sb.IsEqual(m_Text)) return;
m_StringBuilder.Length = 0; _sb.Length = 0;
m_StringBuilder.Append(m_Text); _sb.Append(m_Text);
SetVerticesDirty(); SetVerticesDirty();
} }
} }
public TextAnchor textAnchor public TextAnchor textAnchor
{ {
get => m_TextAnchor; get
{
return m_TextAnchor;
}
set set
{ {
if (m_TextAnchor == value) return; if (m_TextAnchor == value) return;
@ -105,44 +113,11 @@ namespace Coffee.NanoMonitor{
public override bool raycastTarget public override bool raycastTarget
{ {
get => m_Mode == Mode.Fill; get
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)
{ {
fontData.Invalidate(); return m_Mode == Mode.Fill;
fontData.UpdateFont();
} }
set { }
} }
@ -151,19 +126,17 @@ namespace Coffee.NanoMonitor{
//################################ //################################
protected override void OnEnable() protected override void OnEnable()
{ {
//NaNanoMonitortings.Instance.onFontChanged += UpdateFont;
RegisterDirtyMaterialCallback(UpdateFont); RegisterDirtyMaterialCallback(UpdateFont);
base.OnEnable(); base.OnEnable();
raycastTarget = false; raycastTarget = false;
maskable = false; maskable = false;
m_StringBuilder.Length = 0; _sb.Length = 0;
m_StringBuilder.Append(m_Text); _sb.Append(m_Text);
} }
protected override void OnDisable() protected override void OnDisable()
{ {
//NanNanoMonitorings.Instance.onFontChanged -= UpdateFont;
UnregisterDirtyMaterialCallback(UpdateFont); UnregisterDirtyMaterialCallback(UpdateFont);
base.OnDisable(); base.OnDisable();
@ -174,14 +147,38 @@ namespace Coffee.NanoMonitor{
{ {
base.OnValidate(); base.OnValidate();
if (!m_StringBuilder.IsEqual(m_Text)) if (!_sb.IsEqual(m_Text))
{ {
m_StringBuilder.Length = 0; _sb.Length = 0;
m_StringBuilder.Append(m_Text); _sb.Append(m_Text);
} }
} }
#endif #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) protected override void OnPopulateMesh(VertexHelper toFill)
{ {
toFill.Clear(); toFill.Clear();
@ -197,7 +194,7 @@ namespace Coffee.NanoMonitor{
return; return;
} }
var scale = (float) fontSize / fontData.fontSize; var scale = (float)fontSize / fontData.fontSize;
float offset = 0; float offset = 0;
switch (textAnchor) switch (textAnchor)
{ {
@ -205,20 +202,26 @@ namespace Coffee.NanoMonitor{
offset = rectTransform.rect.xMin; offset = rectTransform.rect.xMin;
break; break;
case TextAnchor.Center: case TextAnchor.Center:
for (var i = 0; i < m_StringBuilder.Length; i++) for (var i = 0; i < _sb.Length; i++)
offset = fontData.Layout(m_StringBuilder[i], offset, scale); {
offset = fontData.Layout(_sb[i], offset, scale);
}
offset = -offset / 2; offset = -offset / 2;
break; break;
case TextAnchor.Right: case TextAnchor.Right:
for (var i = 0; i < m_StringBuilder.Length; i++) for (var i = 0; i < _sb.Length; i++)
offset = fontData.Layout(m_StringBuilder[i], offset, scale); {
offset = fontData.Layout(_sb[i], offset, scale);
}
offset = rectTransform.rect.xMax - offset; offset = rectTransform.rect.xMax - offset;
break; 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);
} }
} }

View File

@ -1,55 +0,0 @@
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Coffee.MiniProfiler
{
internal class MiniProfilerSettings : ScriptableSettings<MiniProfilerSettings>
{
[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<Font>("Arial.ttf");
}
[UnityEditor.SettingsProvider]
private static UnityEditor.SettingsProvider CreateSettingsProvider() => new ScriptableSettingsProvider<MiniProfilerSettings>();
#endif
}
}

View File

@ -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:

View File

@ -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<T> : ScriptableSettings
where T : ScriptableSettings<T>
{
//################################
// 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<T>()
.FirstOrDefault() ?? CreateInstance<T>();
}
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<T>().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<T>();
}
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<T> : ScriptableSingleton<T>
where T : ScriptablePreferenceSettings<T>
{
}
#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<T> : SettingsProvider where T : ScriptableSettings<T>
{
public ScriptableSettingsProvider(string path) : base(path)
{
}
public ScriptableSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T)))
{
}
protected SerializedObject serializedObject { get; private set; }
protected ScriptableSettings<T> target { get; private set; }
public sealed override void OnGUI(string searchContext)
{
if (!target)
{
target = ScriptableSettings<T>.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<T> : SettingsProvider where T : ScriptableSettings<T>
{
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<T> target { get; private set; }
public sealed override void OnGUI(string searchContext)
{
if (!target)
{
target = ScriptableSettings<T>.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
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6ea9606f69cee413e9f96f52de99fa5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,4 +1,5 @@
using UnityEngine; using System;
using UnityEngine;
#if UNITY_EDITOR #if UNITY_EDITOR
using UnityEditor; using UnityEditor;
#endif #endif
@ -11,12 +12,17 @@ namespace Coffee.NanoMonitor
{ {
public override void OnGUI(Rect p, SerializedProperty property, GUIContent label) 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")); var pos = new Rect(p.x, p.y + 18 * 0, p.width, 16);
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 1, p.width, 16), property.FindPropertyRelative("m_Format")); EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Text"));
pos.y += 18;
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Format"));
pos.y += 18;
EditorGUI.indentLevel++; EditorGUI.indentLevel++;
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 2, p.width, 16), property.FindPropertyRelative("m_Arg0")); EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg0"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 3, p.width, 16), property.FindPropertyRelative("m_Arg1")); pos.y += 18;
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 4, p.width, 16), property.FindPropertyRelative("m_Arg2")); EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg1"));
pos.y += 18;
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg2"));
EditorGUI.indentLevel--; EditorGUI.indentLevel--;
property.serializedObject.ApplyModifiedProperties(); property.serializedObject.ApplyModifiedProperties();
@ -29,19 +35,21 @@ namespace Coffee.NanoMonitor
} }
#endif #endif
[System.Serializable] [Serializable]
public class CustomMonitorItem public class CustomMonitorItem
{ {
[SerializeField] private MonitorUI m_Text = null; [SerializeField] private MonitorUI m_Text;
[SerializeField] private string m_Format = ""; [SerializeField] private string m_Format = "";
[SerializeField] private NumericProperty m_Arg0 = null; [SerializeField] private NumericProperty m_Arg0;
[SerializeField] private NumericProperty m_Arg1 = null; [SerializeField] private NumericProperty m_Arg1;
[SerializeField] private NumericProperty m_Arg2 = null; [SerializeField] private NumericProperty m_Arg2;
public void UpdateText() public void UpdateText()
{ {
if (m_Text) if (m_Text)
{
m_Text.SetText(m_Format, m_Arg0.Get(), m_Arg1.Get(), m_Arg2.Get()); m_Text.SetText(m_Format, m_Arg0.Get(), m_Arg1.Get(), m_Arg2.Get());
}
} }
} }
} }

View File

@ -2,12 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using UnityEngine;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor; using UnityEditor;
using UnityEngine;
#endif
namespace Coffee.NanoMonitor namespace Coffee.NanoMonitor
{ {
@ -20,39 +16,45 @@ namespace Coffee.NanoMonitor
private static readonly Dictionary<Type, string> s_SupportedTypes = new Dictionary<Type, string> private static readonly Dictionary<Type, string> s_SupportedTypes = new Dictionary<Type, string>
{ {
{typeof(bool), "bool"}, { typeof(bool), "bool" },
{typeof(sbyte), "sbyte"}, { typeof(sbyte), "sbyte" },
{typeof(short), "short"}, { typeof(short), "short" },
{typeof(int), "int"}, { typeof(int), "int" },
{typeof(long), "long"}, { typeof(long), "long" },
{typeof(byte), "byte"}, { typeof(byte), "byte" },
{typeof(ushort), "ushort"}, { typeof(ushort), "ushort" },
{typeof(uint), "uint"}, { typeof(uint), "uint" },
{typeof(ulong), "ulong"}, { typeof(ulong), "ulong" },
{typeof(float), "float"}, { typeof(float), "float" },
{typeof(double), "double"}, { typeof(double), "double" },
{typeof(decimal), "decimal"}, { typeof(decimal), "decimal" }
}; };
private static void Init() private static void Init()
{ {
if (s_PropertyMenu != null) return; if (s_PropertyMenu != null) return;
const BindingFlags bindingFlags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.GetProperty;
var properties = AppDomain.CurrentDomain.GetAssemblies() var properties = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes()) .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)) .Where(pi => pi.GetMethod != null && s_SupportedTypes.ContainsKey(pi.PropertyType))
.OrderBy(pi => ConvertToMenuItem(pi, false)) .OrderBy(pi => ConvertToMenuItem(pi, false))
.ToArray(); .ToArray();
s_PropertyMenu = new GenericMenu(); 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("No Property"), false,
s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, ()=>{}); arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null);
s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, () => { });
s_PropertyMenu.AddSeparator(""); s_PropertyMenu.AddSeparator("");
foreach (var pi in properties) 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; var type = p.DeclaringType;
if (type == null) return ""; 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 typeName = type.FullName;
var asmName = type.Assembly.GetName().Name; var asmName = type.Assembly.GetName().Name;
if (asmName == "UnityEngine.CoreModule") if (asmName == "UnityEngine.CoreModule")
{
asmName = "UnityEngine"; asmName = "UnityEngine";
}
return propertyType return propertyType
? $"{category}{asmName}/{typeName}/{s_SupportedTypes[p.PropertyType]} {p.Name}" ? $"{category}{asmName}/{typeName}/{s_SupportedTypes[p.PropertyType]} {p.Name}"
: $"{category}{asmName}/{typeName}/{p.Name}"; : $"{category}{asmName}/{typeName}/{p.Name}";
@ -84,7 +92,9 @@ namespace Coffee.NanoMonitor
{ {
s_OnMenuSelected = p => 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(); property.serializedObject.ApplyModifiedProperties();
}; };
s_PropertyMenu.DropDown(position); s_PropertyMenu.DropDown(position);
@ -104,6 +114,22 @@ namespace Coffee.NanoMonitor
[SerializeField] private string m_Path = ""; [SerializeField] private string m_Path = "";
//################################
// Private Members.
//################################
private Func<double> _get;
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
var pInfo = GetPropertyInfo(m_Path);
_get = CreateFunc(pInfo?.GetMethod);
}
//################################ //################################
// Public Members. // Public Members.
//################################ //################################
@ -112,12 +138,6 @@ namespace Coffee.NanoMonitor
return _get?.Invoke() ?? -1; return _get?.Invoke() ?? -1;
} }
//################################
// Private Members.
//################################
private Func<double> _get = null;
private static PropertyInfo GetPropertyInfo(string path) private static PropertyInfo GetPropertyInfo(string path)
{ {
var p = path.Split(';'); var p = path.Split(';');
@ -126,14 +146,14 @@ namespace Coffee.NanoMonitor
var type = Type.GetType(p[0]); var type = Type.GetType(p[0]);
if (type == null) 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; return null;
} }
var pInfo = type.GetProperty(p[1], BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static); var pInfo = type.GetProperty(p[1], BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static);
if (pInfo == null) 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; return pInfo;
@ -145,55 +165,72 @@ namespace Coffee.NanoMonitor
switch (Type.GetTypeCode(mInfo.ReturnType)) switch (Type.GetTypeCode(mInfo.ReturnType))
{ {
case TypeCode.Boolean: case TypeCode.Boolean:
var f_bool = (Func<bool>) mInfo.CreateDelegate(typeof(Func<bool>)); {
return () => f_bool() ? 1 : 0; var func = (Func<bool>)mInfo.CreateDelegate(typeof(Func<bool>));
return () => func() ? 1 : 0;
}
case TypeCode.Byte: case TypeCode.Byte:
var f_byte = (Func<byte>) mInfo.CreateDelegate(typeof(Func<byte>)); {
return () => f_byte(); var func = (Func<byte>)mInfo.CreateDelegate(typeof(Func<byte>));
return () => func();
}
case TypeCode.SByte: case TypeCode.SByte:
var f_sbyte = (Func<sbyte>) mInfo.CreateDelegate(typeof(Func<sbyte>)); {
return () => f_sbyte(); var func = (Func<sbyte>)mInfo.CreateDelegate(typeof(Func<sbyte>));
return () => func();
}
case TypeCode.UInt16: case TypeCode.UInt16:
var f_ushort = (Func<ushort>) mInfo.CreateDelegate(typeof(Func<ushort>)); {
return () => f_ushort(); var func = (Func<ushort>)mInfo.CreateDelegate(typeof(Func<ushort>));
return () => func();
}
case TypeCode.UInt32: case TypeCode.UInt32:
var f_uint = (Func<uint>) mInfo.CreateDelegate(typeof(Func<uint>)); {
return () => f_uint(); var func = (Func<uint>)mInfo.CreateDelegate(typeof(Func<uint>));
return () => func();
}
case TypeCode.UInt64: case TypeCode.UInt64:
var f_ulong = (Func<ulong>) mInfo.CreateDelegate(typeof(Func<ulong>)); {
return () => f_ulong(); var func = (Func<ulong>)mInfo.CreateDelegate(typeof(Func<ulong>));
return () => func();
}
case TypeCode.Int16: case TypeCode.Int16:
var f_short = (Func<short>) mInfo.CreateDelegate(typeof(Func<short>)); {
return () => f_short(); var func = (Func<short>)mInfo.CreateDelegate(typeof(Func<short>));
return () => func();
}
case TypeCode.Int32: case TypeCode.Int32:
var f_int = (Func<int>) mInfo.CreateDelegate(typeof(Func<int>)); {
return () => f_int(); var f = (Func<int>)mInfo.CreateDelegate(typeof(Func<int>));
return () => f();
}
case TypeCode.Int64: case TypeCode.Int64:
var f_long = (Func<long>) mInfo.CreateDelegate(typeof(Func<long>)); {
return () => f_long(); var f = (Func<long>)mInfo.CreateDelegate(typeof(Func<long>));
return () => f();
}
case TypeCode.Decimal: case TypeCode.Decimal:
var f_decimal = (Func<decimal>) mInfo.CreateDelegate(typeof(Func<decimal>)); {
return () => (double) f_decimal(); var f = (Func<decimal>)mInfo.CreateDelegate(typeof(Func<decimal>));
return () => (double)f();
}
case TypeCode.Double: case TypeCode.Double:
var f_double = (Func<double>) mInfo.CreateDelegate(typeof(Func<double>)); {
return f_double; var f = (Func<double>)mInfo.CreateDelegate(typeof(Func<double>));
return f;
}
case TypeCode.Single: case TypeCode.Single:
var f_float = (Func<float>) mInfo.CreateDelegate(typeof(Func<float>)); {
return () => f_float(); var f = (Func<float>)mInfo.CreateDelegate(typeof(Func<float>));
return () => f();
}
default: 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; return null;
}
} }
} }
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
var pInfo = GetPropertyInfo(m_Path);
_get = CreateFunc(pInfo?.GetMethod);
}
} }
} }

View File

@ -21,7 +21,8 @@ namespace Coffee.NanoMonitor
return true; 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++) 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); number = Math.Truncate(number);
var sign = number < 0; var sign = number < 0;
@ -68,8 +69,8 @@ namespace Coffee.NanoMonitor
var n = Math.Truncate(number % 10); var n = Math.Truncate(number % 10);
number /= 10; number /= 10;
sb.Append((char) (n + 48)); sb.Append((char)(n + 48));
} while (1 <= number || (sb.Length - startIndex) < padding); } while (1 <= number || sb.Length - startIndex < padding);
if (sign) if (sign)
{ {
@ -82,11 +83,12 @@ namespace Coffee.NanoMonitor
sb.Alignment(alignment, startIndex, endIndex); 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 integer = Math.Truncate(number);
var startIndex = sb.Length; var startIndex = sb.Length;
sb.AppendInteger(integer, padding, precision, 0); sb.AppendInteger(integer, padding, 0);
if (0 < precision) if (0 < precision)
{ {
@ -96,8 +98,8 @@ namespace Coffee.NanoMonitor
for (var p = 0; p < precision; p++) for (var p = 0; p < precision; p++)
{ {
number *= 10; number *= 10;
integer = (long) number; integer = (long)number;
sb.Append((char) (integer + 48)); sb.Append((char)(integer + 48));
number -= integer; number -= integer;
number = Math.Round(number, precision); number = Math.Round(number, precision);
} }
@ -106,20 +108,18 @@ namespace Coffee.NanoMonitor
sb.Alignment(alignment, startIndex, sb.Length - 1); 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) while (start < end)
{ {
var c = sb[start]; // swap
sb[start] = sb[end]; (sb[start], sb[end]) = (sb[end], sb[start]);
sb[end] = c;
start++; start++;
end--; 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; if (alignment == 0) return;
@ -129,9 +129,8 @@ namespace Coffee.NanoMonitor
sb.Append(' ', alignment - len); sb.Append(' ', alignment - len);
for (var i = 0; i < len; i++) for (var i = 0; i < len; i++)
{ {
var c = sb[end - i]; // swap
sb[end - i] = sb[start + alignment - i - 1]; (sb[end - i], sb[start + alignment - i - 1]) = (sb[start + alignment - i - 1], sb[end - i]);
sb[start + alignment - i - 1] = c;
} }
} }
else if (alignment < 0 && len < -alignment) 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; argIndex = -1;
padding = 0; padding = 0;

View File

@ -1,26 +1,35 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
namespace Coffee.UIExtensions.Demo namespace Coffee.UIExtensions.Demo
{ {
public class UIParticle_PerformanceDemo : MonoBehaviour public class UIParticle_PerformanceDemo : MonoBehaviour
{ {
public GameObject copyOrigin; [FormerlySerializedAs("copyOrigin")]
public int copyCount; [SerializeField]
public Canvas root; private GameObject m_CopyOrigin;
[FormerlySerializedAs("copyCount")]
[SerializeField]
public int m_CopyCount;
[FormerlySerializedAs("root")]
[SerializeField]
public Canvas m_RootCanvas;
private void Start() private void Start()
{ {
Application.targetFrameRate = 60; Application.targetFrameRate = 60;
if (copyOrigin) if (m_CopyOrigin)
{ {
copyOrigin.SetActive(false); m_CopyOrigin.SetActive(false);
var parent = copyOrigin.transform.parent; var parent = m_CopyOrigin.transform.parent;
for (var i = 0; i < copyCount; i++) for (var i = 0; i < m_CopyCount; i++)
{ {
var go = GameObject.Instantiate(copyOrigin, parent, false); var go = Instantiate(m_CopyOrigin, parent, false);
go.name = string.Format("{0} {1}", copyOrigin.name, i + 1); go.name = string.Format("{0} {1}", m_CopyOrigin.name, i + 1);
go.hideFlags = HideFlags.DontSave; go.hideFlags = HideFlags.DontSave;
go.SetActive(true); 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) foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(true))
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<Animator>())
{ {
animator.enabled = enabled; uip.enabled = flag;
} }
}
public void UIParticle_Enable(bool enabled) if (!flag)
{
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
{
uip.enabled = enabled;
}
if (!enabled)
{ {
foreach (var ps in FindObjectsOfType<ParticleSystem>()) foreach (var ps in FindObjectsOfType<ParticleSystem>())
{ {
@ -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<UIParticle>(true)) foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(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<UIParticle>(true)) foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(true))
{ {
uip.groupMaxId = enabled ? 4 : 0; uip.groupMaxId = flag
} ? 4
} : 0;
public void UIParticle_Scale(float scale)
{
foreach (var uip in FindObjectsOfType<UIParticle>())
{
uip.scale = scale;
}
}
public void ParticleSystem_WorldSpaseSimulation(bool enabled)
{
foreach (var ps in FindObjectsOfType<ParticleSystem>())
{
var main = ps.main;
main.simulationSpace = enabled ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local;
} }
} }
@ -102,34 +80,5 @@ namespace Coffee.UIExtensions.Demo
ps.transform.localScale = new Vector3(scale, scale, scale); ps.transform.localScale = new Vector3(scale, scale, scale);
} }
} }
public void Canvas_WorldSpace(bool flag)
{
if (flag)
{
var canvas = FindObjectOfType<Canvas>();
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>();
canvas.renderMode = RenderMode.ScreenSpaceCamera;
}
}
public void Canvas_Overlay(bool flag)
{
if (flag)
{
var canvas = FindObjectOfType<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
}
}
} }
} }

View File

@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1 m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0} m_CustomReflection: {fileID: 0}
m_Sun: {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 m_UseRadianceAmbientProbe: 0
--- !u!157 &3 --- !u!157 &3
LightmapSettings: LightmapSettings:
@ -757,85 +757,6 @@ Transform:
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 2 m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 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 --- !u!1 &496349153
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -972,12 +893,12 @@ PrefabInstance:
- target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
propertyPath: m_AnchoredPosition.x propertyPath: m_AnchoredPosition.x
value: 240.00002 value: 240
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
propertyPath: m_AnchoredPosition.y propertyPath: m_AnchoredPosition.y
value: -179.99998 value: -180
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 864895766138689324, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
@ -1160,6 +1081,85 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 608849065} m_GameObject: {fileID: 608849065}
m_CullTransparentMesh: 0 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 --- !u!1 &879285143
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1287,9 +1287,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3a595cf9cf93f4e0686f247a5e7e19ce, type: 3} m_Script: {fileID: 11500000, guid: 3a595cf9cf93f4e0686f247a5e7e19ce, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
copyOrigin: {fileID: 1581241706} m_CopyOrigin: {fileID: 1581241706}
copyCount: 266 m_CopyCount: 266
root: {fileID: 919637305} m_RootCanvas: {fileID: 919637305}
--- !u!4 &903906985 --- !u!4 &903906985
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1505,11 +1505,6 @@ PrefabInstance:
propertyPath: m_SizeDelta.x propertyPath: m_SizeDelta.x
value: 0 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 151878254403844079, guid: 784696794bc6345bc80bf49623581c2e,
type: 3}
propertyPath: m_TargetGraphic
value:
objectReference: {fileID: 1002673091}
- target: {fileID: 323826319202443003, guid: 784696794bc6345bc80bf49623581c2e, - target: {fileID: 323826319202443003, guid: 784696794bc6345bc80bf49623581c2e,
type: 3} type: 3}
propertyPath: m_AnchorMin.y propertyPath: m_AnchorMin.y
@ -1530,11 +1525,6 @@ PrefabInstance:
propertyPath: m_AnchoredPosition.y propertyPath: m_AnchoredPosition.y
value: 0 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 1087632561348207336, guid: 784696794bc6345bc80bf49623581c2e,
type: 3}
propertyPath: m_TargetGraphic
value:
objectReference: {fileID: 1002673092}
- target: {fileID: 1458366075964155596, guid: 784696794bc6345bc80bf49623581c2e, - target: {fileID: 1458366075964155596, guid: 784696794bc6345bc80bf49623581c2e,
type: 3} type: 3}
propertyPath: m_AnchorMin.y propertyPath: m_AnchorMin.y
@ -1564,7 +1554,7 @@ PrefabInstance:
type: 3} type: 3}
propertyPath: m_CustomMonitorItems.Array.data[1].m_Text propertyPath: m_CustomMonitorItems.Array.data[1].m_Text
value: value:
objectReference: {fileID: 455490118} objectReference: {fileID: 733597320}
- target: {fileID: 4567906826058368312, guid: 784696794bc6345bc80bf49623581c2e, - target: {fileID: 4567906826058368312, guid: 784696794bc6345bc80bf49623581c2e,
type: 3} type: 3}
propertyPath: m_CustomMonitorItems.Array.data[1].m_Format propertyPath: m_CustomMonitorItems.Array.data[1].m_Format
@ -1630,16 +1620,6 @@ PrefabInstance:
propertyPath: m_SizeDelta.x propertyPath: m_SizeDelta.x
value: 0 value: 0
objectReference: {fileID: 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, - target: {fileID: 5758968653464739090, guid: 784696794bc6345bc80bf49623581c2e,
type: 3} type: 3}
propertyPath: m_SizeDelta.y propertyPath: m_SizeDelta.y
@ -1803,54 +1783,6 @@ RectTransform:
type: 3} type: 3}
m_PrefabInstance: {fileID: 1002673087} m_PrefabInstance: {fileID: 1002673087}
m_PrefabAsset: {fileID: 0} 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 --- !u!1 &1023851109
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -3632,6 +3564,11 @@ PrefabInstance:
m_Modification: m_Modification:
m_TransformParent: {fileID: 1924051224} m_TransformParent: {fileID: 1924051224}
m_Modifications: m_Modifications:
- target: {fileID: 864895764861262036, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3}
propertyPath: m_IgnoreCanvasScaler
value: 1
objectReference: {fileID: 0}
- target: {fileID: 864895765507486433, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 864895765507486433, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
propertyPath: m_AnchorMax.x propertyPath: m_AnchorMax.x
@ -3790,17 +3727,17 @@ PrefabInstance:
- target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
propertyPath: m_LocalScale.x propertyPath: m_LocalScale.x
value: 0 value: 1
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
propertyPath: m_LocalScale.y propertyPath: m_LocalScale.y
value: 0 value: 1
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b, - target: {fileID: 1088568576793901561, guid: a4669dfbba654429bbcddf0c9b79fb8b,
type: 3} type: 3}
propertyPath: m_LocalScale.z propertyPath: m_LocalScale.z
value: 0 value: 1
objectReference: {fileID: 0} objectReference: {fileID: 0}
m_RemovedComponents: [] m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3} m_SourcePrefab: {fileID: 100100000, guid: a4669dfbba654429bbcddf0c9b79fb8b, type: 3}

View File

@ -1,8 +1,9 @@
using UnityEngine; using System;
using UnityEngine;
namespace Coffee.UIExtensions namespace Coffee.UIExtensions
{ {
[System.Serializable] [Serializable]
public class AnimatableProperty : ISerializationCallbackReceiver public class AnimatableProperty : ISerializationCallbackReceiver
{ {
public enum ShaderPropertyType public enum ShaderPropertyType
@ -11,11 +12,11 @@ namespace Coffee.UIExtensions
Vector, Vector,
Float, Float,
Range, Range,
Texture, Texture
} }
[SerializeField] string m_Name = ""; [SerializeField] private string m_Name = "";
[SerializeField] ShaderPropertyType m_Type = ShaderPropertyType.Vector; [SerializeField] private ShaderPropertyType m_Type = ShaderPropertyType.Vector;
public int id { get; private set; } public int id { get; private set; }
public ShaderPropertyType type public ShaderPropertyType type
@ -23,6 +24,15 @@ namespace Coffee.UIExtensions
get { return m_Type; } get { return m_Type; }
} }
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
id = Shader.PropertyToID(m_Name);
}
public void UpdateMaterialProperties(Material material, MaterialPropertyBlock mpb) public void UpdateMaterialProperties(Material material, MaterialPropertyBlock mpb)
{ {
if (!material.HasProperty(id)) return; if (!material.HasProperty(id)) return;
@ -31,35 +41,38 @@ namespace Coffee.UIExtensions
{ {
case ShaderPropertyType.Color: case ShaderPropertyType.Color:
var color = mpb.GetColor(id); var color = mpb.GetColor(id);
if (color != default(Color)) if (color != default)
{
material.SetColor(id, color); material.SetColor(id, color);
}
break; break;
case ShaderPropertyType.Vector: case ShaderPropertyType.Vector:
var vector = mpb.GetVector(id); var vector = mpb.GetVector(id);
if (vector != default(Vector4)) if (vector != default)
{
material.SetVector(id, vector); material.SetVector(id, vector);
}
break; break;
case ShaderPropertyType.Float: case ShaderPropertyType.Float:
case ShaderPropertyType.Range: case ShaderPropertyType.Range:
var value = mpb.GetFloat(id); var value = mpb.GetFloat(id);
if (value != default(float)) if (!Mathf.Approximately(value, 0))
{
material.SetFloat(id, value); material.SetFloat(id, value);
}
break; break;
case ShaderPropertyType.Texture: case ShaderPropertyType.Texture:
var tex = mpb.GetTexture(id); var tex = mpb.GetTexture(id);
if (tex != default(Texture)) if (tex != default(Texture))
{
material.SetTexture(id, tex); material.SetTexture(id, tex);
}
break; break;
} }
} }
public void OnBeforeSerialize()
{
}
public void OnAfterDeserialize()
{
id = Shader.PropertyToID(m_Name);
}
} }
} }

View File

@ -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<string> s_ActiveNames = new List<string>();
private static readonly StringBuilder s_Sb = new StringBuilder();
private static readonly HashSet<string> s_Names = new HashSet<string>();
private static string CollectActiveNames(SerializedProperty sp, List<string> 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;
}
}
}
}

View File

@ -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<string> s_ActiveNames = new List<string>();
private static readonly System.Text.StringBuilder s_Sb = new System.Text.StringBuilder();
private static readonly HashSet<string> s_Names = new HashSet<string>();
private string _name;
private ShaderPropertyType _type;
static string CollectActiveNames(SerializedProperty sp, List<string> 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();
});
}
}
}

View File

@ -32,11 +32,16 @@ namespace Coffee.UIExtensions
private static void ImportSample(string jsonGuid, string sampleName) private static void ImportSample(string jsonGuid, string sampleName)
{ {
var jsonPath = AssetDatabase.GUIDToAssetPath(jsonGuid); 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 json = File.ReadAllText(jsonPath);
var version = Regex.Match(json, "\"version\"\\s*:\\s*\"([^\"]+)\"").Groups[1].Value; var version = Regex.Match(json, "\"version\"\\s*:\\s*\"([^\"]+)\"").Groups[1].Value;
var src = string.Format("{0}/Samples~/{1}", packageRoot, sampleName); var src = $"{packageRoot}/Samples~/{sampleName}";
var dst = string.Format("Assets/Samples/{0}/{1}/{2}", k_DisplayName, version, sampleName); var dst = $"Assets/Samples/{k_DisplayName}/{version}/{sampleName}";
var previousPath = GetPreviousSamplePath(k_DisplayName, sampleName); var previousPath = GetPreviousSamplePath(k_DisplayName, sampleName);
// Remove the previous sample directory. // Remove the previous sample directory.
@ -46,33 +51,45 @@ namespace Coffee.UIExtensions
+ previousPath + previousPath
+ "\n\nIt will be deleted when you update. Are you sure you want to continue?"; + "\n\nIt will be deleted when you update. Are you sure you want to continue?";
if (!EditorUtility.DisplayDialog("Sample Importer", msg, "OK", "Cancel")) if (!EditorUtility.DisplayDialog("Sample Importer", msg, "OK", "Cancel"))
{
return; return;
}
FileUtil.DeleteFileOrDirectory(previousPath); FileUtil.DeleteFileOrDirectory(previousPath);
var metaFile = previousPath + ".meta"; var metaFile = previousPath + ".meta";
if (File.Exists(metaFile)) if (File.Exists(metaFile))
{
FileUtil.DeleteFileOrDirectory(metaFile); FileUtil.DeleteFileOrDirectory(metaFile);
}
} }
if (!Directory.Exists(dst)) if (!Directory.Exists(dst))
{
FileUtil.DeleteFileOrDirectory(dst); FileUtil.DeleteFileOrDirectory(dst);
}
var dstDir = Path.GetDirectoryName(dst); var dstDir = Path.GetDirectoryName(dst);
if (!Directory.Exists(dstDir)) if (!string.IsNullOrEmpty(dstDir) && !Directory.Exists(dstDir))
{
Directory.CreateDirectory(dstDir); Directory.CreateDirectory(dstDir);
}
if (Directory.Exists(src)) if (Directory.Exists(src))
{
FileUtil.CopyFileOrDirectory(src, dst); FileUtil.CopyFileOrDirectory(src, dst);
}
else else
{
throw new DirectoryNotFoundException(src); throw new DirectoryNotFoundException(src);
}
AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive); AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive);
} }
private static string GetPreviousSamplePath(string displayName, string sampleName) 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); var sampleRootInfo = new DirectoryInfo(sampleRoot);
if (!sampleRootInfo.Exists) return null; if (!sampleRootInfo.Exists) return null;

View File

@ -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 #if UNITY_2021_2_OR_NEWER
using UnityEditor.Overlays; using UnityEditor.Overlays;
#else #else
using System.Reflection; using System.Reflection;
#endif #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 namespace Coffee.UIExtensions
{ {
@ -23,7 +26,10 @@ namespace Coffee.UIExtensions
{ {
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
#if UNITY_2022_1_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 #else
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true)] [Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true)]
#endif #endif
@ -52,27 +58,28 @@ namespace Coffee.UIExtensions
private static readonly GUIContent s_Content3D = new GUIContent("3D"); private static readonly GUIContent s_Content3D = new GUIContent("3D");
private static readonly GUIContent s_ContentRandom = new GUIContent("Random"); private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
private static readonly GUIContent s_ContentScale = new GUIContent("Scale"); 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 SerializedObject s_SerializedObject;
private static bool s_XYZMode;
#if !SERIALIZE_FIELD_MASKABLE private SerializedProperty _maskable;
private SerializedProperty m_Maskable; private SerializedProperty _scale3D;
#endif private SerializedProperty _animatableProperties;
private SerializedProperty m_Scale3D; private SerializedProperty _meshSharing;
private SerializedProperty m_AnimatableProperties; private SerializedProperty _groupId;
private SerializedProperty m_MeshSharing; private SerializedProperty _groupMaxId;
private SerializedProperty m_GroupId; private SerializedProperty _absoluteMode;
private SerializedProperty m_GroupMaxId; private SerializedProperty _ignoreCanvasScaler;
private SerializedProperty m_AbsoluteMode;
private SerializedProperty m_IgnoreCanvasScaler;
private ReorderableList _ro; private ReorderableList _ro;
static private bool _xyzMode;
private bool _showMax; private bool _showMax;
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>(); private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
private static readonly List<ParticleSystemVertexStream> s_Streams = new List<ParticleSystemVertexStream>(); private static readonly List<ParticleSystemVertexStream> s_Streams = new List<ParticleSystemVertexStream>();
private static readonly List<string> s_MaskablePropertyNames = new List<string> private static readonly List<string> s_MaskablePropertyNames = new List<string>
{ {
"_Stencil", "_Stencil",
@ -80,21 +87,20 @@ namespace Coffee.UIExtensions
"_StencilOp", "_StencilOp",
"_StencilWriteMask", "_StencilWriteMask",
"_StencilReadMask", "_StencilReadMask",
"_ColorMask", "_ColorMask"
}; };
[InitializeOnLoadMethod] [InitializeOnLoadMethod]
static void Init() private static void Init()
{ {
#if !UNITY_2021_2_OR_NEWER #if !UNITY_2021_2_OR_NEWER
var miSceneViewOverlayWindow = Type.GetType("UnityEditor.SceneViewOverlay, UnityEditor") 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); .First(x => x.Name == "Window" && 5 <= x.GetParameters().Length);
var windowFunction = (Action<UnityEngine.Object, SceneView>)WindowFunction; var windowFunction = (Action<Object, SceneView>)WindowFunction;
var windowFunctionType = Type.GetType("UnityEditor.SceneViewOverlay+WindowFunction, UnityEditor"); var windowFunctionType = Type.GetType("UnityEditor.SceneViewOverlay+WindowFunction, UnityEditor");
var windowFunctionDelegate = Delegate.CreateDelegate(windowFunctionType, windowFunction.Method); 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 #if UNITY_2019_2_OR_NEWER
//public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option, EditorWindow window = null) //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 }; var sceneViewArgs = new object[] { windowTitle, windowFunctionDelegate, 599, null, 2, null };
@ -104,7 +110,7 @@ namespace Coffee.UIExtensions
#endif #endif
#if UNITY_2019_1_OR_NEWER #if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui += _ => { if (s_SerializedObject != null) miSceneViewOverlayWindow.Invoke(null, sceneViewArgs); }; SceneView.duringSceneGui += _ =>
#else #else
SceneView.onSceneGUIDelegate += _ => SceneView.onSceneGUIDelegate += _ =>
#endif #endif
@ -116,25 +122,21 @@ namespace Coffee.UIExtensions
}; };
#endif #endif
Func<SerializedObject> createSerializeObject = () => SerializedObject CreateSerializeObject()
{ {
var uiParticles = Selection.gameObjects var uiParticles = Selection.gameObjects.Select(x => x.GetComponent<ParticleSystem>())
.Select(x => x.GetComponent<ParticleSystem>()) .Where(x => x)
.Where(x => x) .Select(x => x.GetComponentInParent<UIParticle>())
.Select(x => x.GetComponentInParent<UIParticle>()) .Where(x => x && x.canvas)
.Where(x => x && x.canvas) .Concat(Selection.gameObjects.Select(x => x.GetComponent<UIParticle>())
.Concat( .Where(x => x && x.canvas))
Selection.gameObjects .Distinct()
.Select(x => x.GetComponent<UIParticle>()) .ToArray();
.Where(x => x && x.canvas)
)
.Distinct()
.ToArray();
return 0 < uiParticles.Length ? new SerializedObject(uiParticles) : null; return 0 < uiParticles.Length ? new SerializedObject(uiParticles) : null;
}; }
s_SerializedObject = createSerializeObject(); s_SerializedObject = CreateSerializeObject();
Selection.selectionChanged += () => s_SerializedObject = createSerializeObject(); Selection.selectionChanged += () => s_SerializedObject = CreateSerializeObject();
} }
//################################ //################################
@ -147,64 +149,71 @@ namespace Coffee.UIExtensions
{ {
base.OnEnable(); base.OnEnable();
m_Maskable = serializedObject.FindProperty("m_Maskable"); _maskable = serializedObject.FindProperty("m_Maskable");
m_Scale3D = serializedObject.FindProperty("m_Scale3D"); _scale3D = serializedObject.FindProperty("m_Scale3D");
m_AnimatableProperties = serializedObject.FindProperty("m_AnimatableProperties"); _animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
m_MeshSharing = serializedObject.FindProperty("m_MeshSharing"); _meshSharing = serializedObject.FindProperty("m_MeshSharing");
m_GroupId = serializedObject.FindProperty("m_GroupId"); _groupId = serializedObject.FindProperty("m_GroupId");
m_GroupMaxId = serializedObject.FindProperty("m_GroupMaxId"); _groupMaxId = serializedObject.FindProperty("m_GroupMaxId");
m_AbsoluteMode = serializedObject.FindProperty("m_AbsoluteMode"); _absoluteMode = serializedObject.FindProperty("m_AbsoluteMode");
m_IgnoreCanvasScaler = serializedObject.FindProperty("m_IgnoreCanvasScaler"); _ignoreCanvasScaler = serializedObject.FindProperty("m_IgnoreCanvasScaler");
var sp = serializedObject.FindProperty("m_Particles"); var sp = serializedObject.FindProperty("m_Particles");
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true); _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, _, __) =>
{ {
EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues); elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4,
rect.y += 1; elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2),
rect.height = EditorGUIUtility.singleLineHeight; drawElementCallback = (rect, index, _, __) =>
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<ParticleSystemRenderer>()).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)
{ {
materials.serializedObject.ApplyModifiedProperties(); EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues);
} rect.y += 1;
}; rect.height = EditorGUIUtility.singleLineHeight;
_ro.drawHeaderCallback = rect => var p = sp.GetArrayElementAtIndex(index);
{ EditorGUI.ObjectField(rect, p, GUIContent.none);
#if !UNITY_2019_3_OR_NEWER rect.x += 15;
rect.y -= 1; rect.width -= 15;
#endif var ps = p.objectReferenceValue as ParticleSystem;
EditorGUI.LabelField(new Rect(rect.x, rect.y, 150, rect.height), s_ContentRenderingOrder); var materials = ps
? new SerializedObject(ps.GetComponent<ParticleSystemRenderer>()).FindProperty("m_Materials")
if (GUI.Button(new Rect(rect.width - 35, rect.y, 60, rect.height), s_ContentRefresh, EditorStyles.miniButton)) : null;
{ rect.y += rect.height + 1;
foreach (UIParticle t in targets) 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(); materials.serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(t); }
},
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<UIParticle>())
{
uip.RefreshParticles();
EditorUtility.SetDirty(uip);
}
} }
} }
}; };
// On select UIParticle, refresh particles. // On select UIParticle, refresh particles.
foreach (UIParticle t in targets) if (!Application.isPlaying)
{ {
if (Application.isPlaying || PrefabUtility.GetPrefabAssetType(t) != PrefabAssetType.NotAPrefab) continue; foreach (var uip in targets.OfType<UIParticle>())
t.RefreshParticles(t.particles); {
if (PrefabUtility.GetPrefabAssetType(uip) != PrefabAssetType.NotAPrefab) continue;
uip.RefreshParticles(uip.particles);
}
} }
} }
@ -233,11 +242,11 @@ namespace Coffee.UIExtensions
serializedObject.Update(); serializedObject.Update();
// Maskable // Maskable
EditorGUILayout.PropertyField(m_Maskable); EditorGUILayout.PropertyField(_maskable);
// Scale // Scale
EditorGUI.BeginDisabledGroup(!m_MeshSharing.hasMultipleDifferentValues && m_MeshSharing.intValue == 4); EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
_xyzMode = DrawFloatOrVector3Field(m_Scale3D, _xyzMode); s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup();
// AnimatableProperties // AnimatableProperties
@ -247,12 +256,11 @@ namespace Coffee.UIExtensions
.Where(x => x) .Where(x => x)
.ToArray(); .ToArray();
// Animated properties AnimatablePropertyEditor.Draw(_animatableProperties, mats);
AnimatedPropertiesEditor.DrawAnimatableProperties(m_AnimatableProperties, mats);
// Mesh sharing // Mesh sharing
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
_showMax = DrawMeshSharing(m_MeshSharing, m_GroupId, m_GroupMaxId, _showMax); _showMax = DrawMeshSharing(_meshSharing, _groupId, _groupMaxId, _showMax);
if (EditorGUI.EndChangeCheck()) if (EditorGUI.EndChangeCheck())
{ {
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
@ -263,10 +271,10 @@ namespace Coffee.UIExtensions
} }
// Absolute Mode // Absolute Mode
EditorGUILayout.PropertyField(m_AbsoluteMode); EditorGUILayout.PropertyField(_absoluteMode);
// Auto Scaling // Auto Scaling
DrawInversedToggle(m_IgnoreCanvasScaler, s_ContentAutoScaling, () => DrawInversedToggle(_ignoreCanvasScaler, s_ContentAutoScaling, () =>
{ {
foreach (var uip in targets.OfType<UIParticle>()) foreach (var uip in targets.OfType<UIParticle>())
{ {
@ -292,6 +300,7 @@ namespace Coffee.UIExtensions
} }
// Does the shader support UI masks? // Does the shader support UI masks?
if (current.maskable && current.GetComponentInParent<Mask>()) if (current.maskable && current.GetComponentInParent<Mask>())
{ {
foreach (var mat in current.materials) foreach (var mat in current.materials)
@ -304,15 +313,19 @@ namespace Coffee.UIExtensions
{ {
if (mat.HasProperty(propName)) continue; 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; break;
} }
} }
} }
s_Shaders.Clear(); s_Shaders.Clear();
// UIParticle for trail should be removed. // 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); DestroyUIParticle(current);
} }
@ -328,7 +341,9 @@ namespace Coffee.UIExtensions
{ {
var so = new SerializedObject(allPsRenderers); var so = new SerializedObject(allPsRenderers);
var sp = so.FindProperty("m_ApplyActiveColorSpace"); 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; sp.boolValue = false;
so.ApplyModifiedProperties(); so.ApplyModifiedProperties();
@ -343,8 +358,13 @@ namespace Coffee.UIExtensions
if (2 < s_Streams.Select(GetUsedComponentCount).Sum()) 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: case ParticleSystemVertexStream.Custom2XYZW:
return 4; return 4;
} }
return 3; 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 || showMax |= spGroupId.intValue != spGroupMaxId.intValue ||
spGroupId.hasMultipleDifferentValues || spGroupId.hasMultipleDifferentValues ||
@ -419,7 +441,10 @@ namespace Coffee.UIExtensions
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60)); showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60));
if (EditorGUI.EndChangeCheck() && !showMax) if (EditorGUI.EndChangeCheck() && !showMax)
{
spGroupMaxId.intValue = spGroupId.intValue; spGroupMaxId.intValue = spGroupId.intValue;
}
EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal();
EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0); EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0);
@ -432,23 +457,25 @@ namespace Coffee.UIExtensions
else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4) else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4)
{ {
EditorGUI.BeginDisabledGroup(true); 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.EndDisabledGroup();
} }
EditorGUI.indentLevel--; EditorGUI.indentLevel--;
EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup();
return showMax; 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; EditorGUI.showMixedValue = sp.hasMultipleDifferentValues;
var autoScaling = !inversedProperty.boolValue; var autoScaling = !sp.boolValue;
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
if (autoScaling != EditorGUILayout.Toggle(label, autoScaling)) if (autoScaling != EditorGUILayout.Toggle(label, autoScaling))
{ {
inversedProperty.boolValue = autoScaling; sp.boolValue = autoScaling;
} }
if (EditorGUI.EndChangeCheck()) if (EditorGUI.EndChangeCheck())
@ -459,7 +486,7 @@ namespace Coffee.UIExtensions
EditorGUI.showMixedValue = false; EditorGUI.showMixedValue = false;
} }
private static void WindowFunction(UnityEngine.Object target, SceneView sceneView) private static void WindowFunction(Object target, SceneView sceneView)
{ {
try try
{ {
@ -472,48 +499,45 @@ namespace Coffee.UIExtensions
var labelWidth = EditorGUIUtility.labelWidth; var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 100; EditorGUIUtility.labelWidth = 100;
EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_Enabled")); 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")); 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<UIParticle>()) s_SerializedObject.targetObjects
{ .OfType<UIParticle>()
if (uip && !uip.autoScaling) .Where(x => x && !x.autoScaling)
{ .ToList()
uip.transform.localScale = Vector3.one; .ForEach(x => x.transform.localScale = Vector3.one);
}
}
}); });
EditorGUIUtility.labelWidth = labelWidth; EditorGUIUtility.labelWidth = labelWidth;
} }
s_SerializedObject.ApplyModifiedProperties(); s_SerializedObject.ApplyModifiedProperties();
} }
catch catch
{ {
// ignored
} }
} }
private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false) private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false)
{ {
if (!p || ignoreCurrent && target == p) return; if (!p || (ignoreCurrent && target == p)) return;
var cr = p.canvasRenderer; var cr = p.canvasRenderer;
DestroyImmediate(p); DestroyImmediate(p);
DestroyImmediate(cr); 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 #if UNITY_2018_3_OR_NEWER
var stage = PrefabStageUtility.GetCurrentPrefabStage();
if (stage != null && stage.scene.isLoaded) if (stage != null && stage.scene.isLoaded)
{ {
#if UNITY_2020_1_OR_NEWER #if UNITY_2020_1_OR_NEWER
string prefabAssetPath = stage.assetPath; string prefabAssetPath = stage.assetPath;
#else #else
string prefabAssetPath = stage.prefabAssetPath; var prefabAssetPath = stage.prefabAssetPath;
#endif #endif
PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath); PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath);
} }
@ -562,7 +586,10 @@ namespace Coffee.UIExtensions
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30)); showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30));
if (EditorGUI.EndChangeCheck() && !showXyz) if (EditorGUI.EndChangeCheck() && !showXyz)
{
z.floatValue = y.floatValue = x.floatValue; z.floatValue = y.floatValue = x.floatValue;
}
EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal();
return showXyz; return showXyz;

View File

@ -10,7 +10,7 @@ namespace Coffee.UIParticleExtensions
public static Material Add(Material baseMat, Texture texture, int id) public static Material Add(Material baseMat, Texture texture, int id)
{ {
MatEntry e; MatEntry e;
for (var i = 0; i < s_Entries.Count; ++i) for (var i = 0; i < s_Entries.Count; i++)
{ {
e = s_Entries[i]; e = s_Entries[i];
if (e.baseMat != baseMat || e.texture != texture || e.id != id) continue; if (e.baseMat != baseMat || e.texture != texture || e.id != id) continue;
@ -18,15 +18,19 @@ namespace Coffee.UIParticleExtensions
return e.customMat; return e.customMat;
} }
e = new MatEntry(); e = new MatEntry
e.count = 1; {
e.baseMat = baseMat; count = 1,
e.texture = texture; baseMat = baseMat,
e.id = id; texture = texture,
e.customMat = new Material(baseMat); id = id,
e.customMat.hideFlags = HideFlags.HideAndDontSave; customMat = new Material(baseMat)
if (texture) {
e.customMat.mainTexture = texture; name = $"{baseMat.name}_{id}",
hideFlags = HideFlags.HideAndDontSave,
mainTexture = texture ? texture : null
}
};
s_Entries.Add(e); s_Entries.Add(e);
//Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id); //Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id);
return e.customMat; return e.customMat;
@ -43,7 +47,8 @@ namespace Coffee.UIParticleExtensions
if (--e.count == 0) 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); //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.baseMat = null;
e.texture = null; e.texture = null;
s_Entries.RemoveAt(i); 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 private class MatEntry
{ {
public Material baseMat; public Material baseMat;
public Material customMat;
public int count; public int count;
public Texture texture; public Material customMat;
public int id; public int id;
public Texture texture;
} }
} }
} }

View File

@ -2,7 +2,6 @@
#define SERIALIZE_FIELD_MASKABLE #define SERIALIZE_FIELD_MASKABLE
#endif #endif
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Coffee.UIParticleExtensions; using Coffee.UIParticleExtensions;
using UnityEngine; using UnityEngine;
@ -28,16 +27,19 @@ namespace Coffee.UIExtensions
Auto, Auto,
Primary, Primary,
PrimarySimulator, PrimarySimulator,
Replica, Replica
} }
[HideInInspector][SerializeField] internal bool m_IsTrail = false; [HideInInspector]
[SerializeField]
internal bool m_IsTrail;
[Tooltip("Particle effect scale")] [Tooltip("Particle effect scale")]
[SerializeField] [SerializeField]
private Vector3 m_Scale3D = new Vector3(10, 10, 10); 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] [SerializeField]
internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0]; internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0];
@ -45,40 +47,49 @@ namespace Coffee.UIExtensions
[SerializeField] [SerializeField]
private List<ParticleSystem> m_Particles = new List<ParticleSystem>(); private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
[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] [SerializeField]
private MeshSharing m_MeshSharing = MeshSharing.None; 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] [SerializeField]
private int m_GroupId = 0; private int m_GroupId;
[SerializeField] [SerializeField]
private int m_GroupMaxId = 0; private int m_GroupMaxId;
[SerializeField] [SerializeField]
[Tooltip("The particles will be emitted at the ParticleSystem position.\nMove the UIParticle/ParticleSystem to move the particle.")] [Tooltip("Particle position mode.\n" +
"Absolute Mode: The particles will be emitted from the ParticleSystem position.\n" +
" Move the UIParticle or ParticleSystem to move the particle.\n" +
"Relative Mode: The particles will be emitted from the scaled ParticleSystem position.\n" +
" Move the UIParticle to move the particle.")]
private bool m_AbsoluteMode = false; private bool m_AbsoluteMode = false;
/// <summary> /// <summary>
/// This field uses the inverted value as "AutoScaling". /// This field uses the inverted value as "AutoScaling".
/// </summary> /// </summary>
[SerializeField]
[FormerlySerializedAs("m_IgnoreParent")] [FormerlySerializedAs("m_IgnoreParent")]
private bool m_IgnoreCanvasScaler = false; [SerializeField]
private bool m_IgnoreCanvasScaler;
private List<UIParticleRenderer> m_Renderers = new List<UIParticleRenderer>();
#if !SERIALIZE_FIELD_MASKABLE #if !SERIALIZE_FIELD_MASKABLE
[SerializeField] private bool m_Maskable = true; [SerializeField]
private bool m_Maskable = true;
#endif #endif
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
private DrivenRectTransformTracker _tracker;
private Camera _orthoCamera;
private int _groupId; private int _groupId;
private Camera _orthoCamera;
private DrivenRectTransformTracker _tracker;
/// <summary> /// <summary>
/// Should this graphic be considered a target for raycasting? /// Should this graphic be considered a target for ray-casting?
/// </summary> /// </summary>
public override bool raycastTarget public override bool raycastTarget
{ {
@ -87,7 +98,8 @@ namespace Coffee.UIExtensions
} }
/// <summary> /// <summary>
/// Mesh sharing.None: disable mesh sharing. /// Mesh sharing.
/// None: disable mesh sharing.
/// Auto: automatically select Primary/Replica. /// Auto: automatically select Primary/Replica.
/// Primary: provides particle simulation results to the same group. /// Primary: provides particle simulation results to the same group.
/// Primary Simulator: Primary, but do not render the particle (simulation only). /// Primary Simulator: Primary, but do not render the particle (simulation only).
@ -100,7 +112,8 @@ namespace Coffee.UIExtensions
} }
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public int groupId public int groupId
{ {
@ -110,7 +123,9 @@ namespace Coffee.UIExtensions
if (m_GroupId == value) return; if (m_GroupId == value) return;
m_GroupId = value; m_GroupId = value;
if (m_GroupId != m_GroupMaxId) if (m_GroupId != m_GroupMaxId)
{
ResetGroupId(); ResetGroupId();
}
} }
} }
@ -126,9 +141,11 @@ namespace Coffee.UIExtensions
} }
/// <summary> /// <summary>
/// Absolute particle position mode. /// Particle position mode.
/// The particles will be emitted at the ParticleSystem position. /// Absolute Mode: The particles will be emitted from the ParticleSystem position.
/// Move the UIParticle/ParticleSystem to move the particle. /// 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.
/// </summary> /// </summary>
public bool absoluteMode public bool absoluteMode
{ {
@ -136,6 +153,11 @@ namespace Coffee.UIExtensions
set { m_AbsoluteMode = value; } set { m_AbsoluteMode = value; }
} }
/// <summary>
/// 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.
/// </summary>
public bool autoScaling public bool autoScaling
{ {
get { return !m_IgnoreCanvasScaler; } get { return !m_IgnoreCanvasScaler; }
@ -154,17 +176,33 @@ namespace Coffee.UIExtensions
internal bool isPrimary 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 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 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;
}
} }
/// <summary> /// <summary>
@ -197,12 +235,12 @@ namespace Coffee.UIExtensions
{ {
get 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; var r = _renderers[i];
yield return m_Renderers[i].material; if (!r || !r.material) continue;
yield return r.material;
} }
yield break;
} }
} }
@ -214,10 +252,60 @@ namespace Coffee.UIExtensions
/// <summary> /// <summary>
/// Paused. /// Paused.
/// </summary> /// </summary>
public bool isPaused { get; internal set; } public bool isPaused { get; private set; }
public Vector3 parentScale { 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();
}
/// <summary>
/// This function is called when the behaviour becomes disabled.
/// </summary>
protected override void OnDisable()
{
UpdateTracker();
UIParticleUpdater.Unregister(this);
_renderers.ForEach(r => r.Reset());
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
base.OnDisable();
}
/// <summary>
/// Callback for when properties have been changed by animation.
/// </summary>
protected override void OnDidApplyAnimationProperties()
{
}
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
UpdateTracker();
}
#endif
public void Play() public void Play()
{ {
particles.Exec(p => p.Simulate(0, false, true)); particles.Exec(p => p.Simulate(0, false, true));
@ -240,7 +328,7 @@ namespace Coffee.UIExtensions
particles.Exec(p => p.Stop()); particles.Exec(p => p.Stop());
isPaused = true; isPaused = true;
} }
public void StartEmission() public void StartEmission()
{ {
particles.Exec(p => particles.Exec(p =>
@ -249,7 +337,7 @@ namespace Coffee.UIExtensions
emission.enabled = true; emission.enabled = true;
}); });
} }
public void StopEmission() public void StopEmission()
{ {
particles.Exec(p => particles.Exec(p =>
@ -278,14 +366,10 @@ namespace Coffee.UIExtensions
{ {
var go = child.gameObject; var go = child.gameObject;
go.SetActive(false); go.SetActive(false);
if (!destroyOldParticles) continue; if (destroyOldParticles)
{
#if UNITY_EDITOR Misc.Destroy(go);
if (!Application.isPlaying) }
DestroyImmediate(go);
else
#endif
Destroy(go);
} }
var tr = instance.transform; var tr = instance.transform;
@ -313,11 +397,14 @@ namespace Coffee.UIExtensions
root.GetComponentsInChildren(particles); root.GetComponentsInChildren(particles);
particles.RemoveAll(x => x.GetComponentInParent<UIParticle>() != this); particles.RemoveAll(x => x.GetComponentInParent<UIParticle>() != this);
foreach (var ps in particles) for (var i = 0; i < particles.Count; i++)
{ {
var ps = particles[i];
var tsa = ps.textureSheetAnimation; var tsa = ps.textureSheetAnimation;
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0) if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
{
tsa.uvChannelMask = UVChannelFlags.UV0; tsa.uvChannelMask = UVChannelFlags.UV0;
}
} }
RefreshParticles(particles); RefreshParticles(particles);
@ -326,30 +413,31 @@ namespace Coffee.UIExtensions
public void RefreshParticles(List<ParticleSystem> particles) public void RefreshParticles(List<ParticleSystem> particles)
{ {
// #246: Nullptr exceptions when using nested UIParticle components in hierarchy // #246: Nullptr exceptions when using nested UIParticle components in hierarchy
m_Renderers.Clear(); _renderers.Clear();
foreach (Transform child in transform) foreach (Transform child in transform)
{ {
var uiParticleRenderer = child.GetComponent<UIParticleRenderer>(); var uiParticleRenderer = child.GetComponent<UIParticleRenderer>();
if (uiParticleRenderer != null) 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; var j = 0;
for (var i = 0; i < particles.Count; i++) for (var i = 0; i < particles.Count; i++)
{ {
if (!particles[i]) continue; var ps = particles[i];
GetRenderer(j++).Set(this, particles[i], false); if (!ps) continue;
if (particles[i].trails.enabled) GetRenderer(j++).Set(this, ps, false);
if (ps.trails.enabled)
{ {
GetRenderer(j++).Set(this, particles[i], true); GetRenderer(j++).Set(this, ps, true);
} }
} }
} }
@ -370,9 +458,10 @@ namespace Coffee.UIExtensions
{ {
if (!isActiveAndEnabled) return; 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); RefreshParticles(particles);
break; break;
@ -380,67 +469,29 @@ namespace Coffee.UIExtensions
} }
var bakeCamera = GetBakeCamera(); 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; var r = _renderers[i];
m_Renderers[i].UpdateMesh(bakeCamera); if (!r) continue;
r.UpdateMesh(bakeCamera);
} }
} }
internal void UpdateParticleCount() 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; var r = _renderers[i];
m_Renderers[i].UpdateParticleCount(); 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() internal void ResetGroupId()
{ {
if (m_GroupId == m_GroupMaxId) _groupId = m_GroupId == m_GroupMaxId
{ ? m_GroupId
_groupId = m_GroupId; : Random.Range(m_GroupId, m_GroupMaxId + 1);
}
else
{
_groupId = Random.Range(m_GroupId, m_GroupMaxId + 1);
}
}
/// <summary>
/// This function is called when the behaviour becomes disabled.
/// </summary>
protected override void OnDisable()
{
UpdateTracker();
UIParticleUpdater.Unregister(this);
m_Renderers.ForEach(r => r.Reset());
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
base.OnDisable();
} }
protected override void UpdateMaterial() protected override void UpdateMaterial()
@ -454,43 +505,42 @@ namespace Coffee.UIExtensions
{ {
} }
/// <summary>
/// Callback for when properties have been changed by animation.
/// </summary>
protected override void OnDidApplyAnimationProperties()
{
}
private void UpdateRendererMaterial() 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; var r = _renderers[i];
m_Renderers[i].maskable = maskable; if (!r) continue;
m_Renderers[i].SetMaterialDirty(); r.maskable = maskable;
r.SetMaterialDirty();
} }
} }
internal UIParticleRenderer GetRenderer(int index) 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() private Camera GetBakeCamera()
{ {
if (!canvas) return Camera.main; if (!canvas) return Camera.main;
// World camera. // Render mode is not ScreenSpaceOverlay, use world camera.
var root = canvas.rootCanvas; 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. // Create ortho-camera.
if (!_orthoCamera) if (!_orthoCamera)
@ -498,10 +548,7 @@ namespace Coffee.UIExtensions
_orthoCamera = GetComponentInChildren<Camera>(); _orthoCamera = GetComponentInChildren<Camera>();
if (!_orthoCamera) if (!_orthoCamera)
{ {
var go = new GameObject("UIParticleOverlayCamera") var go = new GameObject("UIParticleOverlayCamera") { hideFlags = HideFlags.DontSave };
{
hideFlags = HideFlags.DontSave,
};
go.SetActive(false); go.SetActive(false);
go.transform.SetParent(transform, false); go.transform.SetParent(transform, false);
_orthoCamera = go.AddComponent<Camera>(); _orthoCamera = go.AddComponent<Camera>();
@ -509,7 +556,7 @@ namespace Coffee.UIExtensions
} }
} }
// //
var size = ((RectTransform)root.transform).rect.size; var size = ((RectTransform)root.transform).rect.size;
_orthoCamera.orthographicSize = Mathf.Max(size.x, size.y) * root.scaleFactor; _orthoCamera.orthographicSize = Mathf.Max(size.x, size.y) * root.scaleFactor;
_orthoCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity); _orthoCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
@ -530,13 +577,5 @@ namespace Coffee.UIExtensions
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale); _tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
} }
} }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
UpdateTracker();
}
#endif
} }
} }

View File

@ -1,7 +1,7 @@
using UnityEngine; using System;
using Coffee.UIParticleExtensions; using Coffee.UIParticleExtensions;
using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using System;
namespace Coffee.UIExtensions namespace Coffee.UIExtensions
{ {
@ -12,13 +12,13 @@ namespace Coffee.UIExtensions
{ {
Linear, Linear,
Smooth, Smooth,
Sphere, Sphere
} }
public enum UpdateMode public enum UpdateMode
{ {
Normal, Normal,
UnscaledTime, UnscaledTime
} }
[SerializeField] [SerializeField]
@ -30,7 +30,7 @@ namespace Coffee.UIExtensions
[Range(0f, 0.95f)] [Range(0f, 0.95f)]
[SerializeField] [SerializeField]
private float m_DelayRate = 0; private float m_DelayRate;
[Range(0.001f, 100f)] [Range(0.001f, 100f)]
[SerializeField] [SerializeField]
@ -45,84 +45,51 @@ namespace Coffee.UIExtensions
[SerializeField] [SerializeField]
private UnityEvent m_OnAttracted; private UnityEvent m_OnAttracted;
private UIParticle _uiParticle;
public float destinationRadius public float destinationRadius
{ {
get get { return m_DestinationRadius; }
{ set { m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f); }
return m_DestinationRadius;
}
set
{
m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f);
}
} }
public float delay public float delay
{ {
get get { return m_DelayRate; }
{ set { m_DelayRate = value; }
return m_DelayRate;
}
set
{
m_DelayRate = value;
}
} }
public float maxSpeed public float maxSpeed
{ {
get get { return m_MaxSpeed; }
{ set { m_MaxSpeed = value; }
return m_MaxSpeed;
}
set
{
m_MaxSpeed = value;
}
} }
public Movement movement public Movement movement
{ {
get get { return m_Movement; }
{ set { m_Movement = value; }
return m_Movement;
}
set
{
m_Movement = value;
}
} }
public UpdateMode updateMode public UpdateMode updateMode
{ {
get get { return m_UpdateMode; }
{ set { m_UpdateMode = value; }
return m_UpdateMode;
}
set
{
m_UpdateMode = value;
}
} }
public UnityEvent onAttracted public UnityEvent onAttracted
{ {
get get { return m_OnAttracted; }
{ set { m_OnAttracted = value; }
return m_OnAttracted;
}
set
{
m_OnAttracted = value;
}
} }
#if UNITY_EDITOR
public new ParticleSystem particleSystem
#else
public ParticleSystem particleSystem public ParticleSystem particleSystem
#endif
{ {
get get { return m_ParticleSystem; }
{
return m_ParticleSystem;
}
set set
{ {
m_ParticleSystem = value; m_ParticleSystem = value;
@ -130,8 +97,6 @@ namespace Coffee.UIExtensions
} }
} }
private UIParticle _uiParticle;
private void OnEnable() private void OnEnable()
{ {
ApplyParticleSystem(); ApplyParticleSystem();
@ -207,7 +172,7 @@ namespace Coffee.UIExtensions
var psPos = m_ParticleSystem.transform.position; var psPos = m_ParticleSystem.transform.position;
var attractorPos = transform.position; var attractorPos = transform.position;
var dstPos = attractorPos; var dstPos = attractorPos;
var isLocalSpace = m_ParticleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local; var isLocalSpace = m_ParticleSystem.IsLocalSpace();
if (isLocalSpace) if (isLocalSpace)
{ {
@ -251,6 +216,7 @@ namespace Coffee.UIExtensions
speed *= 60 * Time.unscaledDeltaTime; speed *= 60 * Time.unscaledDeltaTime;
break; break;
} }
switch (m_Movement) switch (m_Movement)
{ {
case Movement.Linear: case Movement.Linear:
@ -278,6 +244,7 @@ namespace Coffee.UIExtensions
{ {
Debug.LogError("No particle system attached to particle attractor script", this); Debug.LogError("No particle system attached to particle attractor script", this);
} }
return; return;
} }
@ -288,4 +255,4 @@ namespace Coffee.UIExtensions
} }
} }
} }
} }

View File

@ -1,9 +1,10 @@
using UnityEngine; using System;
using UnityEngine.UI; using System.Collections.Generic;
using Coffee.UIParticleExtensions; using Coffee.UIParticleExtensions;
using UnityEngine;
using UnityEngine.Profiling; using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
using System.Collections.Generic; using UnityEngine.UI;
namespace Coffee.UIExtensions namespace Coffee.UIExtensions
{ {
@ -13,41 +14,34 @@ namespace Coffee.UIExtensions
[AddComponentMenu("")] [AddComponentMenu("")]
internal class UIParticleRenderer : MaskableGraphic 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<Material> s_Materials = new List<Material>(2); private static readonly List<Material> s_Materials = new List<Material>(2);
private static MaterialPropertyBlock s_Mpb; private static MaterialPropertyBlock s_Mpb;
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>(); private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>();
private static readonly Vector3[] s_Corners = new Vector3[4]; private static readonly Vector3[] s_Corners = new Vector3[4];
private Material _currentMaterialForRendering;
private ParticleSystemRenderer _renderer; private bool _delay;
private ParticleSystem _particleSystem;
private int _prevParticleCount = 0;
private UIParticle _parent;
private int _index; private int _index;
private bool _isTrail; 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 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 public override Texture mainTexture
{ {
get get { return _isTrail ? null : _particleSystem.GetTextureForSprite(); }
{
return _isTrail ? null : _particleSystem.GetTextureForSprite();
}
} }
public override bool raycastTarget public override bool raycastTarget
{ {
get get { return false; }
{
return false;
}
} }
private Rect rootCanvasRect private Rect rootCanvasRect
@ -62,32 +56,103 @@ namespace Coffee.UIExtensions
{ {
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix; var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
for (var i = 0; i < 4; ++i) for (var i = 0; i < 4; ++i)
{
s_Corners[i] = worldToLocalMatrix.MultiplyPoint(s_Corners[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) for (var i = 1; i < 4; ++i)
{ {
if (s_Corners[i].x < corner1.x) if (s_Corners[i].x < corner1.x)
{
corner1.x = s_Corners[i].x; corner1.x = s_Corners[i].x;
}
else if (s_Corners[i].x > corner2.x) else if (s_Corners[i].x > corner2.x)
{
corner2.x = s_Corners[i].x; corner2.x = s_Corners[i].x;
}
if (s_Corners[i].y < corner1.y) if (s_Corners[i].y < corner1.y)
{
corner1.y = s_Corners[i].y; corner1.y = s_Corners[i].y;
}
else if (s_Corners[i].y > corner2.y) else if (s_Corners[i].y > corner2.y)
{
corner2.y = s_Corners[i].y; corner2.y = s_Corners[i].y;
}
} }
return new Rect(corner1, corner2 - corner1); 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) public static UIParticleRenderer AddRenderer(UIParticle parent, int index)
{ {
// Create renderer object. // Create renderer object.
var go = new GameObject("UIParticleRenderer", typeof(UIParticleRenderer)) var go = new GameObject("UIParticleRenderer", typeof(UIParticleRenderer))
{ {
hideFlags = HideFlags.DontSave, hideFlags = HideFlags.DontSave,
layer = parent.gameObject.layer, layer = parent.gameObject.layer
}; };
// Set parent. // Set parent.
@ -139,45 +204,14 @@ namespace Coffee.UIExtensions
return modifiedMaterial; return modifiedMaterial;
} }
public void Reset(int index = -1) public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
{
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)
{ {
_parent = parent; _parent = parent;
maskable = parent.maskable; maskable = parent.maskable;
gameObject.layer = parent.gameObject.layer; gameObject.layer = parent.gameObject.layer;
_particleSystem = particleSystem; _particleSystem = ps;
_prewarm = _particleSystem.main.prewarm; _prewarm = _particleSystem.main.prewarm;
#if UNITY_EDITOR #if UNITY_EDITOR
@ -191,7 +225,7 @@ namespace Coffee.UIExtensions
} }
} }
_renderer = particleSystem.GetComponent<ParticleSystemRenderer>(); _renderer = ps.GetComponent<ParticleSystemRenderer>();
_renderer.enabled = false; _renderer.enabled = false;
//_emitter = emitter; //_emitter = emitter;
@ -202,9 +236,11 @@ namespace Coffee.UIExtensions
s_Materials.Clear(); s_Materials.Clear();
// Support sprite. // Support sprite.
var tsa = particleSystem.textureSheetAnimation; var tsa = ps.textureSheetAnimation;
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0) if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
{
tsa.uvChannelMask = UVChannelFlags.UV0; tsa.uvChannelMask = UVChannelFlags.UV0;
}
_prevScale = GetWorldScale(); _prevScale = GetWorldScale();
_prevPsPos = _particleSystem.transform.position; _prevPsPos = _particleSystem.transform.position;
@ -221,15 +257,17 @@ namespace Coffee.UIExtensions
{ {
// No particle to render: Clear mesh. // No particle to render: Clear mesh.
if ( if (
!isActiveAndEnabled || !_particleSystem || !_parent || !canvasRenderer || !canvas || !bakeCamera !isActiveAndEnabled || !_particleSystem || !_parent
|| !canvasRenderer || !canvas || !bakeCamera
|| _parent.meshSharing == UIParticle.MeshSharing.Replica || _parent.meshSharing == UIParticle.MeshSharing.Replica
|| !transform.lossyScale.GetScaled(_parent.scale3D).IsVisible() // Scale is not visible. || !transform.lossyScale.GetScaled(_parent.scale3D).IsVisible() // Scale is not visible.
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle. || (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled. || (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
#if UNITY_2018_3_OR_NEWER #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 #endif
) )
{ {
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh"); Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
workerMesh.Clear(); workerMesh.Clear();
@ -265,15 +303,20 @@ namespace Coffee.UIExtensions
} }
// When the ParticleSystem simulation is complete, stop it. // 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); _particleSystem.Stop(false);
} }
} }
_prevScale = scale; _prevScale = scale;
_prevPsPos = psPos; _prevPsPos = psPos;
_delay = false; _delay = false;
} }
Profiler.EndSample(); Profiler.EndSample();
// Bake mesh. // Bake mesh.
@ -295,7 +338,7 @@ namespace Coffee.UIExtensions
if (65535 <= s_CombineInstances[0].mesh.vertexCount) if (65535 <= s_CombineInstances[0].mesh.vertexCount)
{ {
s_CombineInstances[0].mesh.Clear(false); 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)", "Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)",
_index, _index,
_isTrail, _isTrail,
@ -303,6 +346,7 @@ namespace Coffee.UIExtensions
); );
s_CombineInstances[0].mesh.Clear(false); s_CombineInstances[0].mesh.Clear(false);
} }
Profiler.EndSample(); Profiler.EndSample();
// Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local) // Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local)
@ -311,13 +355,19 @@ namespace Coffee.UIExtensions
{ {
if (_parent.absoluteMode) if (_parent.absoluteMode)
{ {
s_CombineInstances[0].transform = canvasRenderer.transform.worldToLocalMatrix * GetWorldMatrix(psPos, scale); s_CombineInstances[0].transform =
canvasRenderer.transform.worldToLocalMatrix
* GetWorldMatrix(psPos, scale);
} }
else else
{ {
var diff = _particleSystem.transform.position - _parent.transform.position; 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.CombineMeshes(s_CombineInstances, true, true);
workerMesh.RecalculateBounds(); workerMesh.RecalculateBounds();
@ -331,6 +381,7 @@ namespace Coffee.UIExtensions
workerMesh.bounds = bounds; workerMesh.bounds = bounds;
_lastBounds = bounds; _lastBounds = bounds;
} }
Profiler.EndSample(); Profiler.EndSample();
@ -343,7 +394,7 @@ namespace Coffee.UIExtensions
// Set mesh to the CanvasRenderer. // Set mesh to the CanvasRenderer.
Profiler.BeginSample("[UIParticleRenderer] Set Mesh"); 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; if (s_Renderers[i] == this) continue;
s_Renderers[i].canvasRenderer.SetMesh(workerMesh); s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
@ -354,6 +405,7 @@ namespace Coffee.UIExtensions
{ {
workerMesh.Clear(); workerMesh.Clear();
} }
canvasRenderer.SetMesh(workerMesh); canvasRenderer.SetMesh(workerMesh);
Profiler.EndSample(); Profiler.EndSample();
@ -366,7 +418,8 @@ namespace Coffee.UIExtensions
{ {
_currentMaterialForRendering = materialForRendering; _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; if (s_Renderers[i] == this) continue;
@ -374,6 +427,7 @@ namespace Coffee.UIExtensions
s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0); s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0);
} }
} }
Profiler.EndSample(); Profiler.EndSample();
s_Renderers.Clear(); s_Renderers.Clear();
@ -385,30 +439,6 @@ namespace Coffee.UIExtensions
_prevParticleCount = _particleSystem.particleCount; _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;
}
/// <summary> /// <summary>
/// Call to update the geometry of the Graphic onto the CanvasRenderer. /// Call to update the geometry of the Graphic onto the CanvasRenderer.
/// </summary> /// </summary>
@ -418,7 +448,9 @@ namespace Coffee.UIExtensions
public override void Cull(Rect clipRect, bool validRect) 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; if (canvasRenderer.cull == cull) return;
canvasRenderer.cull = cull; canvasRenderer.cull = cull;
@ -450,8 +482,8 @@ namespace Coffee.UIExtensions
{ {
case ParticleSystemSimulationSpace.World: case ParticleSystemSimulationSpace.World:
return Matrix4x4.Translate(psPos) return Matrix4x4.Translate(psPos)
* Matrix4x4.Scale(scale) * Matrix4x4.Scale(scale)
* Matrix4x4.Translate(-psPos); * Matrix4x4.Translate(-psPos);
} }
} }
#endif #endif
@ -460,17 +492,17 @@ namespace Coffee.UIExtensions
{ {
case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Local:
return Matrix4x4.Translate(psPos) return Matrix4x4.Translate(psPos)
* Matrix4x4.Scale(scale); * Matrix4x4.Scale(scale);
case ParticleSystemSimulationSpace.World: case ParticleSystemSimulationSpace.World:
return Matrix4x4.Scale(scale); return Matrix4x4.Scale(scale);
case ParticleSystemSimulationSpace.Custom: case ParticleSystemSimulationSpace.Custom:
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale)) return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
//* Matrix4x4.Translate(wpos) //* Matrix4x4.Translate(wpos)
* Matrix4x4.Scale(scale) * Matrix4x4.Scale(scale)
//* Matrix4x4.Translate(-wpos) //* Matrix4x4.Translate(-wpos)
; ;
default: default:
throw new System.NotSupportedException(); throw new NotSupportedException();
} }
} }
@ -482,8 +514,9 @@ namespace Coffee.UIExtensions
private void ResolveResolutionChange(Vector3 psPos, Vector3 scale) private void ResolveResolutionChange(Vector3 psPos, Vector3 scale)
{ {
var screenSize = new Vector2Int(Screen.width, Screen.height); var screenSize = new Vector2Int(Screen.width, Screen.height);
//if ((_prevScreenSize != screenSize || _prevScale != scale) && _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World && _parent.uiScaling) var isWorldSpace = _particleSystem.IsWorldSpace();
if ((_prevScreenSize != screenSize || _prevScale != scale) && _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World) var resolutionChanged = _prevScreenSize != screenSize || _prevScale != scale;
if (resolutionChanged && isWorldSpace)
{ {
// Update particle array size and get particles. // Update particle array size and get particles.
var size = _particleSystem.particleCount; var size = _particleSystem.particleCount;
@ -492,13 +525,17 @@ namespace Coffee.UIExtensions
// Resolusion resolver: // Resolusion resolver:
// (psPos / scale) / (prevPsPos / prevScale) -> psPos * scale.inv * prevPsPos.inv * prevScale // (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++) for (var i = 0; i < size; i++)
{ {
var particle = particles[i]; var particle = particles[i];
particle.position = particle.position.GetScaled(modifier); particle.position = particle.position.GetScaled(modifier);
particles[i] = particle; particles[i] = particle;
} }
_particleSystem.SetParticles(particles, size); _particleSystem.SetParticles(particles, size);
// Delay: Do not progress in the frame where the resolution has been changed. // Delay: Do not progress in the frame where the resolution has been changed.
@ -506,6 +543,7 @@ namespace Coffee.UIExtensions
_prevScale = scale; _prevScale = scale;
_prevPsPos = psPos; _prevPsPos = psPos;
} }
_prevScreenSize = screenSize; _prevScreenSize = screenSize;
} }
@ -548,13 +586,14 @@ namespace Coffee.UIExtensions
var psTransform = _particleSystem.transform; var psTransform = _particleSystem.transform;
var originWorldPosition = psTransform.position; var originWorldPosition = psTransform.position;
var originWorldRotation = psTransform.rotation; var originWorldRotation = psTransform.rotation;
var emission = _particleSystem.emission; 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) if (rateOverDistance)
{ {
// (For rate-over-distance emission,) Move to previous scaled position, simulate (delta = 0). // (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); psTransform.SetPositionAndRotation(prevScaledPos, originWorldRotation);
_particleSystem.Simulate(0, false, false, false); _particleSystem.Simulate(0, false, false, false);
} }
@ -570,7 +609,8 @@ namespace Coffee.UIExtensions
private void SimulateForEditor(Vector3 diffPos, Vector3 scale) private void SimulateForEditor(Vector3 diffPos, Vector3 scale)
{ {
// Extra world simulation. // 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"); Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x); diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x);
@ -598,7 +638,9 @@ namespace Coffee.UIExtensions
if (_parent.m_AnimatableProperties.Length == 0) return; if (_parent.m_AnimatableProperties.Length == 0) return;
if (s_Mpb == null) if (s_Mpb == null)
{
s_Mpb = new MaterialPropertyBlock(); s_Mpb = new MaterialPropertyBlock();
}
_renderer.GetPropertyBlock(s_Mpb); _renderer.GetPropertyBlock(s_Mpb);
if (s_Mpb.isEmpty) return; if (s_Mpb.isEmpty) return;
@ -606,8 +648,9 @@ namespace Coffee.UIExtensions
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer // #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
if (!_modifiedMaterial) return; 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); ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb);
} }

View File

@ -1,21 +1,19 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Coffee.UIExtensions namespace Coffee.UIExtensions
{ {
internal static class UIParticleUpdater internal static class UIParticleUpdater
{ {
static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>(); private static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>(); private static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>();
static readonly HashSet<int> s_UpdatedGroupIds = new HashSet<int>(); private static readonly HashSet<int> s_UpdatedGroupIds = new HashSet<int>();
private static int frameCount = 0; private static int s_FrameCount;
public static int uiParticleCount public static int uiParticleCount
{ {
get get { return s_ActiveParticles.Count; }
{
return s_ActiveParticles.Count;
}
} }
public static void Register(UIParticle particle) public static void Register(UIParticle particle)
@ -43,7 +41,7 @@ namespace Coffee.UIExtensions
} }
#if UNITY_EDITOR #if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod] [InitializeOnLoadMethod]
#endif #endif
[RuntimeInitializeOnLoadMethod] [RuntimeInitializeOnLoadMethod]
private static void InitializeOnLoad() private static void InitializeOnLoad()
@ -55,8 +53,8 @@ namespace Coffee.UIExtensions
private static void Refresh() private static void Refresh()
{ {
// Do not allow it to be called in the same frame. // Do not allow it to be called in the same frame.
if (frameCount == Time.frameCount) return; if (s_FrameCount == Time.frameCount) return;
frameCount = Time.frameCount; s_FrameCount = Time.frameCount;
// Simulate -> Primary // Simulate -> Primary
for (var i = 0; i < s_ActiveParticles.Count; i++) for (var i = 0; i < s_ActiveParticles.Count; i++)
@ -129,6 +127,7 @@ namespace Coffee.UIExtensions
if (uip.isPrimary) return uip; if (uip.isPrimary) return uip;
if (!primary && uip.canSimulate) primary = uip; if (!primary && uip.canSimulate) primary = uip;
} }
return primary; return primary;
} }
} }

View File

@ -46,11 +46,11 @@ namespace Coffee.UIParticleExtensions
internal static class SpriteExtensions internal static class SpriteExtensions
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
private static Type tSpriteEditorExtension = private static readonly Type s_SpriteEditorExtensionType =
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor") Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
?? Type.GetType("UnityEditor.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); .GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
public static Texture2D GetActualTexture(this Sprite self) public static Texture2D GetActualTexture(this Sprite self)
@ -58,8 +58,10 @@ namespace Coffee.UIParticleExtensions
if (!self) return null; if (!self) return null;
if (Application.isPlaying) return self.texture; if (Application.isPlaying) return self.texture;
var ret = miGetActiveAtlasTexture.Invoke(null, new[] { self }) as Texture2D; var ret = s_GetActiveAtlasTextureMethodInfo.Invoke(null, new object[] { self }) as Texture2D;
return ret ? ret : self.texture; return ret
? ret
: self.texture;
} }
#else #else
internal static Texture2D GetActualTexture(this Sprite self) internal static Texture2D GetActualTexture(this Sprite self)
@ -77,12 +79,14 @@ namespace Coffee.UIParticleExtensions
{ {
if (s_TmpParticles.Length < size) if (s_TmpParticles.Length < size)
{ {
while(s_TmpParticles.Length < size) while (s_TmpParticles.Length < size)
{ {
size = Mathf.NextPowerOfTwo(size); size = Mathf.NextPowerOfTwo(size);
} }
s_TmpParticles = new ParticleSystem.Particle[size]; s_TmpParticles = new ParticleSystem.Particle[size];
} }
return s_TmpParticles; return s_TmpParticles;
} }
@ -102,47 +106,69 @@ namespace Coffee.UIParticleExtensions
var main = self.main; var main = self.main;
var space = main.simulationSpace; var space = main.simulationSpace;
if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace) if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace)
{
space = ParticleSystemSimulationSpace.Local; space = ParticleSystemSimulationSpace.Local;
}
return space; 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<ParticleSystem> self, Transform transform, bool sortByMaterial) public static void SortForRendering(this List<ParticleSystem> self, Transform transform, bool sortByMaterial)
{ {
self.Sort((a, b) => self.Sort((a, b) =>
{ {
var tr = transform;
var aRenderer = a.GetComponent<ParticleSystemRenderer>(); var aRenderer = a.GetComponent<ParticleSystemRenderer>();
var bRenderer = b.GetComponent<ParticleSystemRenderer>(); var bRenderer = b.GetComponent<ParticleSystemRenderer>();
// Render queue: ascending // Render queue: ascending
var aMat = aRenderer.sharedMaterial ?? aRenderer.trailMaterial; var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
var bMat = bRenderer.sharedMaterial ?? bRenderer.trailMaterial; var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
if (!aMat && !bMat) return 0; if (!aMat && !bMat) return 0;
if (!aMat) return -1; if (!aMat) return -1;
if (!bMat) return 1; if (!bMat) return 1;
if (sortByMaterial) if (sortByMaterial)
{
return aMat.GetInstanceID() - bMat.GetInstanceID(); return aMat.GetInstanceID() - bMat.GetInstanceID();
}
if (aMat.renderQueue != bMat.renderQueue) if (aMat.renderQueue != bMat.renderQueue)
{
return aMat.renderQueue - bMat.renderQueue; return aMat.renderQueue - bMat.renderQueue;
}
// Sorting layer: ascending // Sorting layer: ascending
if (aRenderer.sortingLayerID != bRenderer.sortingLayerID) 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 // Sorting order: ascending
if (aRenderer.sortingOrder != bRenderer.sortingOrder) if (aRenderer.sortingOrder != bRenderer.sortingOrder)
{
return aRenderer.sortingOrder - bRenderer.sortingOrder; return aRenderer.sortingOrder - bRenderer.sortingOrder;
}
// Z position & sortingFudge: descending // Z position & sortingFudge: descending
var aTransform = a.transform; var aTransform = a.transform;
var bTransform = b.transform; var bTransform = b.transform;
var aPos = tr.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge; var aPos = transform.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge;
var bPos = tr.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge; var bPos = transform.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge;
if (!Mathf.Approximately(aPos, bPos)) if (!Mathf.Approximately(aPos, bPos))
{
return (int)Mathf.Sign(bPos - aPos); return (int)Mathf.Sign(bPos - aPos);
}
return (int)Mathf.Sign(GetIndex(self, a) - GetIndex(self, b)); 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++) 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; return 0;
@ -183,4 +212,37 @@ namespace Coffee.UIParticleExtensions
self.ForEach(action); 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);
}
}
}
} }