public void ImportClips(IEnumerable <AtomAnimationClip> clips)
        {
            var importedClips = new List <AtomAnimationClip>();

            _animation.index.StartBulkUpdates();
            try
            {
                foreach (var clip in clips.SelectMany(ImportClip))
                {
                    clip.Validate();
                    _animation.AddClip(clip);
                    importedClips.Add(clip);
                }
            }
            finally
            {
                _animation.index.EndBulkUpdates();
            }

            foreach (var clip in importedClips)
            {
                if (clip.autoPlay && _animation.index.ByLayer(clip.animationLayer).Any(c => c.autoPlay))
                {
                    clip.autoPlay = false;
                }
            }

            _animation.RebuildAnimationNow();
        }
        public void DeserializeAnimation(AtomAnimation animation, JSONClass animationJSON)
        {
            if (animation == null)
            {
                throw new ArgumentNullException(nameof(animation));
            }

            animation.speed  = DeserializeFloat(animationJSON["Speed"], 1f);
            animation.master = DeserializeBool(animationJSON["Master"], false);

            animation.index.StartBulkUpdates();
            try
            {
                var clipsJSON = animationJSON["Clips"].AsArray;
                if (clipsJSON == null || clipsJSON.Count == 0)
                {
                    throw new NullReferenceException("Saved state does not have clips");
                }
                foreach (JSONClass clipJSON in clipsJSON)
                {
                    var clip = DeserializeClip(clipJSON);
                    animation.AddClip(clip);
                }
            }
            finally
            {
                animation.index.EndBulkUpdates();
            }
        }
        public void DeserializeAnimation(AtomAnimation animation, JSONClass animationJSON)
        {
            if (animation == null)
            {
                throw new ArgumentNullException(nameof(animation));
            }

            animation.speed = DeserializeFloat(animationJSON["Speed"], 1f);

            JSONArray clipsJSON = animationJSON["Clips"].AsArray;

            if (clipsJSON == null || clipsJSON.Count == 0)
            {
                throw new NullReferenceException("Saved state does not have clips");
            }
            foreach (JSONClass clipJSON in clipsJSON)
            {
                var animationName  = clipJSON["AnimationName"].Value;
                var animationLayer = DeserializeString(clipJSON["AnimationLayer"], AtomAnimationClip.DefaultAnimationLayer);
                var existingClip   = animation.GetClip(animationName);
                if (existingClip != null)
                {
                    if (existingClip.IsEmpty())
                    {
                        var clipToRemove = animation.GetClip(animationName);
                        animation.clips.Remove(clipToRemove);
                        clipToRemove.Dispose();
                    }
                    else
                    {
                        var newAnimationName = GenerateUniqueAnimationName(animation, animationName);
                        SuperController.LogError($"VamTimeline: Imported clip '{animationName}' already exists and will be imported with the name {newAnimationName}");
                        animationName = newAnimationName;
                    }
                }
                var clip = new AtomAnimationClip(animationName, animationLayer)
                {
                    blendDuration = DeserializeFloat(clipJSON["BlendDuration"], AtomAnimationClip.DefaultBlendDuration),
                    loop          = DeserializeBool(clipJSON["Loop"], true),
                    transition    = DeserializeBool(clipJSON["Transition"], false),
                    ensureQuaternionContinuity = DeserializeBool(clipJSON["EnsureQuaternionContinuity"], true),
                    nextAnimationName          = clipJSON["NextAnimationName"]?.Value,
                    nextAnimationTime          = DeserializeFloat(clipJSON["NextAnimationTime"], 0),
                    autoPlay = DeserializeBool(clipJSON["AutoPlay"], false),
                    speed    = DeserializeFloat(clipJSON["Speed"], 1),
                    weight   = DeserializeFloat(clipJSON["Weight"], 1),
                };
                clip.animationLength = DeserializeFloat(clipJSON["AnimationLength"]).Snap();
                DeserializeClip(clip, clipJSON);
                animation.AddClip(clip);
            }
            animation.Initialize();
            animation.RebuildAnimationNow();
        }