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();
        }
        public AtomAnimationClip AddTransitionAnimation()
        {
            var next = _animation.GetClip(_clip.animationLayer, _clip.nextAnimationName);

            if (next == null)
            {
                SuperController.LogError("There is no animation to transition to");
                return(null);
            }

            var clip = _animation.CreateClip(_clip);

            clip.animationName              = $"{_clip.animationName} > {next.animationName}";
            clip.loop                       = false;
            clip.autoTransitionPrevious     = _animation.index.ByLayer(_clip.animationLayer).Any(c => c.animationLayer == _clip.animationLayer);
            clip.autoTransitionNext         = _clip.nextAnimationName != null;
            clip.nextAnimationName          = _clip.nextAnimationName;
            clip.blendInDuration            = AtomAnimationClip.DefaultBlendDuration;
            clip.nextAnimationTime          = clip.animationLength - clip.blendInDuration;
            clip.ensureQuaternionContinuity = _clip.ensureQuaternionContinuity;

            foreach (var origTarget in _clip.targetControllers)
            {
                var newTarget = CopyTarget(clip, origTarget);
                newTarget.SetCurveSnapshot(0f, origTarget.GetCurveSnapshot(_clip.animationLength));
                newTarget.SetCurveSnapshot(clip.animationLength, next.targetControllers.First(t => t.TargetsSameAs(origTarget)).GetCurveSnapshot(0f));
            }
            foreach (var origTarget in _clip.targetFloatParams)
            {
                if (!origTarget.EnsureAvailable(false))
                {
                    continue;
                }
                var newTarget = clip.Add(origTarget.storable, origTarget.floatParam);
                newTarget.SetCurveSnapshot(0f, origTarget.GetCurveSnapshot(_clip.animationLength));
                newTarget.SetCurveSnapshot(clip.animationLength, next.targetFloatParams.First(t => t.TargetsSameAs(origTarget)).GetCurveSnapshot(0f));
            }

            _animation.clips.Remove(clip);
            _animation.clips.Insert(_animation.clips.IndexOf(_clip) + 1, clip);

            _clip.nextAnimationName = clip.animationName;
            return(clip);
        }
Beispiel #3
0
        public List <AtomAnimationClip> ImportClip(AtomAnimationClip clip)
        {
            var clips = new List <AtomAnimationClip>();

            var matchingLayer = _animation.clips.FirstOrDefault(c =>
            {
                // We only need to match float params and controllers, triggers can be in any layers
                if (!clip.targetFloatParams.All(t => c.targetFloatParams.Any(t.TargetsSameAs)))
                {
                    return(false);
                }
                if (!clip.targetControllers.All(t => c.targetControllers.Any(t.TargetsSameAs)))
                {
                    return(false);
                }
                return(true);
            });

            if (matchingLayer != null)
            {
                clip.animationLayer = matchingLayer.animationLayer;

                // Add missing targets
                foreach (var target in matchingLayer.targetFloatParams)
                {
                    if (!clip.targetFloatParams.Any(t => target.TargetsSameAs(t)))
                    {
                        var missing = new FloatParamAnimationTarget(target);
                        missing.AddEdgeFramesIfMissing(clip.animationLength);
                        clip.Add(missing);
                    }
                }
                foreach (var target in matchingLayer.targetControllers)
                {
                    if (!clip.targetControllers.Any(t => target.TargetsSameAs(t)))
                    {
                        var missing = new FreeControllerAnimationTarget(target.controller);
                        missing.AddEdgeFramesIfMissing(clip.animationLength);
                        clip.Add(missing);
                    }
                }
            }
            else if (_animation.index.ByLayer(clip.animationLayer).Any())
            {
                clip.animationLayer = new LayersOperations(_animation, clip).GetNewLayerName();
            }

            foreach (var controller in clip.targetControllers.Select(t => t.controller))
            {
                if (_animation.clips.Where(c => c.animationLayer != clip.animationLayer).Any(c => c.targetControllers.Any(t => t.controller == controller)))
                {
                    if (!_silent)
                    {
                        SuperController.LogError($"Timeline: Imported animation contains controller {controller.name} in layer {clip.animationLayer}, but that controller is already used elsewhere in your animation. To import, a layer is needed with targets: {string.Join(", ", clip.GetAllCurveTargets().Select(c => c.GetShortName()).ToArray())}");
                    }
                    return(clips);
                }
            }

            foreach (var floatParam in clip.targetFloatParams.Select(t => t.name))
            {
                if (_animation.clips.Where(c => c.animationLayer != clip.animationLayer).Any(c => c.targetFloatParams.Any(t => t.name == floatParam)))
                {
                    if (!_silent)
                    {
                        SuperController.LogError($"Timeline: Imported animation contains storable float {floatParam} in layer {clip.animationLayer}, but that storable is already used elsewhere in your animation. To import, a layer is needed with targets: {string.Join(", ", clip.GetAllCurveTargets().Select(c => c.GetShortName()).ToArray())}");
                    }
                    return(clips);
                }
            }

            var existingClip = _animation.GetClip(clip.animationLayer, clip.animationName);

            if (existingClip != null)
            {
                if (existingClip.IsEmpty())
                {
                    _animation.clips.Remove(existingClip);
                    existingClip.Dispose();
                }
                else
                {
                    var newAnimationName = GenerateUniqueAnimationName(clip.animationLayer, clip.animationName);
                    if (!_silent)
                    {
                        SuperController.LogError($"Timeline: Imported clip '{clip.animationNameQualified}' already exists and will be imported with the name {newAnimationName}");
                    }
                    clip.animationName = newAnimationName;
                }
            }

            clips.Add(clip);
            return(clips);
        }
Beispiel #4
0
 private AtomAnimationClip GetClip(object[] e)
 {
     return(animation.GetClip((string)e[1]));
 }