public void Copy()
        {
            try
            {
                if (!CanEdit())
                {
                    return;
                }

                var time  = clipTime;
                var entry = AtomAnimationClip.Copy(time, GetAllOrSelectedTargets().ToList());

                if (entry.empty)
                {
                    SuperController.LogMessage("Timeline: Nothing to copy");
                }
                else
                {
                    clipboard.Clear();
                    clipboard.time = time;
                    clipboard.entries.Add(entry);
                }
            }
            catch (Exception exc)
            {
                SuperController.LogError($"Timeline.{nameof(AtomAnimationEditContext)}.{nameof(Copy)}: {exc}");
            }
        }
Esempio n. 2
0
        public void CopyDeleteSelected(bool copy, bool delete)
        {
            plugin.animationEditContext.clipboard.Clear();
            plugin.animationEditContext.clipboard.time = _startJSON.valNoCallback;
            foreach (var target in animationEditContext.GetAllOrSelectedTargets())
            {
                target.StartBulkUpdates();
                try
                {
                    var keyframes = target.GetAllKeyframesTime();
                    for (var key = keyframes.Length - 1; key >= 0; key--)
                    {
                        var keyTime = keyframes[key];
                        if (keyTime < _startJSON.val || keyTime > _endJSON.val)
                        {
                            continue;
                        }

                        if (copy)
                        {
                            plugin.animationEditContext.clipboard.entries.Insert(0, AtomAnimationClip.Copy(keyTime, animationEditContext.GetAllOrSelectedTargets().ToList()));
                        }
                        if (delete && !keyTime.IsSameFrame(0) && !keyTime.IsSameFrame(current.animationLength))
                        {
                            target.DeleteFrame(keyTime);
                        }
                    }
                }
                finally
                {
                    target.EndBulkUpdates();
                }
            }
        }
        public void StopClip(AtomAnimationClip clip)
        {
            if (clip.playbackEnabled)
            {
                clip.Leave();
                clip.Reset(false);
                if (clip.animationPattern)
                {
                    clip.animationPattern.SetBoolParamValue("loopOnce", true);
                }
            }
            else
            {
                clip.playbackMainInLayer = false;
            }

            if (isPlaying)
            {
                if (!clips.Any(c => c.playbackMainInLayer))
                {
                    isPlaying  = false;
                    sequencing = false;
                }

                onIsPlayingChanged.Invoke(clip);
            }
        }
Esempio n. 4
0
 private void OnClipIsPlayingChanged(AtomAnimationClip clip)
 {
     if (animation.master && clip.playbackEnabled && animation.sequencing)
     {
         peers.SendMasterClipState(clip);
     }
 }
Esempio n. 5
0
        public virtual void Bind(IAtomPlugin plugin, AtomAnimationClip clip, T target)
        {
            this.plugin = plugin;
            this.clip   = clip;
            this.target = target;

            CreateToggle(plugin);
            toggle.label = target.GetShortName();

            CreateCustom();

            valueText = CreateValueText();

            _expandButton = CreateExpandButton();
            var expandListener = _expandButton.AddComponent <Clickable>();

            expandListener.onClick.AddListener(pointerEvent => ToggleExpanded());

            this.plugin.animationEditContext.onTimeChanged.AddListener(OnTimeChanged);
            OnTimeChanged(this.plugin.animationEditContext.timeArgs);

            target.onAnimationKeyframesRebuilt.AddListener(OnAnimationKeyframesRebuilt);

            OnAnimationKeyframesRebuilt();
        }
