Last active
June 6, 2018 17:37
-
-
Save pharan/c9793f0bb35345f537e515cc0d653f58 to your computer and use it in GitHub Desktop.
Preview of the spine-unity AnimationTools static class module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
* Spine Runtimes Software License v2.5 | |
* | |
* Copyright (c) 2013-2018, Esoteric Software | |
* All rights reserved. | |
* | |
* You are granted a perpetual, non-exclusive, non-sublicensable, and | |
* non-transferable license to use, install, execute, and perform the Spine | |
* Runtimes software and derivative works solely for personal or internal | |
* use. Without the written permission of Esoteric Software (see Section 2 of | |
* the Spine Software License Agreement), you may not (a) modify, translate, | |
* adapt, or develop new applications using the Spine Runtimes or otherwise | |
* create derivative works or improvements of the Spine Runtimes or (b) remove, | |
* delete, alter, or obscure any trademarks or any copyright, trademark, patent, | |
* or other intellectual property or proprietary rights notices on or in the | |
* Software, including any copy thereof. Redistributions in binary or source | |
* form must include this license and terms. | |
* | |
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF | |
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
*****************************************************************************/ | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace Spine.Unity.Modules.AnimationTools { | |
public static class AnimationTools { | |
#region Filler Timelines | |
/// <summary> | |
/// Matches the animation timelines across the given set of animations. | |
/// This allows unkeyed properties to assume setup pose when animations are naively mixed using Animation.Apply. | |
/// </summary> | |
/// <param name="animations">An enumerable collection animations whose timelines will be matched.</param> | |
/// <param name="skeletonData">The SkeletonData where the animations belong.</param> | |
public static void MatchAnimationTimelines (IEnumerable<Spine.Animation> animations, SkeletonData skeletonData) { | |
if (animations == null) return; | |
if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "Timelines can't be matched without a SkeletonData source."); | |
// Build a reference collection of timelines to match | |
// and a collection of dummy timelines that can be used to fill-in missing items. | |
var timelineDictionary = new Dictionary<int, Spine.Timeline>(); | |
foreach (var animation in animations) { | |
foreach (var timeline in animation.timelines) { | |
if (timeline is EventTimeline) continue; | |
int propertyID = timeline.PropertyId; | |
if (!timelineDictionary.ContainsKey(propertyID)) { | |
timelineDictionary.Add(propertyID, GetFillerTimeline(timeline, skeletonData)); | |
} | |
} | |
} | |
var idsToMatch = new List<int>(timelineDictionary.Keys); | |
// For each animation in the list, check for and add missing timelines. | |
var currentAnimationIDs = new HashSet<int>(); | |
foreach (var animation in animations) { | |
currentAnimationIDs.Clear(); | |
foreach (var timeline in animation.timelines) { | |
if (timeline is EventTimeline) continue; | |
currentAnimationIDs.Add(timeline.PropertyId); | |
} | |
var animationTimelines = animation.timelines; | |
foreach (int propertyID in idsToMatch) { | |
if (!currentAnimationIDs.Contains(propertyID)) | |
animationTimelines.Add(timelineDictionary[propertyID]); | |
} | |
} | |
// These are locals, but sometimes Unity's GC does weird stuff. So let's clean up. | |
timelineDictionary.Clear(); | |
timelineDictionary = null; | |
idsToMatch.Clear(); | |
idsToMatch = null; | |
currentAnimationIDs.Clear(); | |
currentAnimationIDs = null; | |
} | |
static Timeline GetFillerTimeline (Timeline timeline, SkeletonData skeletonData) { | |
int propertyID = timeline.PropertyId; | |
int tt = propertyID >> 24; | |
var timelineType = (TimelineType)tt; | |
switch (timelineType) { | |
// Bone | |
case TimelineType.Rotate: | |
return GetFillerTimeline((RotateTimeline)timeline, skeletonData); | |
case TimelineType.Translate: | |
return GetFillerTimeline((TranslateTimeline)timeline, skeletonData); | |
case TimelineType.Scale: | |
return GetFillerTimeline((ScaleTimeline)timeline, skeletonData); | |
case TimelineType.Shear: | |
return GetFillerTimeline((ShearTimeline)timeline, skeletonData); | |
// Slot | |
case TimelineType.Attachment: | |
return GetFillerTimeline((AttachmentTimeline)timeline, skeletonData); | |
case TimelineType.Color: | |
return GetFillerTimeline((ColorTimeline)timeline, skeletonData); | |
case TimelineType.TwoColor: | |
return GetFillerTimeline((TwoColorTimeline)timeline, skeletonData); | |
case TimelineType.Deform: | |
return GetFillerTimeline((DeformTimeline)timeline, skeletonData); | |
// Skeleton | |
case TimelineType.DrawOrder: | |
return GetFillerTimeline((DrawOrderTimeline)timeline, skeletonData); | |
// IK Constraint | |
case TimelineType.IkConstraint: | |
return GetFillerTimeline((IkConstraintTimeline)timeline, skeletonData); | |
// TransformConstraint | |
case TimelineType.TransformConstraint: | |
return GetFillerTimeline((TransformConstraintTimeline)timeline, skeletonData); | |
// Path Constraint | |
case TimelineType.PathConstraintPosition: | |
return GetFillerTimeline((PathConstraintPositionTimeline)timeline, skeletonData); | |
case TimelineType.PathConstraintSpacing: | |
return GetFillerTimeline((PathConstraintSpacingTimeline)timeline, skeletonData); | |
case TimelineType.PathConstraintMix: | |
return GetFillerTimeline((PathConstraintMixTimeline)timeline, skeletonData); | |
} | |
return null; | |
} | |
static RotateTimeline GetFillerTimeline (RotateTimeline timeline, SkeletonData skeletonData) { | |
var t = new RotateTimeline(1); | |
t.boneIndex = timeline.boneIndex; | |
t.SetFrame(0, 0, 0); | |
return t; | |
} | |
static TranslateTimeline GetFillerTimeline (TranslateTimeline timeline, SkeletonData skeletonData) { | |
var t = new TranslateTimeline(1); | |
t.boneIndex = timeline.boneIndex; | |
t.SetFrame(0, 0, 0, 0); | |
return t; | |
} | |
static ScaleTimeline GetFillerTimeline (ScaleTimeline timeline, SkeletonData skeletonData) { | |
var t = new ScaleTimeline(1); | |
t.boneIndex = timeline.boneIndex; | |
t.SetFrame(0, 0, 0, 0); | |
return t; | |
} | |
static ShearTimeline GetFillerTimeline (ShearTimeline timeline, SkeletonData skeletonData) { | |
var t = new ShearTimeline(1); | |
t.boneIndex = timeline.boneIndex; | |
t.SetFrame(0, 0, 0, 0); | |
return t; | |
} | |
static AttachmentTimeline GetFillerTimeline (AttachmentTimeline timeline, SkeletonData skeletonData) { | |
var t = new AttachmentTimeline(1); | |
t.slotIndex = timeline.slotIndex; | |
var slotData = skeletonData.slots.Items[t.slotIndex]; | |
t.SetFrame(0, 0, slotData.attachmentName); | |
return t; | |
} | |
static ColorTimeline GetFillerTimeline (ColorTimeline timeline, SkeletonData skeletonData) { | |
var t = new ColorTimeline(1); | |
t.slotIndex = timeline.slotIndex; | |
var slotData = skeletonData.slots.Items[t.slotIndex]; | |
t.SetFrame(0, 0, slotData.r, slotData.g, slotData.b, slotData.a); | |
return t; | |
} | |
static TwoColorTimeline GetFillerTimeline (TwoColorTimeline timeline, SkeletonData skeletonData) { | |
var t = new TwoColorTimeline(1); | |
t.slotIndex = timeline.slotIndex; | |
var slotData = skeletonData.slots.Items[t.slotIndex]; | |
t.SetFrame(0, 0, slotData.r, slotData.g, slotData.b, slotData.a, slotData.r2, slotData.g2, slotData.b2); | |
return t; | |
} | |
static DeformTimeline GetFillerTimeline (DeformTimeline timeline, SkeletonData skeletonData) { | |
var t = new DeformTimeline(1); | |
t.slotIndex = timeline.slotIndex; | |
t.attachment = timeline.attachment; | |
var slotData = skeletonData.slots.Items[t.slotIndex]; | |
if (t.attachment.IsWeighted()) { | |
t.SetFrame(0, 0, new float[t.attachment.vertices.Length]); | |
} else { | |
t.SetFrame(0, 0, t.attachment.vertices.Clone() as float[]); | |
} | |
return t; | |
} | |
static DrawOrderTimeline GetFillerTimeline (DrawOrderTimeline timeline, SkeletonData skeletonData) { | |
var t = new DrawOrderTimeline(1); | |
t.SetFrame(0, 0, null); // null means use setup pose in DrawOrderTimeline.Apply. | |
return t; | |
} | |
static IkConstraintTimeline GetFillerTimeline (IkConstraintTimeline timeline, SkeletonData skeletonData) { | |
var t = new IkConstraintTimeline(1); | |
var ikConstraintData = skeletonData.ikConstraints.Items[timeline.ikConstraintIndex]; | |
t.SetFrame(0, 0, ikConstraintData.mix, ikConstraintData.bendDirection); | |
return t; | |
} | |
static TransformConstraintTimeline GetFillerTimeline (TransformConstraintTimeline timeline, SkeletonData skeletonData) { | |
var t = new TransformConstraintTimeline(1); | |
var data = skeletonData.transformConstraints.Items[timeline.transformConstraintIndex]; | |
t.SetFrame(0, 0, data.rotateMix, data.translateMix, data.scaleMix, data.shearMix); | |
return t; | |
} | |
static PathConstraintPositionTimeline GetFillerTimeline (PathConstraintPositionTimeline timeline, SkeletonData skeletonData) { | |
var t = new PathConstraintPositionTimeline(1); | |
var data = skeletonData.pathConstraints.Items[timeline.pathConstraintIndex]; | |
t.SetFrame(0, 0, data.position); | |
return t; | |
} | |
static PathConstraintSpacingTimeline GetFillerTimeline (PathConstraintSpacingTimeline timeline, SkeletonData skeletonData) { | |
var t = new PathConstraintSpacingTimeline(1); | |
var data = skeletonData.pathConstraints.Items[timeline.pathConstraintIndex]; | |
t.SetFrame(0, 0, data.spacing); | |
return t; | |
} | |
static PathConstraintMixTimeline GetFillerTimeline (PathConstraintMixTimeline timeline, SkeletonData skeletonData) { | |
var t = new PathConstraintMixTimeline(1); | |
var data = skeletonData.pathConstraints.Items[timeline.pathConstraintIndex]; | |
t.SetFrame(0, 0, data.rotateMix, data.translateMix); | |
return t; | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment