//--------------- Serialize / Deserialize --------------------
        public static byte[] Serialize(ParticleDataSnapshot input)
        {
            if (input == null)
                return null;

            ComposedByteStream stream = ComposedByteStream.FetchStream(input.particleSystems.Count);
            int iMax = input.particleSystems.Count;
            for (int i = 0; i < iMax; i++)
                stream.AddStream(SGenericParticleSystem.Serialize(input.particleSystems[i]));

            return stream.Compose();
        }
        public void GetResultEOF(ref ParticleDataSnapshot storeTo)
        {
            ParticleSystem[] systems = GameObject.FindObjectsOfType<ParticleSystem>();
            SGenericParticleSystem[] surrogates = new SGenericParticleSystem[systems.Length];

            if(systems != null && systems.Length > 0){
                int i = systems.Length;
                while(--i > -1)                {
                    ParticleSystem system = systems[i];
                    if (system == null)
                        continue;

                    //--------------- Check if captureable --------------------
                    int id = system.GetInstanceID();
                    if (flaggedAsCapturable.ContainsKey(id)) {
                        if (!flaggedAsCapturable[id])
                            continue;
                    } else {
                        bool isCaptureable = GameObjectUtility.GetComponentInParent<vBugParticleRecordable>(system.gameObject) != null;
                        flaggedAsCapturable.Add(id, isCaptureable);

                        if (!isCaptureable)
                            continue;
                    }
                    //--------------- Check if captureable --------------------

                    Renderer renderer = system.GetComponent<Renderer>();
                    if (renderer == null || !(renderer is ParticleSystemRenderer))
                        continue;

                    ParticleSystem.Particle[] particles = GetParticleBuffer(system.particleCount); //fetch buffer;
                    int maxParticles = system.GetParticles(particles);

                    //--------------- Local to world --------------------
                    Matrix4x4 m = system.transform.localToWorldMatrix;
                    if (system.simulationSpace == ParticleSystemSimulationSpace.Local) {
                        for (int p = 0; p < maxParticles; p++)
                            particles[p].position = m.MultiplyPoint(particles[p].position);
                    }
                    //--------------- Local to world --------------------

                    SGenericParticleSystem surrogate = new SGenericParticleSystem(system, (ParticleSystemRenderer)renderer, particles, maxParticles);
                    surrogate.renderer.materialInstanceID = MaterialDataGrabber.RegisterMaterial(system);
                    surrogates[i] = surrogate;
                    buffers.Add(particles); //store buffer

                }
            }

            storeTo.particleSystems.AddRange(surrogates);
        }
        public void GetResultEOF(ref ParticleDataSnapshot storeTo)
        {
            ParticleEmitter[] emitters = GameObject.FindObjectsOfType<ParticleEmitter>();
            SGenericParticleSystem[] surrogates = new SGenericParticleSystem[emitters.Length];

            int e = 0;
            if (emitters != null && emitters.Length > 0) {
                int i = emitters.Length;
                while (--i > -1){
                    ParticleEmitter emitter = emitters[i];

                    //--------------- Check if captureable --------------------
                    int id = emitter.GetInstanceID();
                    if (flaggedAsCapturable.ContainsKey(id)) {
                        if (!flaggedAsCapturable[id])
                            continue;
                    } else {
                        bool isCaptureable = GameObjectUtility.GetComponentInParent<vBugParticleRecordable>(emitter.gameObject) != null;
                        flaggedAsCapturable.Add(id, isCaptureable);

                        if(!isCaptureable)
                            continue;
                    }
                    //--------------- Check if captureable --------------------

                    ParticleRenderer renderer = emitter.gameObject.GetComponent<ParticleRenderer>();
                    if (renderer != null){
                        Particle[] particles = emitter.particles;

                        if (!emitter.useWorldSpace) {
                            Matrix4x4 m = emitter.transform.localToWorldMatrix;
                            for (int p = 0; p < particles.Length; p++)
                                particles[p].position = m.MultiplyPoint(particles[p].position);
                        }

                        SGenericParticleSystem surrogate = new SGenericParticleSystem(emitter, renderer, particles);
                        surrogate.renderer.materialInstanceID = MaterialDataGrabber.RegisterMaterial(renderer);
                        surrogates[e++] = surrogate;
                    }
                }
            }

            if (e != emitters.Length)
                Array.Resize(ref surrogates, e);

            storeTo.particleSystems.AddRange(surrogates);
        }
        public static ParticleDataSnapshot Deserialize(byte[] input)
        {
            if (input == null || input.Length == 0)
                return null;

            ComposedByteStream stream = ComposedByteStream.FromByteArray(input);
            if (stream == null)
                return null;

            ParticleDataSnapshot result = new ParticleDataSnapshot();
            int iMax = stream.streamCount;
            result.particleSystems = new List<SGenericParticleSystem>(iMax);

            for (int i = 0; i < iMax; i++)
                result.particleSystems.Add(SGenericParticleSystem.Deserialize(stream.ReadNextStream<byte>()));

            stream.Dispose();
            return result;
        }
        //--------------- External commands --------------------
        public void DrawSlice(int frameNumber)
        {
            if (state == SceneVisualState.off || currentFrameNumber == frameNumber)
                return;

            VerticalActivitySlice slice = GetClosestAvailableSlice(frameNumber);
            if (slice == null) {
                Dispose();
                return;
            }
            currentFrameNumber = slice.header.frameNumber;

            if (currentLevelName != slice.header.levelName) {
                PruneAllVisualizers();
                currentLevelName = slice.header.levelName;
            }

            if(slice.particleData == null) {
                return;

            } else {
                ParticleDataSnapshot data = slice.particleData;
                if (data.particleSystems != null && data.particleSystems.Count > 0){
                    currentFrameData = data;
                    int iMax = data.particleSystems.Count;
                    List<int> updatedIDs = new List<int>();
                    List<int> missingIDs = new List<int>();

                    //--------------- Update/Add representors --------------------
                    for (int i = 0; i < iMax; i++) {
                        SGenericParticleSystem sParticles = data.particleSystems[i];
                        if (sParticles == null || sParticles.particles == null || sParticles.particles.positions == null || sParticles.particles.positions.Length == 0)
                            continue;

                        if (!representors.ContainsKey(sParticles.instanceID))
                            representors.Add(sParticles.instanceID, ParticleSystemSurrogate.Create(sParticles.name));

                        ParticleSystemSurrogate representor = representors[sParticles.instanceID];
                        representor.SetParticles(slice.header.frameNumber, sParticles.renderer, sParticles.particles);
                        updatedIDs.Add(sParticles.instanceID);
                    }
                    //--------------- Update/Add representors --------------------

                    //--------------- Remove missing --------------------
                    foreach (KeyValuePair<int, ParticleSystemSurrogate> pair in representors) {
                        if (!updatedIDs.Contains(pair.Key))
                            missingIDs.Add(pair.Key);
                    }

                    if (missingIDs.Count > 0) {
                        foreach (int id in missingIDs) {
                            GameObject.DestroyImmediate(representors[id].gameObject);
                            representors.Remove(id);
                        }
                    }
                    //--------------- Remove missing --------------------
                }
            }
        }
        public void PruneAllVisualizers()
        {
            ParticleSystemSurrogate[] leftovers = Resources.FindObjectsOfTypeAll<ParticleSystemSurrogate>();
            int i = leftovers.Length;
            while (--i > -1)
                GameObject.DestroyImmediate(leftovers[i].gameObject);

            representors.Clear();
            currentFrameNumber = 0;
            currentFrameData = null;
            Reset();
        }
        //Todo:Add material data and make all dispose calls recursive.
        public override void Dispose()
        {
            base.Dispose();

            if (header != null) header.Dispose();
            if (systemInfo != null) systemInfo.Dispose();
            if (debugLogs != null) debugLogs.Dispose();
            if (humanInput != null) humanInput.Dispose();
            if (meshData != null) meshData.Dispose();
            if (particleData != null) particleData.Dispose();
            if (materialData != null) materialData.Dispose();
            if (gameObjectsSnapshot != null) gameObjectsSnapshot.Dispose();

            header = null;
            systemInfo = null;
            debugLogs = null;
            humanInput = null;
            meshData = null;
            particleData = null;
            materialData = null;
            gameObjectsSnapshot = null;
            screenCapture = null;
        }