Esempio n. 6
0
        private void RebuildTransition(AtomAnimationClip clip)
        {
            bool realign  = false;
            var  previous = clips.FirstOrDefault(c => c.nextAnimationName == clip.animationName);

            if (previous != null && (previous.IsDirty() || clip.IsDirty()))
            {
                clip.Paste(0f, previous.Copy(previous.animationLength, previous.GetAllCurveTargets().Cast <IAtomAnimationTarget>()), false);
                realign = true;
            }
            var next = GetClip(clip.nextAnimationName);

            if (next != null && (next.IsDirty() || clip.IsDirty()))
            {
                clip.Paste(clip.animationLength, next.Copy(0f, next.GetAllCurveTargets().Cast <IAtomAnimationTarget>()), false);
                realign = true;
            }
            if (realign)
            {
                foreach (var target in clip.targetControllers)
                {
                    if (clip.ensureQuaternionContinuity)
                    {
                        UnitySpecific.EnsureQuaternionContinuityAndRecalculateSlope(
                            target.rotX,
                            target.rotY,
                            target.rotZ,
                            target.rotW);
                    }
                }
            }
        }
        public AtomAnimationClip DeserializeClip(JSONClass clipJSON)
        {
            var  animationName    = clipJSON["AnimationName"].Value;
            var  animationLayer   = DeserializeString(clipJSON["AnimationLayer"], AtomAnimationClip.DefaultAnimationLayer);
            bool?legacyTransition = null;

            if (clipJSON.HasKey("Transition"))
            {
                legacyTransition = DeserializeBool(clipJSON["Transition"], false);
            }

            var clip = new AtomAnimationClip(animationName, animationLayer)
            {
                blendInDuration            = DeserializeFloat(clipJSON["BlendDuration"], AtomAnimationClip.DefaultBlendDuration),
                loop                       = DeserializeBool(clipJSON["Loop"], true),
                autoTransitionPrevious     = legacyTransition ?? DeserializeBool(clipJSON["AutoTransitionPrevious"], false),
                autoTransitionNext         = legacyTransition ?? DeserializeBool(clipJSON["AutoTransitionNext"], false),
                preserveLoops              = DeserializeBool(clipJSON["SyncTransitionTime"], false),
                ensureQuaternionContinuity = DeserializeBool(clipJSON["EnsureQuaternionContinuity"], true),
                nextAnimationName          = clipJSON["NextAnimationName"]?.Value,
                nextAnimationTime          = DeserializeFloat(clipJSON["NextAnimationTime"]),
                nextAnimationTimeRandomize = DeserializeFloat(clipJSON["NextAnimationTimeRandomize"]),
                autoPlay                   = DeserializeBool(clipJSON["AutoPlay"], false),
                speed                      = DeserializeFloat(clipJSON["Speed"], 1),
                weight                     = DeserializeFloat(clipJSON["Weight"], 1),
                uninterruptible            = DeserializeBool(clipJSON["Uninterruptible"], false),
                animationLength            = DeserializeFloat(clipJSON["AnimationLength"]).Snap()
            };

            DeserializeClip(clip, clipJSON);
            return(clip);
        }
Esempio n. 8
0
        private IEnumerator UpdateAnimButton(UIDynamicButton btn, AtomAnimationClip clip)
        {
            yield return(0);

            var playLabel = $" \u25B6 {clip.animationName}";

            while (!_disposing)
            {
                if (!clip.playbackEnabled && !clip.playbackMainInLayer)
                {
                    if (btn.label != playLabel)
                    {
                        btn.label = playLabel;
                    }
                }
                else
                {
                    btn.label = $" \u25A0 [time: {clip.clipTime:00.000}, weight: {Mathf.Round(clip.playbackBlendWeight * 100f):000}%]";
                }

                for (var i = 0; i < 4; i++)
                {
                    yield return(0);
                }
            }
        }
Esempio n. 9
0
        public void SelectAnimation(AtomAnimationClip clip)
        {
            var previous = current;

            current = clip;

            if (previous != null)
            {
                previous.Leave();
            }

            if (previous.animationLayer != current.animationLayer)
            {
                onClipsListChanged.Invoke();
            }
            onCurrentAnimationChanged.Invoke(new CurrentAnimationChangedEventArgs
            {
                before = previous,
                after  = current
            });

            if (isPlaying)
            {
                var previousMain = clips.FirstOrDefault(c => c.playbackMainInLayer && c.animationLayer == current.animationLayer);
                if (previousMain != null)
                {
                    TransitionAnimation(previousMain, current);
                }
            }
            else
            {
                clipTime = 0f;
                Sample();
            }
        }
Esempio n. 10
0
        public void Bind(IAtomPlugin plugin, AtomAnimationClip clip, T target)
        {
            this.plugin = plugin;
            this.clip   = clip;
            this.target = target;

            CreateToggle(plugin);
            toggle.label = target.name;

            CreateCustom();

            valueText = CreateValueText();

            _expandButton = CreateExpandButton();
            var expandListener = _expandButton.AddComponent <Clickable>();

            expandListener.onClick.AddListener(pointerEvent => ToggleExpanded());

            this.plugin.animation.TimeChanged.AddListener(this.OnTimeChanged);
            OnTimeChanged(this.plugin.animation.Time);

            target.onAnimationKeyframesModified.AddListener(OnAnimationKeyframesModified);

            OnAnimationKeyframesModified();
        }
Esempio n. 11
0
 public void RemoveClip(AtomAnimationClip clip)
 {
     clips.Remove(clip);
     clip.Dispose();
     onClipsListChanged.Invoke();
     OnAnimationKeyframesDirty();
 }
