diff --git a/Scripts/MeshHelper.cs b/Scripts/MeshHelper.cs index 3830706..2a4f79a 100644 --- a/Scripts/MeshHelper.cs +++ b/Scripts/MeshHelper.cs @@ -6,12 +6,13 @@ namespace Coffee.UIParticleExtensions { internal static class MeshHelper { - public static long activeMeshIndices { get; private set; } + public static List activeMeshIndices { get; private set; } private static readonly List s_CachedInstance; private static int count; public static void Init() { + activeMeshIndices = new List(); } static MeshHelper() @@ -64,13 +65,13 @@ namespace Coffee.UIParticleExtensions inst.Push(mesh, transform); Profiler.EndSample(); - activeMeshIndices |= (long) 1 << inst.index; + activeMeshIndices[inst.index] = true; } public static void Clear() { count = 0; - activeMeshIndices = 0; + activeMeshIndices.Clear(); foreach (var inst in s_CachedInstance) { inst.Clear(); diff --git a/Scripts/UIParticle.cs b/Scripts/UIParticle.cs index e78a67c..3cdf3c2 100755 --- a/Scripts/UIParticle.cs +++ b/Scripts/UIParticle.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using Coffee.UIParticleExtensions; using UnityEngine; @@ -44,7 +43,7 @@ namespace Coffee.UIExtensions private Mesh _bakedMesh; private readonly List _modifiedMaterials = new List(); private readonly List _maskMaterials = new List(); - private long _activeMeshIndices; + private readonly List _activeMeshIndices = new List(); private Vector3 _cachedPosition; private static readonly List s_TempMaterials = new List(2); private static MaterialPropertyBlock s_Mpb; @@ -117,13 +116,14 @@ namespace Coffee.UIExtensions get { return _modifiedMaterials; } } - internal long activeMeshIndices + public List activeMeshIndices { get { return _activeMeshIndices; } set { - if (_activeMeshIndices == value) return; - _activeMeshIndices = value; + if (_activeMeshIndices.SequenceEqualFast(value)) return; + _activeMeshIndices.Clear(); + _activeMeshIndices.AddRange(value); UpdateMaterial(); } } @@ -228,9 +228,9 @@ namespace Coffee.UIExtensions } // No mesh to render. - if (activeMeshIndices == 0 || !isActiveAndEnabled || particles.Count == 0) + var count = activeMeshIndices.CountFast(); + if (count == 0 || !isActiveAndEnabled || particles.Count == 0) { - _activeMeshIndices = 0; canvasRenderer.Clear(); foreach (var m in s_PrevMaskMaterials) @@ -242,7 +242,7 @@ namespace Coffee.UIExtensions } // - var materialCount = Mathf.Max(8, activeMeshIndices.BitCount()); + var materialCount = Mathf.Max(8, count); canvasRenderer.materialCount = materialCount; var j = 0; for (var i = 0; i < particles.Count; i++) @@ -255,8 +255,8 @@ namespace Coffee.UIExtensions r.GetSharedMaterials(s_TempMaterials); // Main - var bit = (long) 1 << (i * 2); - if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count) + var index = i * 2; + if (activeMeshIndices[index] && 0 < s_TempMaterials.Count) { var mat = GetModifiedMaterial(s_TempMaterials[0], ps.GetTextureForSprite()); canvasRenderer.SetMaterial(mat, j); @@ -265,9 +265,9 @@ namespace Coffee.UIExtensions } // Trails + index++; if (materialCount <= j) break; - bit <<= 1; - if (0 < (activeMeshIndices & bit) && 1 < s_TempMaterials.Count) + if (activeMeshIndices[index] && 1 < s_TempMaterials.Count) { var mat = GetModifiedMaterial(s_TempMaterials[1], null); canvasRenderer.SetMaterial(mat, j++); @@ -303,7 +303,8 @@ namespace Coffee.UIExtensions if (m_AnimatableProperties.Length == 0) return; // - var materialCount = Mathf.Max(8, activeMeshIndices.BitCount()); + var count = activeMeshIndices.CountFast(); + var materialCount = Mathf.Max(8, count); canvasRenderer.materialCount = materialCount; var j = 0; for (var i = 0; i < particles.Count; i++) @@ -316,8 +317,7 @@ namespace Coffee.UIExtensions r.GetSharedMaterials(s_TempMaterials); // Main - var bit = (long) 1 << (i * 2); - if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count) + if (activeMeshIndices[i * 2] && 0 < s_TempMaterials.Count) { UpdateMaterialProperties(r, j); j++; @@ -350,7 +350,7 @@ namespace Coffee.UIExtensions protected override void OnEnable() { _cachedPosition = transform.localPosition; - _activeMeshIndices = 0; + activeMeshIndices.Clear(); UIParticleUpdater.Register(this); particles.Exec(p => p.GetComponent().enabled = false); @@ -418,7 +418,7 @@ namespace Coffee.UIExtensions return; } - if (!this || particles.Any(x => x)) return; + if (!this || particles.AnyFast()) return; // refresh. #if UNITY_EDITOR diff --git a/Scripts/UIParticleUpdater.cs b/Scripts/UIParticleUpdater.cs index 3fc0391..d3c68c6 100755 --- a/Scripts/UIParticleUpdater.cs +++ b/Scripts/UIParticleUpdater.cs @@ -129,8 +129,10 @@ namespace Coffee.UIExtensions private static void BakeMesh(UIParticle particle) { // Clear mesh before bake. + Profiler.BeginSample("[UIParticle] Bake Mesh > Clear mesh before bake"); MeshHelper.Clear(); particle.bakedMesh.Clear(false); + Profiler.EndSample(); // Get camera for baking mesh. var camera = BakingCamera.GetCamera(particle.canvas); @@ -153,11 +155,17 @@ namespace Coffee.UIExtensions for (var i = 0; i < particle.particles.Count; i++) { + Profiler.BeginSample("[UIParticle] Bake Mesh > Push index"); + MeshHelper.activeMeshIndices.Add(false); + MeshHelper.activeMeshIndices.Add(false); + Profiler.EndSample(); + // No particle to render. var currentPs = particle.particles[i]; if (!currentPs || !currentPs.IsAlive() || currentPs.particleCount == 0) continue; // Calc matrix. + Profiler.BeginSample("[UIParticle] Bake Mesh > Calc matrix"); var matrix = rootMatrix; if (currentPs.transform != root) { @@ -177,6 +185,7 @@ namespace Coffee.UIExtensions } matrix = scaleMatrix * matrix; + Profiler.EndSample(); // Extra world simulation. if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude) @@ -245,7 +254,9 @@ namespace Coffee.UIExtensions } // Set active indices. + Profiler.BeginSample("[UIParticle] Bake Mesh > Set active indices"); particle.activeMeshIndices = MeshHelper.activeMeshIndices; + Profiler.EndSample(); // Combine Profiler.BeginSample("[UIParticle] Bake Mesh > CombineMesh"); diff --git a/Scripts/Utils.cs b/Scripts/Utils.cs index ad7d60d..a14f61e 100644 --- a/Scripts/Utils.cs +++ b/Scripts/Utils.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Reflection; using UnityEngine; +using Object = UnityEngine.Object; namespace Coffee.UIParticleExtensions { @@ -30,13 +31,38 @@ namespace Coffee.UIParticleExtensions #endif } - internal static class LongExtensions + internal static class ListExtensions { - public static int BitCount(this long self) + public static bool SequenceEqualFast(this List self, List value) { - self = self - ((self >> 1) & 0x5555555555555555L); - self = (self & 0x3333333333333333L) + ((self >> 2) & 0x3333333333333333L); - return (int) (unchecked(((self + (self >> 4)) & 0xF0F0F0F0F0F0F0FL) * 0x101010101010101L) >> 56); + if (self.Count != value.Count) return false; + for (var i = 0; i < self.Count; ++i) + { + if (self[i] != value[i]) return false; + } + + return true; + } + + public static int CountFast(this List self) + { + var count = 0; + for (var i = 0; i < self.Count; ++i) + { + if (self[i]) count++; + } + + return count; + } + + public static bool AnyFast(this List self) where T : Object + { + for (var i = 0; i < self.Count; ++i) + { + if (self[i]) return true; + } + + return false; } } @@ -107,24 +133,28 @@ namespace Coffee.UIParticleExtensions internal static class CombineInstanceArrayPool { - private static readonly List s_Pool; + private static readonly Dictionary s_Pool; public static void Init() { + s_Pool.Clear(); } static CombineInstanceArrayPool() { - s_Pool = new List(32); - for (var i = 0; i < 32; i++) - { - s_Pool.Add(new CombineInstance[i]); - } + s_Pool = new Dictionary(); } public static CombineInstance[] Get(List src) { - var dst = s_Pool[src.Count]; + CombineInstance[] dst; + var count = src.Count; + if (!s_Pool.TryGetValue(count, out dst)) + { + dst = new CombineInstance[count]; + s_Pool.Add(count, dst); + } + for (var i = 0; i < src.Count; i++) { dst[i].mesh = src[i].mesh; @@ -136,7 +166,13 @@ namespace Coffee.UIParticleExtensions public static CombineInstance[] Get(List src, int count) { - var dst = s_Pool[count]; + CombineInstance[] dst; + if (!s_Pool.TryGetValue(count, out dst)) + { + dst = new CombineInstance[count]; + s_Pool.Add(count, dst); + } + for (var i = 0; i < count; i++) { dst[i].mesh = src[i].mesh;