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); }
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); }
private static TriggersAnimationTarget GivenThreeKeyframesTrigger(TestContext context, AtomAnimationClip clip) { var target = clip.Add(new TriggersAnimationTarget()); context.Assert(clip.animationLength, 2f, "Default animation length"); target.SetKeyframe(0f, new AtomAnimationTrigger()); target.SetKeyframe(1f, new AtomAnimationTrigger()); target.SetKeyframe(2f, new AtomAnimationTrigger()); context.animation.RebuildAnimationNow(); context.Assert(target.triggersMap.Select(k => k.Key).OrderBy(k => k), new[] { 0, 1000, 2000 }, "Map before resize"); return(target); }
private static FloatParamAnimationTarget GivenThreeKeyframesFloatParam(TestContext context, AtomAnimationClip clip) { var storable = context.gameObject.AddComponent <JSONStorable>(); var target = clip.Add(storable, new JSONStorableFloat("Test", 0, 0, 1)); context.Assert(clip.animationLength, 2f, "Default animation length"); target.SetKeyframe(0f, 0f); target.SetKeyframe(1f, 1f); target.SetKeyframe(2f, 0f); context.animation.RebuildAnimationNow(); context.Assert(target.value.keys.Select(k => k.time), new[] { 0f, 1f, 2f }, "Keyframes before resize"); return(target); }
private static FreeControllerAnimationTarget GivenThreeKeyframesFreeController(TestContext context, AtomAnimationClip clip) { var controller = new GameObject("Test Controller"); controller.SetActive(false); controller.transform.SetParent(context.gameObject.transform, false); var fc = controller.AddComponent <FreeControllerV3>(); fc.UITransforms = new Transform[0]; fc.UITransformsPlayMode = new Transform[0]; var target = clip.Add(fc); context.Assert(clip.animationLength, 2f, "Default animation length"); target.SetKeyframe(0f, Vector3.zero, Quaternion.identity); target.SetKeyframe(1f, Vector3.one, Quaternion.identity); target.SetKeyframe(2f, Vector3.zero, Quaternion.identity); context.animation.RebuildAnimationNow(); context.Assert(target.x.keys.Select(k => k.time), new[] { 0f, 1f, 2f }, "Keyframes before resize"); return(target); }
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); }
private void DeserializeClip(AtomAnimationClip clip, JSONClass clipJSON) { var animationPatternUID = clipJSON["AnimationPattern"]?.Value; if (!string.IsNullOrEmpty(animationPatternUID)) { var animationPattern = SuperController.singleton.GetAtomByUid(animationPatternUID)?.GetComponentInChildren <AnimationPattern>(); if (animationPattern == null) { SuperController.LogError($"Animation Pattern '{animationPatternUID}' linked to animation '{clip.animationName}' of atom '{_atom.uid}' was not found in scene"); } else { clip.animationPattern = animationPattern; } } JSONArray controllersJSON = clipJSON["Controllers"].AsArray; if (controllersJSON != null) { foreach (JSONClass controllerJSON in controllersJSON) { var controllerName = controllerJSON["Controller"].Value; var controller = _atom.freeControllers.Single(fc => fc.name == controllerName); if (controller == null) { SuperController.LogError($"VamTimeline: Atom '{_atom.uid}' does not have a controller '{controllerName}'"); continue; } var target = new FreeControllerAnimationTarget(controller); clip.Add(target); DeserializeCurve(target.x, controllerJSON["X"], clip.animationLength, target.settings); DeserializeCurve(target.y, controllerJSON["Y"], clip.animationLength); DeserializeCurve(target.z, controllerJSON["Z"], clip.animationLength); DeserializeCurve(target.rotX, controllerJSON["RotX"], clip.animationLength); DeserializeCurve(target.rotY, controllerJSON["RotY"], clip.animationLength); DeserializeCurve(target.rotZ, controllerJSON["RotZ"], clip.animationLength); DeserializeCurve(target.rotW, controllerJSON["RotW"], clip.animationLength); AddMissingKeyframeSettings(target); target.AddEdgeFramesIfMissing(clip.animationLength); } } JSONArray floatParamsJSON = clipJSON["FloatParams"].AsArray; if (floatParamsJSON != null) { foreach (JSONClass paramJSON in floatParamsJSON) { var storableId = paramJSON["Storable"].Value; var floatParamName = paramJSON["Name"].Value; var target = new FloatParamAnimationTarget(_atom, storableId, floatParamName); clip.Add(target); DeserializeCurve(target.value, paramJSON["Value"], clip.animationLength, target.settings); AddMissingKeyframeSettings(target); target.AddEdgeFramesIfMissing(clip.animationLength); } } JSONArray triggersJSON = clipJSON["Triggers"].AsArray; if (triggersJSON != null) { foreach (JSONClass triggerJSON in triggersJSON) { var target = new TriggersAnimationTarget { name = DeserializeString(triggerJSON["Name"], "Trigger") }; foreach (JSONClass entryJSON in triggerJSON["Triggers"].AsArray) { var trigger = new AtomAnimationTrigger(); trigger.RestoreFromJSON(entryJSON); target.SetKeyframe(trigger.startTime, trigger); } target.AddEdgeFramesIfMissing(clip.animationLength); clip.Add(target); } } }
private void DeserializeClip(AtomAnimationClip clip, JSONClass clipJSON) { var animationPatternUID = clipJSON["AnimationPattern"]?.Value; if (!string.IsNullOrEmpty(animationPatternUID)) { var animationPattern = SuperController.singleton.GetAtomByUid(animationPatternUID)?.GetComponentInChildren <AnimationPattern>(); if (animationPattern == null) { SuperController.LogError($"Animation Pattern '{animationPatternUID}' linked to animation '{clip.AnimationName}' of atom '{_atom.uid}' was not found in scene"); } else { clip.AnimationPattern = animationPattern; } } JSONArray controllersJSON = clipJSON["Controllers"].AsArray; if (controllersJSON != null) { foreach (JSONClass controllerJSON in controllersJSON) { var controllerName = controllerJSON["Controller"].Value; var controller = _atom.freeControllers.Single(fc => fc.name == controllerName); if (controller == null) { SuperController.LogError($"VamTimeline: Atom '{_atom.uid}' does not have a controller '{controllerName}'"); continue; } var target = new FreeControllerAnimationTarget(controller); clip.Add(target); DeserializeCurve(target.x, controllerJSON["X"], clip.animationLength, target.settings); DeserializeCurve(target.y, controllerJSON["Y"], clip.animationLength); DeserializeCurve(target.z, controllerJSON["Z"], clip.animationLength); DeserializeCurve(target.rotX, controllerJSON["RotX"], clip.animationLength); DeserializeCurve(target.rotY, controllerJSON["RotY"], clip.animationLength); DeserializeCurve(target.rotZ, controllerJSON["RotZ"], clip.animationLength); DeserializeCurve(target.rotW, controllerJSON["RotW"], clip.animationLength); AnimationCurve leadCurve = target.GetLeadCurve(); for (var key = 0; key < leadCurve.length; key++) { var time = leadCurve[key].time; var ms = time.ToMilliseconds(); if (!target.settings.ContainsKey(ms)) { target.settings.Add(ms, new KeyframeSettings { curveType = CurveTypeValues.LeaveAsIs }); } } } } JSONArray paramsJSON = clipJSON["FloatParams"].AsArray; var morphs = GetMorphs(); if (paramsJSON != null) { foreach (JSONClass paramJSON in paramsJSON) { var storableId = paramJSON["Storable"].Value; var floatParamName = paramJSON["Name"].Value; if (storableId == "geometry") { // This allows loading an animation even though the animatable option was checked off (e.g. loading a pose) var morph = morphs.FirstOrDefault(m => m.jsonFloat.name == floatParamName); if (morph == null) { SuperController.LogError($"VamTimeline: Atom '{_atom.uid}' does not have a morph (geometry) '{floatParamName}'"); continue; } if (!morph.animatable) { morph.animatable = true; } } var storable = _atom.GetStorableByID(storableId); if (storable == null) { SuperController.LogError($"VamTimeline: Atom '{_atom.uid}' does not have a storable '{storableId}'"); continue; } var jsf = storable.GetFloatJSONParam(floatParamName); if (jsf == null) { SuperController.LogError($"VamTimeline: Atom '{_atom.uid}' does not have a param '{storableId}/{floatParamName}'"); continue; } var target = new FloatParamAnimationTarget(storable, jsf); clip.Add(target); DeserializeCurve(target.value, paramJSON["Value"], clip.animationLength); } } }