Esempio n. 12
0
 public void RemoveClip(AtomAnimationClip clip)
 {
     Clips.Remove(clip);
     clip.Dispose();
     ClipsListChanged.Invoke();
     OnAnimationModified();
 }
Esempio n. 13
0
        private string GetNewAnimationName(AtomAnimationClip source)
        {
            var    match = _lastDigitsRegex.Match(source.animationName);
            string animationNameBeforeInt;
            int    animationNameInt;

            if (!match.Success)
            {
                animationNameBeforeInt = $"{source.animationName.TrimEnd()} ";
                animationNameInt       = 1;
            }
            else
            {
                animationNameBeforeInt = match.Groups["name"].Value;
                animationNameInt       = int.Parse(match.Groups["index"].Value);
            }
            for (var i = animationNameInt + 1; i < 999; i++)
            {
                var animationName = animationNameBeforeInt + i;
                if (clips.All(c => c.animationName != animationName))
                {
                    return(animationName);
                }
            }
            return(Guid.NewGuid().ToString());
        }
        private void SerializeClip(AtomAnimationClip clip, JSONClass clipJSON)
        {
            if (clip.animationPattern != null)
            {
                clipJSON.Add("AnimationPattern", clip.animationPattern.containingAtom.uid);
            }

            var controllersJSON = new JSONArray();

            clipJSON.Add("Controllers", controllersJSON);
            foreach (var controller in clip.targetControllers)
            {
                var controllerJSON = new JSONClass
                {
                    { "Controller", controller.controller.name },
                    { "X", SerializeCurve(controller.x, controller.settings) },
                    { "Y", SerializeCurve(controller.y, controller.settings) },
                    { "Z", SerializeCurve(controller.z, controller.settings) },
                    { "RotX", SerializeCurve(controller.rotX, controller.settings) },
                    { "RotY", SerializeCurve(controller.rotY, controller.settings) },
                    { "RotZ", SerializeCurve(controller.rotZ, controller.settings) },
                    { "RotW", SerializeCurve(controller.rotW, controller.settings) }
                };
                controllersJSON.Add(controllerJSON);
            }

            var paramsJSON = new JSONArray();

            clipJSON.Add("FloatParams", paramsJSON);
            foreach (var target in clip.targetFloatParams)
            {
                var paramJSON = new JSONClass
                {
                    { "Storable", target.storableId },
                    { "Name", target.floatParamName },
                    { "Value", SerializeCurve(target.value, target.settings) },
                };
                paramsJSON.Add(paramJSON);
            }

            var triggersJSON = new JSONArray();

            clipJSON.Add("", triggersJSON);
            clipJSON.Add("Triggers", triggersJSON);
            foreach (var target in clip.targetTriggers)
            {
                var triggerJSON = new JSONClass()
                {
                    { "Name", target.name }
                };
                var entriesJSON = new JSONArray();
                foreach (var x in target.triggersMap.OrderBy(kvp => kvp.Key))
                {
                    entriesJSON.Add(x.Value.GetJSON());
                }
                triggerJSON["Triggers"] = entriesJSON;
                triggersJSON.Add(triggerJSON);
            }
        }
Esempio n. 15
0
        private static void RebuildClip(AtomAnimationClip clip, AtomAnimationClip previous)
        {
            foreach (var target in clip.targetControllers)
            {
                if (!target.dirty)
                {
                    continue;
                }

                if (clip.loop)
                {
                    target.SetCurveSnapshot(clip.animationLength, target.GetCurveSnapshot(0f), false);
                }

                target.ComputeCurves();

                if (clip.ensureQuaternionContinuity)
                {
                    var lastMatching = previous?.targetControllers.FirstOrDefault(t => t.TargetsSameAs(target));
                    var q            = lastMatching?.GetRotationAtKeyframe(lastMatching.rotX.length - 1) ?? target.GetRotationAtKeyframe(target.rotX.length - 1);
                    UnitySpecific.EnsureQuaternionContinuityAndRecalculateSlope(
                        target.rotX,
                        target.rotY,
                        target.rotZ,
                        target.rotW,
                        q);
                }

                foreach (var curve in target.GetCurves())
                {
                    curve.ComputeCurves();
                }
            }

            foreach (var target in clip.targetFloatParams)
            {
                if (!target.dirty)
                {
                    continue;
                }

                if (clip.loop)
                {
                    target.SetCurveSnapshot(clip.animationLength, target.GetCurveSnapshot(0), false);
                }

                target.value.ComputeCurves();
            }

            foreach (var target in clip.targetTriggers)
            {
                if (!target.dirty)
                {
                    continue;
                }

                target.RebuildKeyframes(clip.animationLength);
            }
        }
