public void PreviewEditModePose(Playable playable,
                                        ISkeletonComponent skeletonComponent, IAnimationStateComponent animationStateComponent,
                                        SkeletonAnimation skeletonAnimation, SkeletonGraphic skeletonGraphic)
        {
            if (Application.isPlaying)
            {
                return;
            }
            if (animationStateComponent.IsNullOrDestroyed() || skeletonComponent == null)
            {
                return;
            }

            int inputCount             = playable.GetInputCount();
            int lastNonZeroWeightTrack = -1;

            for (int i = 0; i < inputCount; i++)
            {
                float inputWeight = playable.GetInputWeight(i);
                if (inputWeight > 0)
                {
                    lastNonZeroWeightTrack = i;
                }
            }

            if (lastNonZeroWeightTrack != -1)
            {
                ScriptPlayable <SpineAnimationStateBehaviour> inputPlayableClip =
                    (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastNonZeroWeightTrack);
                SpineAnimationStateBehaviour clipData = inputPlayableClip.GetBehaviour();

                var skeleton = skeletonComponent.Skeleton;

                bool skeletonDataMismatch = clipData.animationReference != null && clipData.animationReference.SkeletonDataAsset &&
                                            skeletonComponent.SkeletonDataAsset.GetSkeletonData(true) != clipData.animationReference.SkeletonDataAsset.GetSkeletonData(true);
                if (skeletonDataMismatch)
                {
                    Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}",
                                           skeletonComponent.SkeletonDataAsset, clipData.animationReference.SkeletonDataAsset);
                }

                // Getting the from-animation here because it's required to get the mix information from AnimationStateData.
                Animation fromAnimation = null;
                float     fromClipTime  = 0;
                bool      fromClipLoop  = false;
                if (lastNonZeroWeightTrack != 0 && inputCount > 1)
                {
                    var fromClip     = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastNonZeroWeightTrack - 1);
                    var fromClipData = fromClip.GetBehaviour();
                    fromAnimation = fromClipData.animationReference != null ? fromClipData.animationReference.Animation : null;
                    fromClipTime  = (float)fromClip.GetTime() * (float)fromClip.GetSpeed();
                    fromClipLoop  = fromClipData.loop;
                }

                Animation toAnimation = clipData.animationReference != null ? clipData.animationReference.Animation : null;
                float     toClipTime  = (float)inputPlayableClip.GetTime() * (float)inputPlayableClip.GetSpeed();
                float     mixDuration = clipData.mixDuration;

                if (!clipData.customDuration && fromAnimation != null && toAnimation != null)
                {
                    mixDuration = animationStateComponent.AnimationState.Data.GetMix(fromAnimation, toAnimation);
                }

                if (trackIndex == 0)
                {
                    skeleton.SetToSetupPose();
                }

                // Approximate what AnimationState might do at runtime.
                if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration)
                {
                    dummyAnimationState = dummyAnimationState ?? new AnimationState(skeletonComponent.SkeletonDataAsset.GetAnimationStateData());

                    var  toEntry   = dummyAnimationState.GetCurrent(0);
                    var  fromEntry = toEntry != null ? toEntry.MixingFrom : null;
                    bool isAnimationTransitionMatch = (toEntry != null && toEntry.Animation == toAnimation && fromEntry != null && fromEntry.Animation == fromAnimation);

                    if (!isAnimationTransitionMatch)
                    {
                        dummyAnimationState.ClearTracks();
                        fromEntry = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop);
                        fromEntry.AllowImmediateQueue();
                        if (toAnimation != null)
                        {
                            toEntry = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop);
                            toEntry.HoldPrevious = clipData.holdPrevious;
                        }
                    }

                    // Update track times.
                    fromEntry.TrackTime = fromClipTime;
                    if (toEntry != null)
                    {
                        toEntry.TrackTime = toClipTime;
                        toEntry.MixTime   = toClipTime;
                    }

                    // Apply Pose
                    dummyAnimationState.Update(0);
                    dummyAnimationState.Apply(skeleton);
                }
                else
                {
                    if (toAnimation != null)
                    {
                        toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, 1f, MixBlend.Setup, MixDirection.In);
                    }
                }
                skeleton.UpdateWorldTransform();

                if (skeletonAnimation)
                {
                    skeletonAnimation.LateUpdate();
                }
                else if (skeletonGraphic)
                {
                    skeletonGraphic.LateUpdate();
                }
            }
            // Do nothing outside of the first clip and the last clip.
        }
        // NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties.
        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
            var skeletonAnimation       = playerData as SkeletonAnimation;
            var skeletonGraphic         = playerData as SkeletonGraphic;
            var animationStateComponent = playerData as IAnimationStateComponent;
            var skeletonComponent       = playerData as ISkeletonComponent;

            if (animationStateComponent == null || skeletonComponent == null)
            {
                return;
            }

            var skeleton = skeletonComponent.Skeleton;
            var state    = animationStateComponent.AnimationState;

            if (!Application.isPlaying)
            {
                                #if SPINE_EDITMODEPOSE
                PreviewEditModePose(playable, skeletonComponent, animationStateComponent,
                                    skeletonAnimation, skeletonGraphic);
                                #endif
                return;
            }

            int inputCount = playable.GetInputCount();

            // Ensure correct buffer size.
            if (this.lastInputWeights == null || this.lastInputWeights.Length < inputCount)
            {
                this.lastInputWeights = new float[inputCount];

                for (int i = 0; i < inputCount; i++)
                {
                    this.lastInputWeights[i] = default(float);
                }
            }
            var lastInputWeights = this.lastInputWeights;

            // Check all clips. If a clip that was weight 0 turned into weight 1, call SetAnimation.
            for (int i = 0; i < inputCount; i++)
            {
                float lastInputWeight = lastInputWeights[i];
                float inputWeight     = playable.GetInputWeight(i);
                bool  trackStarted    = lastInputWeight == 0 && inputWeight > 0;
                lastInputWeights[i] = inputWeight;

                if (trackStarted)
                {
                    ScriptPlayable <SpineAnimationStateBehaviour> inputPlayable = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(i);
                    SpineAnimationStateBehaviour clipData = inputPlayable.GetBehaviour();

                    if (clipData.animationReference == null)
                    {
                        float mixDuration = clipData.customDuration ? clipData.mixDuration : state.Data.DefaultMix;
                        state.SetEmptyAnimation(trackIndex, mixDuration);
                    }
                    else
                    {
                        if (clipData.animationReference.Animation != null)
                        {
                            Spine.TrackEntry trackEntry = state.SetAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop);

                            trackEntry.EventThreshold      = clipData.eventThreshold;
                            trackEntry.DrawOrderThreshold  = clipData.drawOrderThreshold;
                            trackEntry.TrackTime           = (float)inputPlayable.GetTime() * (float)inputPlayable.GetSpeed();
                            trackEntry.TimeScale           = (float)inputPlayable.GetSpeed();
                            trackEntry.AttachmentThreshold = clipData.attachmentThreshold;
                            trackEntry.HoldPrevious        = clipData.holdPrevious;

                            if (clipData.customDuration)
                            {
                                trackEntry.MixDuration = clipData.mixDuration;
                            }
                        }
                        //else Debug.LogWarningFormat("Animation named '{0}' not found", clipData.animationName);
                    }

                    // Ensure that the first frame ends with an updated mesh.
                    if (skeletonAnimation)
                    {
                        skeletonAnimation.Update(0);
                        skeletonAnimation.LateUpdate();
                    }
                    else if (skeletonGraphic)
                    {
                        skeletonGraphic.Update(0);
                        skeletonGraphic.LateUpdate();
                    }
                }
            }
        }
        // NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties.
        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
            var skeletonAnimation = playerData as SkeletonAnimation;
            var skeletonGraphic   = playerData as SkeletonGraphic;

            animationStateComponent = playerData as IAnimationStateComponent;
            var skeletonComponent = playerData as ISkeletonComponent;

            if (animationStateComponent.IsNullOrDestroyed() || skeletonComponent == null)
            {
                return;
            }

            var skeleton = skeletonComponent.Skeleton;
            var state    = animationStateComponent.AnimationState;

            if (!Application.isPlaying)
            {
#if SPINE_EDITMODEPOSE
                PreviewEditModePose(playable, skeletonComponent, animationStateComponent,
                                    skeletonAnimation, skeletonGraphic);
#endif
                return;
            }

            int inputCount = playable.GetInputCount();

            // Ensure correct buffer size.
            if (this.lastInputWeights == null || this.lastInputWeights.Length < inputCount)
            {
                this.lastInputWeights = new float[inputCount];

                for (int i = 0; i < inputCount; i++)
                {
                    this.lastInputWeights[i] = default(float);
                }
            }
            var  lastInputWeights = this.lastInputWeights;
            int  numStartingClips = 0;
            bool anyClipPlaying   = false;

            // Check all clips. If a clip that was weight 0 turned into weight 1, call SetAnimation.
            for (int i = 0; i < inputCount; i++)
            {
                float lastInputWeight = lastInputWeights[i];
                float inputWeight     = playable.GetInputWeight(i);
                bool  clipStarted     = lastInputWeight == 0 && inputWeight > 0;
                if (inputWeight > 0)
                {
                    anyClipPlaying = true;
                }
                lastInputWeights[i] = inputWeight;

                if (clipStarted && numStartingClips < 2)
                {
                    ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(i);
                    startingClips[numStartingClips++] = clipPlayable;
                }
            }
            // unfortunately order of clips can be wrong when two start at the same time, we have to sort clips
            if (numStartingClips == 2)
            {
                ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable0 = startingClips[0];
                ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable1 = startingClips[1];
                if (clipPlayable0.GetDuration() > clipPlayable1.GetDuration())                   // swap, clip 0 ends after clip 1
                {
                    startingClips[0] = clipPlayable1;
                    startingClips[1] = clipPlayable0;
                }
            }

            for (int j = 0; j < numStartingClips; ++j)
            {
                ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable = startingClips[j];
                SpineAnimationStateBehaviour clipData = clipPlayable.GetBehaviour();
                pauseWithDirector = !clipData.dontPauseWithDirector;
                endAtClipEnd      = !clipData.dontEndWithClip;
                endMixOutDuration = clipData.endMixOutDuration;

                if (clipData.animationReference == null)
                {
                    float mixDuration = clipData.customDuration ? GetCustomMixDuration(clipData) : state.Data.DefaultMix;
                    state.SetEmptyAnimation(trackIndex, mixDuration);
                }
                else
                {
                    if (clipData.animationReference.Animation != null)
                    {
                        TrackEntry       currentEntry = state.GetCurrent(trackIndex);
                        Spine.TrackEntry trackEntry;
                        float            customMixDuration = clipData.customDuration ? GetCustomMixDuration(clipData) : 0.0f;
                        if (currentEntry == null && customMixDuration > 0)
                        {
                            state.SetEmptyAnimation(trackIndex, 0);                             // ease in requires empty animation
                            trackEntry = state.AddAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop, 0);
                        }
                        else
                        {
                            trackEntry = state.SetAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop);
                        }

                        trackEntry.EventThreshold      = clipData.eventThreshold;
                        trackEntry.DrawOrderThreshold  = clipData.drawOrderThreshold;
                        trackEntry.TrackTime           = (float)clipPlayable.GetTime() * (float)clipPlayable.GetSpeed();
                        trackEntry.TimeScale           = (float)clipPlayable.GetSpeed();
                        trackEntry.AttachmentThreshold = clipData.attachmentThreshold;
                        trackEntry.HoldPrevious        = clipData.holdPrevious;

                        if (clipData.customDuration)
                        {
                            trackEntry.MixDuration = customMixDuration;
                        }

                        timelineStartedTrackEntry = trackEntry;
                    }
                    //else Debug.LogWarningFormat("Animation named '{0}' not found", clipData.animationName);
                }

                // Ensure that the first frame ends with an updated mesh.
                if (skeletonAnimation)
                {
                    skeletonAnimation.Update(0);
                    skeletonAnimation.LateUpdate();
                }
                else if (skeletonGraphic)
                {
                    skeletonGraphic.Update(0);
                    skeletonGraphic.LateUpdate();
                }
            }
            startingClips[0] = startingClips[1] = ScriptPlayable <SpineAnimationStateBehaviour> .Null;
            if (lastAnyClipPlaying && !anyClipPlaying)
            {
                HandleClipEnd();
            }
            this.lastAnyClipPlaying = anyClipPlaying;
        }
    // NOTE: This function is called at runtime and edit time.  Keep that in mind when setting the values of properties.
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        int inputCount = playable.GetInputCount();

        bool densityFieldCleared = false;

