using System; using System.Collections.Generic; using UnityEngine; using Object = UnityEngine.Object; namespace Coffee.UIParticleInternal { internal static class ParticleSystemExtensions { private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048]; public static ParticleSystem.Particle[] GetParticleArray(int size) { if (s_TmpParticles.Length < size) { while (s_TmpParticles.Length < size) { size = Mathf.NextPowerOfTwo(size); } s_TmpParticles = new ParticleSystem.Particle[size]; } return s_TmpParticles; } public static void ValidateShape(this ParticleSystem self) { var shape = self.shape; if (shape.enabled && shape.alignToDirection) { if (Mathf.Approximately(shape.scale.x * shape.scale.y * shape.scale.z, 0)) { if (Mathf.Approximately(shape.scale.x, 0)) { shape.scale.Set(0.0001f, shape.scale.y, shape.scale.z); } else if (Mathf.Approximately(shape.scale.y, 0)) { shape.scale.Set(shape.scale.x, 0.0001f, shape.scale.z); } else if (Mathf.Approximately(shape.scale.z, 0)) { shape.scale.Set(shape.scale.x, shape.scale.y, 0.0001f); } } } } public static bool CanBakeMesh(this ParticleSystemRenderer self) { // #69: Editor crashes when mesh is set to null when `ParticleSystem.RenderMode = Mesh` if (self.renderMode == ParticleSystemRenderMode.Mesh && self.mesh == null) return false; // #61: When `ParticleSystem.RenderMode = None`, an error occurs if (self.renderMode == ParticleSystemRenderMode.None) return false; return true; } public static ParticleSystemSimulationSpace GetActualSimulationSpace(this ParticleSystem self) { var main = self.main; var space = main.simulationSpace; if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace) { space = ParticleSystemSimulationSpace.Local; } return space; } public static bool IsLocalSpace(this ParticleSystem self) { return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.Local; } public static bool IsWorldSpace(this ParticleSystem self) { return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.World; } public static void SortForRendering(this List self, Transform transform, bool sortByMaterial) { self.Sort((a, b) => { var aRenderer = a.GetComponent(); var bRenderer = b.GetComponent(); // Render queue: ascending var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial; var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial; if (!aMat && !bMat) return 0; if (!aMat) return -1; if (!bMat) return 1; if (sortByMaterial) { return aMat.GetInstanceID() - bMat.GetInstanceID(); } if (aMat.renderQueue != bMat.renderQueue) { return aMat.renderQueue - bMat.renderQueue; } // Sorting layer: ascending if (aRenderer.sortingLayerID != bRenderer.sortingLayerID) { return SortingLayer.GetLayerValueFromID(aRenderer.sortingLayerID) - SortingLayer.GetLayerValueFromID(bRenderer.sortingLayerID); } // Sorting order: ascending if (aRenderer.sortingOrder != bRenderer.sortingOrder) { return aRenderer.sortingOrder - bRenderer.sortingOrder; } // Z position & sortingFudge: descending var aTransform = a.transform; var bTransform = b.transform; var aPos = transform.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge; var bPos = transform.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge; if (!Mathf.Approximately(aPos, bPos)) { return (int)Mathf.Sign(bPos - aPos); } return (int)Mathf.Sign(GetIndex(self, a) - GetIndex(self, b)); }); } private static int GetIndex(IList list, Object ps) { for (var i = 0; i < list.Count; i++) { if (list[i].GetInstanceID() == ps.GetInstanceID()) { return i; } } return 0; } public static Texture2D GetTextureForSprite(this ParticleSystem self) { if (!self) return null; // Get sprite's texture. var tsaModule = self.textureSheetAnimation; if (!tsaModule.enabled || tsaModule.mode != ParticleSystemAnimationMode.Sprites) return null; for (var i = 0; i < tsaModule.spriteCount; i++) { var sprite = tsaModule.GetSprite(i); if (!sprite) continue; return sprite.GetActualTexture(); } return null; } public static void Exec(this List self, Action action) { foreach (var p in self) { if (!p) continue; action.Invoke(p); } } } }