Esempio n. 16
0
        public AtomAnimationClip AddAnimation()
        {
            string animationName = GetNewAnimationName();
            var    clip          = new AtomAnimationClip(animationName);

            AddClip(clip);
            return(clip);
        }
Esempio n. 17
0
 public virtual void Init(IAtomPlugin plugin)
 {
     this.plugin          = plugin;
     prefabFactory        = gameObject.AddComponent <VamPrefabFactory>();
     prefabFactory.plugin = plugin;
     plugin.animation.onCurrentAnimationChanged.AddListener(OnCurrentAnimationChanged);
     current = plugin.animation?.current;
 }
Esempio n. 18
0
        private AtomAnimationClip WithStorable(TestContext context, AtomAnimationClip clip, string name)
        {
            var storable = context.gameObject.GetComponent <JSONStorable>() ?? context.gameObject.AddComponent <JSONStorable>();
            var target   = clip.Add(new FloatParamAnimationTarget(storable, new JSONStorableFloat(name, 0, 0, 1)));

            target.AddEdgeFramesIfMissing(clip.animationLength);
            return(clip);
        }
Esempio n. 19
0
        private void ReapplyClipCurve(AtomAnimationClip clip)
        {
            clip.Clip.ClearCurves();

            foreach (var target in clip.TargetControllers)
            {
                target.ReapplyCurvesToClip(clip.Clip);
            }
        }
Esempio n. 20
0
 private void Blend(AtomAnimationClip clip, float weight, float duration)
 {
     if (!clip.playbackEnabled)
     {
         clip.playbackWeight = 0;
     }
     clip.playbackEnabled   = true;
     clip.playbackBlendRate = (weight - clip.playbackWeight) / duration;
 }
Esempio n. 21
0
        public void PlayClip(AtomAnimationClip clip, bool sequencing, bool allowPreserveLoops = true)
        {
            paused = false;
            if (clip.playbackEnabled && clip.playbackMainInLayer)
            {
                return;
            }
            if (!isPlaying)
            {
                isPlaying       = true;
                this.sequencing = this.sequencing || sequencing;
                #if (PLAYBACK_HEALTH_CHECK)
                PlaybackHealthCheck(clip);
                #endif
            }
            if (sequencing && !clip.playbackEnabled)
            {
                clip.clipTime = 0;
            }
            var previousMain = index.ByLayer(clip.animationLayer).FirstOrDefault(c => c.playbackMainInLayer);
            if (previousMain != null && previousMain != clip)
            {
                if (previousMain.uninterruptible)
                {
                    return;
                }

                if (clip.loop && clip.preserveLoops && previousMain.loop && allowPreserveLoops)
                {
                    previousMain.SetNext(clip.animationName, Mathf.Max(previousMain.animationLength - previousMain.clipTime, 0f));
                }
                else
                {
                    TransitionAnimation(previousMain, clip);
                }
            }
            else
            {
                if (clip.clipTime == clip.animationLength)
                {
                    clip.clipTime = 0f;
                }
                Blend(clip, 1f, clip.blendInDuration);
                clip.playbackMainInLayer = true;
            }
            if (clip.animationPattern)
            {
                clip.animationPattern.SetBoolParamValue("loopOnce", false);
                clip.animationPattern.ResetAndPlay();
            }
            if (sequencing && clip.nextAnimationName != null)
            {
                AssignNextAnimation(clip);
            }

            onIsPlayingChanged.Invoke(clip);
        }
Esempio n. 22
0
 public void AddClip(AtomAnimationClip clip)
 {
     clip.AnimationSettingsModified.AddListener(OnAnimationSettingsModified);
     clip.onAnimationKeyframesModified.AddListener(OnAnimationModified);
     clip.onTargetsListChanged.AddListener(OnAnimationModified);
     clip.onTargetsSelectionChanged.AddListener(OnTargetsSelectionChanged);
     Clips.Add(clip);
     ClipsListChanged.Invoke();
 }
