public void Prepare(bool resize) { if (SuperController.singleton.motionAnimationMaster == null || _containingAtom?.motionAnimationControls == null) { throw new Exception("Timeline: Missing motion animation controls"); } var length = _containingAtom.motionAnimationControls.Select(m => m?.clip?.clipLength ?? 0).Max().Snap(0.01f); if (length < 0.01f) { throw new Exception("Timeline: No motion animation to import."); } var requiresRebuild = false; if (clip.loop) { clip.loop = SuperController.singleton.motionAnimationMaster.loop; requiresRebuild = true; } if (resize && length != clip.animationLength) { new ResizeAnimationOperations(clip).CropOrExtendEnd(length); requiresRebuild = true; } if (requiresRebuild) { _animation.RebuildAnimationNow(); } }
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); 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 IEnumerator StartRecording(List <FreeControllerAnimationTarget> controllers, List <FloatParamAnimationTarget> floatParams) { // TODO: Handle stopping in the middle of it // TODO: Handle starting while it's already recording // TODO: Counter should use in-game rather than helptext _animation.StopAll(); _animation.ResetAll(); var keyframesOps = new KeyframesOperations(_clip); for (var i = 5; i > 0; i--) { SuperController.singleton.helpText = $"Start recording in {i}..."; var next = Time.realtimeSinceStartup + 1f; while (Time.realtimeSinceStartup < next) { yield return(0); if (Input.GetKeyDown(KeyCode.Escape)) { yield break; } } } SuperController.singleton.helpText = "Recording..."; foreach (var target in controllers) { keyframesOps.RemoveAll(target); } foreach (var target in floatParams) { keyframesOps.RemoveAll(target); } _clip.DirtyAll(); _animation.RebuildAnimationNow(); yield return(0); foreach (var target in controllers) { target.recording = true; target.StartBulkUpdates(); } foreach (var target in floatParams) { target.recording = true; target.StartBulkUpdates(); } _animation.PlayClip(_clip, false); while (_animation.playTime <= _clip.animationLength && _animation.isPlaying) { if (Input.GetKeyDown(KeyCode.Escape)) { break; } yield return(0); } _animation.StopAll(); _animation.ResetAll(); SuperController.singleton.helpText = ""; // TODO: This needs to be guaranteed. We could register the enumerator inside a disposable class, dispose being called in different cancel situations foreach (var target in controllers) { target.recording = false; target.EndBulkUpdates(); } foreach (var target in floatParams) { target.recording = false; target.EndBulkUpdates(); } _clip.DirtyAll(); }