#if !UNITY_EDITOR
        //check the current time of timeline

        /*       PlayableDirector director = DFMRef_.gameObject.GetComponent<PlayableDirector>();
         *     int frame = -1;
         *
         *     if (director != null)
         *     {
         #if UNITY_PS4
         *         int frameRate = 60;
         #else
         *         int frameRate = 90;
         #endif
         *         //frame = (int)(director.time * frameRate);
         *     }
         *
         *     if (lastMixerFrame == frame)
         *         return;
         *
         *     lastMixerFrame = frame;*/
#endif

        for (int i = 0; i < inputCount; i++)
        {
            float inputWeight = playable.GetInputWeight(i);

            if (inputWeight > 0.0f)
            {
                ScriptPlayable <PointCloudBehaviour> inputPlayable = (ScriptPlayable <PointCloudBehaviour>)playable.GetInput(i);
                float time = (float)inputPlayable.GetTime();
                PointCloudBehaviour input = inputPlayable.GetBehaviour();

#if UNITY_EDITOR
                if (input.PointCloudDirectory != input.PointCloudDirectoryInternal)
                {
                    input.SetFrameFileList();
                }
#endif

                if (input.frameFiles.Length == 0)
                {
                    continue;
                }

                if (!densityFieldCleared)
                {
                    ClearDensityField(DFMRef_.Resolution);
                    densityFieldCleared = true;
                }

                float frameRate = 30.0f * (float)inputPlayable.GetSpeed();

                int   newFrame = (int)(time * frameRate);
                float fraction = (time * frameRate) - (int)(time * frameRate);
                Shader.SetGlobalFloat("_ArtSpaces_frame_fraction", fraction);

                bool forceReload = false;
                if (newFrame - input.frameNo != 0 && newFrame - input.frameNo != 1)
                {
                    forceReload = true;
#if UNITY_EDITOR
                    UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
#endif
                }
                input.frameNo = newFrame;

                if (input.frameNo >= input.frameFiles.Length)
                {
                    input.frameNo = input.frameFiles.Length - 1;
                }

                int nextFrameNo = newFrame + 1;

                if (nextFrameNo >= input.frameFiles.Length)
                {
                    nextFrameNo = input.frameFiles.Length - 1;
                }

                SetParticleClipFrameName(input.GetHashCode(), input.frameFiles[input.frameNo], input.frameFiles[nextFrameNo], fraction, inputWeight * input.influence, DFMRef_.Resolution,
                                         input.scale.x, input.scale.y, input.scale.z, input.translate.x, input.translate.y, input.translate.z, forceReload);

                //Debug.Log("Current frame: " + input.frameNo + "   Next frame: " + nextFrameNo + " fraction: " + fraction);
            }
        }

        DFMRef_.numPointCloudParticles_ = GenerateDensityField(GetHashCode());
        if (DFMRef_.numPointCloudParticles_ >= 0)
        {
            DFMRef_.particleBuffer_.SetData(particles_, 0, 0, DFMRef_.numPointCloudParticles_);
        }
    }