Esempio n. 23
0
        public void ChangeAnimation(string animationName)
        {
            var clip = Clips.FirstOrDefault(c => c.AnimationName == animationName);

            if (clip == null)
            {
                throw new NullReferenceException($"Could not find animation '{animationName}'. Found animations: '{string.Join("', '", Clips.Select(c => c.AnimationName).ToArray())}'.");
            }
            var targetAnim = _unityAnimation[animationName];
            var time       = Time;

            if (_isPlaying)
            {
                if (HasAnimatableControllers())
                {
                    targetAnim.time    = 0f;
                    targetAnim.enabled = true;
                    targetAnim.weight  = 0f;
                    _unityAnimation.Blend(Current.AnimationName, 0f, Current.BlendDuration);
                    _unityAnimation.Blend(animationName, 1f, Current.BlendDuration);
                }
                if (Current.AnimationPattern != null)
                {
                    // Let the loop finish during the transition
                    Current.AnimationPattern.SetBoolParamValue("loopOnce", true);
                }
                _previousClip     = Current;
                _blendingTimeLeft = _blendingDuration = Current.BlendDuration;
            }

            var previous = Current;

            Current    = clip;
            _animState = targetAnim;

            if (_isPlaying)
            {
                DetermineNextAnimation(_playTime);

                if (Current.AnimationPattern != null)
                {
                    Current.AnimationPattern.SetBoolParamValue("loopOnce", false);
                    Current.AnimationPattern.ResetAndPlay();
                }
            }
            else
            {
                Time = 0f;
                Sample();
                CurrentAnimationChanged.Invoke(new CurrentAnimationChangedEventArgs
                {
                    Before = previous,
                    After  = Current
                });
            }
        }
Esempio n. 24
0
        private static FreeControllerAnimationTarget CopyTarget(AtomAnimationClip clip, FreeControllerAnimationTarget origTarget)
        {
            var newTarget = clip.Add(origTarget.controller);

            newTarget.SetParent(origTarget.parentAtomId, origTarget.parentRigidbodyId);
            newTarget.weight          = origTarget.weight;
            newTarget.controlPosition = origTarget.controlPosition;
            newTarget.controlRotation = origTarget.controlPosition;
            return(newTarget);
        }
Esempio n. 25
0
        private void RebuildClip(AtomAnimationClip clip)
        {
            foreach (var target in clip.targetControllers)
            {
                if (!target.dirty)
                {
                    continue;
                }

                if (clip.loop)
                {
                    target.SetCurveSnapshot(clip.animationLength, target.GetCurveSnapshot(0f), false);
                }

                target.ReapplyCurveTypes(clip.loop);

                if (clip.ensureQuaternionContinuity)
                {
                    UnitySpecific.EnsureQuaternionContinuityAndRecalculateSlope(
                        target.rotX,
                        target.rotY,
                        target.rotZ,
                        target.rotW);
                }

                RebuildClipLoop(clip, target);
            }

            foreach (var target in clip.targetFloatParams)
            {
                if (!target.dirty)
                {
                    continue;
                }

                if (clip.loop)
                {
                    target.value.SetKeyframe(clip.animationLength, target.value[0].value);
                }

                target.ReapplyCurveTypes(clip.loop);

                RebuildClipLoop(clip, target);
            }

            foreach (var target in clip.targetTriggers)
            {
                if (!target.dirty)
                {
                    continue;
                }

                target.RebuildKeyframes(clip.animationLength);
            }
        }
Esempio n. 26
0
        public AtomAnimationClip CreateClip(string animationLayer, string animationName)
        {
            if (clips.Any(c => c.animationName == animationName))
            {
                throw new InvalidOperationException($"Animation '{animationName}' already exists");
            }
            var clip = new AtomAnimationClip(animationName, animationLayer);

            AddClip(clip);
            return(clip);
        }
Esempio n. 27
0
 public void SendCurrentAnimation(AtomAnimationClip clip)
 {
     if (syncing)
     {
         return;
     }
     SendTimelineEvent(new object[] {
         nameof(SendCurrentAnimation),
         clip.animationName
     });
 }
Esempio n. 28
0
        public IEnumerable OverwriteEmptyClip(TestContext context)
        {
            var existing = context.animation.clips.Single();
            var clip     = new AtomAnimationClip(existing.animationName, "New Layer");

            new ImportOperations(context.animation, true).ImportClips(new[] { clip });

            context.Assert(context.animation.clips.Count, 1, "When the animation is empty, replace it");
            context.Assert(clip.animationLayer, "Main Layer", "The existing animation layer is used");
            yield break;
        }
        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();
        }
Esempio n. 30
0
 public void SendTime(AtomAnimationClip clip)
 {
     if (syncing)
     {
         return;
     }
     SendTimelineEvent(new object[] {
         nameof(SendTime),   // 0
         clip.animationName, // 1
         clip.clipTime       // 2
     });
 }