mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Merge remote-tracking branch 'origin/3.6-beta' into 3.6-beta
This commit is contained in:
commit
277f96d50f
Binary file not shown.
@ -36,6 +36,9 @@ package spine.animation {
|
|||||||
import flash.utils.Dictionary;
|
import flash.utils.Dictionary;
|
||||||
|
|
||||||
public class AnimationState {
|
public class AnimationState {
|
||||||
|
public static var SUBSEQUENT : int = 0;
|
||||||
|
public static var FIRST : int = 1;
|
||||||
|
public static var DIP : int = 2;
|
||||||
internal static var emptyAnimation : Animation = new Animation("<empty>", new Vector.<Timeline>(), 0);
|
internal static var emptyAnimation : Animation = new Animation("<empty>", new Vector.<Timeline>(), 0);
|
||||||
public var data : AnimationStateData;
|
public var data : AnimationStateData;
|
||||||
public var tracks : Vector.<TrackEntry> = new Vector.<TrackEntry>();
|
public var tracks : Vector.<TrackEntry> = new Vector.<TrackEntry>();
|
||||||
@ -48,8 +51,8 @@ package spine.animation {
|
|||||||
public var onEvent : Listeners = new Listeners();
|
public var onEvent : Listeners = new Listeners();
|
||||||
internal var queue : EventQueue;
|
internal var queue : EventQueue;
|
||||||
internal var propertyIDs : Dictionary = new Dictionary();
|
internal var propertyIDs : Dictionary = new Dictionary();
|
||||||
|
internal var mixingTo : Vector.<TrackEntry> = new Vector.<TrackEntry>();
|
||||||
internal var animationsChanged : Boolean;
|
internal var animationsChanged : Boolean;
|
||||||
public var multipleMixing : Boolean = false;
|
|
||||||
public var timeScale : Number = 1;
|
public var timeScale : Number = 1;
|
||||||
internal var trackEntryPool : Pool;
|
internal var trackEntryPool : Pool;
|
||||||
|
|
||||||
@ -104,7 +107,15 @@ package spine.animation {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateMixingFrom(current, delta);
|
if (current.mixingFrom != null && updateMixingFrom(current, delta, 2)) {
|
||||||
|
// End mixing from entries once all have completed.
|
||||||
|
var from : TrackEntry = current.mixingFrom;
|
||||||
|
current.mixingFrom = null;
|
||||||
|
while (from != null) {
|
||||||
|
queue.end(from);
|
||||||
|
from = from.mixingFrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
current.trackTime += currentDelta;
|
current.trackTime += currentDelta;
|
||||||
}
|
}
|
||||||
@ -112,22 +123,26 @@ package spine.animation {
|
|||||||
queue.drain();
|
queue.drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updateMixingFrom(entry : TrackEntry, delta : Number) : void {
|
private function updateMixingFrom(entry : TrackEntry, delta : Number, animationCount : int) : Boolean {
|
||||||
var from : TrackEntry = entry.mixingFrom;
|
var from : TrackEntry = entry.mixingFrom;
|
||||||
if (from == null) return;
|
if (from == null) return true;
|
||||||
|
|
||||||
updateMixingFrom(from, delta);
|
var finished : Boolean = updateMixingFrom(from, delta, animationCount + 1);
|
||||||
|
|
||||||
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) {
|
// Require mixTime > 0 to ensure the mixing from entry was applied at least once.
|
||||||
entry.mixingFrom = null;
|
if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
|
||||||
queue.end(from);
|
if (animationCount > 6 && from.mixingFrom == null) { // Limit the mixing from linked list.
|
||||||
return;
|
entry.mixingFrom = null;
|
||||||
|
queue.end(from);
|
||||||
|
}
|
||||||
|
return finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
from.animationLast = from.nextAnimationLast;
|
from.animationLast = from.nextAnimationLast;
|
||||||
from.trackLast = from.nextTrackLast;
|
from.trackLast = from.nextTrackLast;
|
||||||
from.trackTime += delta * from.timeScale;
|
from.trackTime += delta * from.timeScale;
|
||||||
entry.mixTime += delta * entry.timeScale;
|
entry.mixTime += delta * entry.timeScale;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apply(skeleton : Skeleton) : void {
|
public function apply(skeleton : Skeleton) : void {
|
||||||
@ -156,17 +171,18 @@ package spine.animation {
|
|||||||
for (ii = 0; ii < timelineCount; ii++)
|
for (ii = 0; ii < timelineCount; ii++)
|
||||||
Timeline(timelines[ii]).apply(skeleton, animationLast, animationTime, events, 1, true, false);
|
Timeline(timelines[ii]).apply(skeleton, animationLast, animationTime, events, 1, true, false);
|
||||||
} else {
|
} else {
|
||||||
|
var timelineData : Vector.<int> = current.timelineData;
|
||||||
|
|
||||||
var firstFrame : Boolean = current.timelinesRotation.length == 0;
|
var firstFrame : Boolean = current.timelinesRotation.length == 0;
|
||||||
if (firstFrame) current.timelinesRotation.length = timelineCount << 1;
|
if (firstFrame) current.timelinesRotation.length = timelineCount << 1;
|
||||||
var timelinesRotation : Vector.<Number> = current.timelinesRotation;
|
var timelinesRotation : Vector.<Number> = current.timelinesRotation;
|
||||||
|
|
||||||
var timelinesFirst : Vector.<Boolean> = current.timelinesFirst;
|
|
||||||
for (ii = 0; ii < timelineCount; ii++) {
|
for (ii = 0; ii < timelineCount; ii++) {
|
||||||
var timeline : Timeline = timelines[ii];
|
var timeline : Timeline = timelines[ii];
|
||||||
if (timeline is RotateTimeline) {
|
if (timeline is RotateTimeline) {
|
||||||
applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame);
|
applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
|
||||||
} else
|
} else
|
||||||
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false);
|
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queueEvents(current, animationTime);
|
queueEvents(current, animationTime);
|
||||||
@ -178,15 +194,15 @@ package spine.animation {
|
|||||||
queue.drain();
|
queue.drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function applyMixingFrom(entry : TrackEntry, skeleton : Skeleton) : Number {
|
private function applyMixingFrom(to : TrackEntry, skeleton : Skeleton) : Number {
|
||||||
var from : TrackEntry = entry.mixingFrom;
|
var from : TrackEntry = to.mixingFrom;
|
||||||
if (from.mixingFrom != null) applyMixingFrom(from, skeleton);
|
if (from.mixingFrom != null) applyMixingFrom(from, skeleton);
|
||||||
|
|
||||||
var mix : Number = 0;
|
var mix : Number = 0;
|
||||||
if (entry.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
||||||
mix = 1;
|
mix = 1;
|
||||||
else {
|
else {
|
||||||
mix = entry.mixTime / entry.mixDuration;
|
mix = to.mixTime / to.mixDuration;
|
||||||
if (mix > 1) mix = 1;
|
if (mix > 1) mix = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,31 +211,47 @@ package spine.animation {
|
|||||||
var animationLast : Number = from.animationLast, animationTime : Number = from.getAnimationTime();
|
var animationLast : Number = from.animationLast, animationTime : Number = from.getAnimationTime();
|
||||||
var timelineCount : int = from.animation.timelines.length;
|
var timelineCount : int = from.animation.timelines.length;
|
||||||
var timelines : Vector.<Timeline> = from.animation.timelines;
|
var timelines : Vector.<Timeline> = from.animation.timelines;
|
||||||
var timelinesFirst : Vector.<Boolean> = from.timelinesFirst;
|
var timelineData : Vector.<int> = from.timelineData;
|
||||||
var timelinesLast : Vector.<Boolean> = multipleMixing ? null : from.timelinesLast;
|
var timelineDipMix : Vector.<TrackEntry> = from.timelineDipMix;
|
||||||
var alphaBase : Number = from.alpha * entry.mixAlpha;
|
|
||||||
var alphaMix : Number = alphaBase * (1 - mix);
|
|
||||||
|
|
||||||
var firstFrame : Boolean = from.timelinesRotation.length == 0;
|
var firstFrame : Boolean = from.timelinesRotation.length == 0;
|
||||||
if (firstFrame) from.timelinesRotation.length = timelineCount << 1;
|
if (firstFrame) from.timelinesRotation.length = timelineCount << 1;
|
||||||
var timelinesRotation : Vector.<Number> = from.timelinesRotation;
|
var timelinesRotation : Vector.<Number> = from.timelinesRotation;
|
||||||
|
|
||||||
|
var first : Boolean = false;
|
||||||
|
var alphaDip : Number = from.alpha * to.interruptAlpha;
|
||||||
|
var alphaMix : Number = alphaDip * (1 - mix);
|
||||||
|
var alpha : Number = 0;
|
||||||
for (var i : int = 0; i < timelineCount; i++) {
|
for (var i : int = 0; i < timelineCount; i++) {
|
||||||
var timeline : Timeline = timelines[i];
|
var timeline : Timeline = timelines[i];
|
||||||
var setupPose : Boolean = timelinesFirst[i];
|
switch (timelineData[i]) {
|
||||||
var alpha : Number = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix;
|
case SUBSEQUENT:
|
||||||
|
first = false;
|
||||||
|
alpha = alphaMix;
|
||||||
|
break;
|
||||||
|
case FIRST:
|
||||||
|
first = true;
|
||||||
|
alpha = alphaMix;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
first = true;
|
||||||
|
alpha = alphaDip;
|
||||||
|
var dipMix : TrackEntry = timelineDipMix[i];
|
||||||
|
if (dipMix != null) alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (timeline is RotateTimeline)
|
if (timeline is RotateTimeline)
|
||||||
applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame);
|
applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
|
||||||
else {
|
else {
|
||||||
if (!setupPose) {
|
if (!first) {
|
||||||
if (!attachments && timeline is AttachmentTimeline) continue;
|
if (!attachments && timeline is AttachmentTimeline) continue;
|
||||||
if (!drawOrder && timeline is DrawOrderTimeline) continue;
|
if (!drawOrder && timeline is DrawOrderTimeline) continue;
|
||||||
}
|
}
|
||||||
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
|
timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.mixDuration > 0) queueEvents(from, animationTime);
|
if (to.mixDuration > 0) queueEvents(from, animationTime);
|
||||||
this.events.length = 0;
|
this.events.length = 0;
|
||||||
from.nextAnimationLast = animationTime;
|
from.nextAnimationLast = animationTime;
|
||||||
from.nextTrackLast = from.trackTime;
|
from.nextTrackLast = from.trackTime;
|
||||||
@ -361,28 +393,11 @@ package spine.animation {
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
|
|
||||||
var mixingFrom : TrackEntry = from.mixingFrom;
|
// Store the interrupted mix percentage.
|
||||||
if (mixingFrom != null && from.mixDuration > 0) {
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
if (multipleMixing) {
|
current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
|
||||||
} else {
|
|
||||||
// A mix was interrupted, mix from the closest animation.
|
|
||||||
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
|
|
||||||
current.mixingFrom = mixingFrom;
|
|
||||||
mixingFrom.mixingFrom = from;
|
|
||||||
mixingFrom.mixTime = from.mixDuration - from.mixTime;
|
|
||||||
mixingFrom.mixDuration = from.mixDuration;
|
|
||||||
from.mixingFrom = null;
|
|
||||||
from = mixingFrom;
|
|
||||||
}
|
|
||||||
|
|
||||||
from.mixAlpha = 0;
|
from.timelinesRotation.length = 0; // Reset rotation for mixing out, in case entry was mixed in.
|
||||||
from.mixTime = 0;
|
|
||||||
from.mixDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
from.timelinesRotation.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.start(current);
|
queue.start(current);
|
||||||
@ -506,7 +521,7 @@ package spine.animation {
|
|||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
|
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.interruptAlpha = 1;
|
||||||
entry.mixTime = 0;
|
entry.mixTime = 0;
|
||||||
entry.mixDuration = last == null ? 0 : data.getMix(last.animation, animation);
|
entry.mixDuration = last == null ? 0 : data.getMix(last.animation, animation);
|
||||||
return entry;
|
return entry;
|
||||||
@ -525,88 +540,17 @@ package spine.animation {
|
|||||||
animationsChanged = false;
|
animationsChanged = false;
|
||||||
|
|
||||||
var propertyIDs : Dictionary = this.propertyIDs = new Dictionary();
|
var propertyIDs : Dictionary = this.propertyIDs = new Dictionary();
|
||||||
|
var mixingTo : Vector.<TrackEntry> = this.mixingTo;
|
||||||
// Compute timelinesFirst from lowest to highest track entries.
|
var lastEntry : TrackEntry = null;
|
||||||
var i : int = 0, n : int = tracks.length;
|
for (var i : int = 0, n : int = tracks.length; i < n; i++) {
|
||||||
for (var key : String in propertyIDs) {
|
var entry : TrackEntry = tracks[i];
|
||||||
delete propertyIDs[key];
|
if (entry != null) {
|
||||||
}
|
entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
|
||||||
var entry : TrackEntry;
|
lastEntry = entry;
|
||||||
for (; i < n; i++) { // Find first non-null entry.
|
|
||||||
entry = tracks[i];
|
|
||||||
if (entry == null) continue;
|
|
||||||
setTimelinesFirst(entry);
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (; i < n; i++) { // Rest of entries.
|
|
||||||
entry = tracks[i];
|
|
||||||
if (entry != null) checkTimelinesFirst(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multipleMixing) return;
|
|
||||||
|
|
||||||
// Set timelinesLast for mixingFrom entries, from highest track to lowest that has mixingFrom.
|
|
||||||
propertyIDs = this.propertyIDs = new Dictionary();
|
|
||||||
var lowestMixingFrom : int = n;
|
|
||||||
for (i = 0; i < n; i++) { // Find lowest track with a mixingFrom entry.
|
|
||||||
entry = tracks[i];
|
|
||||||
if (entry == null || entry.mixingFrom == null) continue;
|
|
||||||
lowestMixingFrom = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (i = n - 1; i >= lowestMixingFrom; i--) { // Find first non-null entry.
|
|
||||||
entry = tracks[i];
|
|
||||||
if (entry == null) continue;
|
|
||||||
|
|
||||||
// Store properties for non-mixingFrom entry but don't set timelinesLast, which is only used for mixingFrom entries.
|
|
||||||
var timelines : Vector.<Timeline> = entry.animation.timelines;
|
|
||||||
for (var ii : int = 0, nn : int = entry.animation.timelines.length; ii < nn; ii++)
|
|
||||||
propertyIDs[timelines[ii].getPropertyId().toString()] = true;
|
|
||||||
|
|
||||||
entry = entry.mixingFrom;
|
|
||||||
while (entry != null) {
|
|
||||||
checkTimelinesUsage(entry, entry.timelinesLast);
|
|
||||||
entry = entry.mixingFrom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setTimelinesFirst(entry : TrackEntry) : void {
|
|
||||||
if (entry.mixingFrom != null) {
|
|
||||||
setTimelinesFirst(entry.mixingFrom);
|
|
||||||
checkTimelinesUsage(entry, entry.timelinesFirst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var propertyIDs : Dictionary = this.propertyIDs;
|
|
||||||
var timelines : Vector.<Timeline> = entry.animation.timelines;
|
|
||||||
var n : int = timelines.length;
|
|
||||||
var usage : Vector.<Boolean> = entry.timelinesFirst;
|
|
||||||
usage.length = n;
|
|
||||||
for (var i : int = 0; i < n; i++) {
|
|
||||||
propertyIDs[timelines[i].getPropertyId().toString()] = true;
|
|
||||||
usage[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkTimelinesFirst(entry : TrackEntry) : void {
|
|
||||||
if (entry.mixingFrom != null) checkTimelinesFirst(entry.mixingFrom);
|
|
||||||
checkTimelinesUsage(entry, entry.timelinesFirst);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkTimelinesUsage(entry : TrackEntry, usageArray : Vector.<Boolean>) : void {
|
|
||||||
var propertyIDs : Dictionary = this.propertyIDs;
|
|
||||||
var timelines : Vector.<Timeline> = entry.animation.timelines;
|
|
||||||
var n : int = timelines.length;
|
|
||||||
var usage : Vector.<Boolean> = usageArray;
|
|
||||||
usageArray.length = n;
|
|
||||||
for (var i : int = 0; i < n; i++) {
|
|
||||||
var id : String = timelines[i].getPropertyId().toString();
|
|
||||||
usage[i] = !propertyIDs.hasOwnProperty(id);
|
|
||||||
propertyIDs[id] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCurrent(trackIndex : int) : TrackEntry {
|
public function getCurrent(trackIndex : int) : TrackEntry {
|
||||||
if (trackIndex >= tracks.length) return null;
|
if (trackIndex >= tracks.length) return null;
|
||||||
return tracks[trackIndex];
|
return tracks[trackIndex];
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
package spine.animation {
|
package spine.animation {
|
||||||
|
import flash.utils.Dictionary;
|
||||||
import spine.Poolable;
|
import spine.Poolable;
|
||||||
|
|
||||||
public class TrackEntry implements Poolable {
|
public class TrackEntry implements Poolable {
|
||||||
@ -45,9 +46,9 @@ package spine.animation {
|
|||||||
public var eventThreshold : Number, attachmentThreshold : Number, drawOrderThreshold : Number;
|
public var eventThreshold : Number, attachmentThreshold : Number, drawOrderThreshold : Number;
|
||||||
public var animationStart : Number, animationEnd : Number, animationLast : Number, nextAnimationLast : Number;
|
public var animationStart : Number, animationEnd : Number, animationLast : Number, nextAnimationLast : Number;
|
||||||
public var delay : Number, trackTime : Number, trackLast : Number, nextTrackLast : Number, trackEnd : Number, timeScale : Number;
|
public var delay : Number, trackTime : Number, trackLast : Number, nextTrackLast : Number, trackEnd : Number, timeScale : Number;
|
||||||
public var alpha : Number, mixTime : Number, mixDuration : Number, mixAlpha : Number;
|
public var alpha : Number, mixTime : Number, mixDuration : Number, interruptAlpha : Number;
|
||||||
public var timelinesFirst : Vector.<Boolean> = new Vector.<Boolean>();
|
public var timelineData : Vector.<int> = new Vector.<int>();
|
||||||
public var timelinesLast : Vector.<Boolean> = new Vector.<Boolean>();
|
public var timelineDipMix : Vector.<TrackEntry> = new Vector.<TrackEntry>();
|
||||||
public var timelinesRotation : Vector.<Number> = new Vector.<Number>();
|
public var timelinesRotation : Vector.<Number> = new Vector.<Number>();
|
||||||
|
|
||||||
public function TrackEntry() {
|
public function TrackEntry() {
|
||||||
@ -72,11 +73,56 @@ package spine.animation {
|
|||||||
onDispose.listeners.length = 0;
|
onDispose.listeners.length = 0;
|
||||||
onComplete.listeners.length = 0;
|
onComplete.listeners.length = 0;
|
||||||
onEvent.listeners.length = 0;
|
onEvent.listeners.length = 0;
|
||||||
timelinesFirst.length = 0;
|
timelineData.length = 0;
|
||||||
timelinesLast.length = 0;
|
timelineDipMix.length = 0;
|
||||||
timelinesRotation.length = 0;
|
timelinesRotation.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setTimelineData (to: TrackEntry, mixingToArray : Vector.<TrackEntry>, propertyIDs : Dictionary) : TrackEntry {
|
||||||
|
if (to != null) mixingToArray.push(to);
|
||||||
|
var lastEntry : TrackEntry = mixingFrom != null ? mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
|
||||||
|
if (to != null) mixingToArray.pop();
|
||||||
|
|
||||||
|
var mixingTo : Vector.<TrackEntry> = mixingToArray;
|
||||||
|
var mixingToLast : int = mixingToArray.length - 1;
|
||||||
|
var timelines : Vector.<Timeline> = animation.timelines;
|
||||||
|
var timelinesCount : int = animation.timelines.length;
|
||||||
|
var timelineData : Vector.<int> = this.timelineData;
|
||||||
|
timelineData.length = timelinesCount;
|
||||||
|
var timelineDipMix : Vector.<TrackEntry> = this.timelineDipMix;
|
||||||
|
timelineDipMix.length = timelinesCount;
|
||||||
|
|
||||||
|
outer:
|
||||||
|
for (var i : int = 0; i < timelinesCount; i++) {
|
||||||
|
var intId : int = timelines[i].getPropertyId();
|
||||||
|
var id : String = intId.toString();
|
||||||
|
if (!(propertyIDs[id] == false)) {
|
||||||
|
propertyIDs[id] = true;
|
||||||
|
timelineData[i] = AnimationState.SUBSEQUENT;
|
||||||
|
} else if (to == null || !to.hasTimeline(intId))
|
||||||
|
timelineData[i] = AnimationState.FIRST;
|
||||||
|
else {
|
||||||
|
timelineData[i] = AnimationState.DIP;
|
||||||
|
for (var ii : int = mixingToLast; ii >= 0; ii--) {
|
||||||
|
var entry : TrackEntry = mixingTo[ii];
|
||||||
|
if (!entry.hasTimeline(intId)) {
|
||||||
|
if (entry.mixDuration > 0) timelineDipMix[i] = entry;
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timelineDipMix[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasTimeline (id : int) : Boolean {
|
||||||
|
var timelines : Vector.<Timeline> = animation.timelines;
|
||||||
|
for (var i : int = 0, n : int = animation.timelines.length; i < n; i++)
|
||||||
|
if (timelines[i].getPropertyId() == id) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function resetRotationDirection() : void {
|
public function resetRotationDirection() : void {
|
||||||
timelinesRotation.length = 0;
|
timelinesRotation.length = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,11 +37,11 @@ namespace Spine {
|
|||||||
internal float duration;
|
internal float duration;
|
||||||
internal String name;
|
internal String name;
|
||||||
|
|
||||||
public String Name { get { return name; } }
|
public string Name { get { return name; } }
|
||||||
public ExposedList<Timeline> Timelines { get { return timelines; } set { timelines = value; } }
|
public ExposedList<Timeline> Timelines { get { return timelines; } set { timelines = value; } }
|
||||||
public float Duration { get { return duration; } set { duration = value; } }
|
public float Duration { get { return duration; } set { duration = value; } }
|
||||||
|
|
||||||
public Animation (String name, ExposedList<Timeline> timelines, float duration) {
|
public Animation (string name, ExposedList<Timeline> timelines, float duration) {
|
||||||
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
|
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
|
||||||
if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null.");
|
if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null.");
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|||||||
@ -34,6 +34,7 @@ using System.Collections.Generic;
|
|||||||
namespace Spine {
|
namespace Spine {
|
||||||
public class AnimationState {
|
public class AnimationState {
|
||||||
static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
|
static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
|
||||||
|
internal const int SUBSEQUENT = 0, FIRST = 1, DIP = 2;
|
||||||
|
|
||||||
private AnimationStateData data;
|
private AnimationStateData data;
|
||||||
private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
|
private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
|
||||||
@ -41,24 +42,8 @@ namespace Spine {
|
|||||||
private readonly ExposedList<Event> events = new ExposedList<Event>();
|
private readonly ExposedList<Event> events = new ExposedList<Event>();
|
||||||
private readonly EventQueue queue;
|
private readonly EventQueue queue;
|
||||||
|
|
||||||
|
private readonly ExposedList<TrackEntry> mixingTo = new ExposedList<TrackEntry>();
|
||||||
private bool animationsChanged;
|
private bool animationsChanged;
|
||||||
private bool multipleMixing;
|
|
||||||
/// <summary>
|
|
||||||
/// <para>When false, only two animations can be mixed at once. Interrupting a mix by setting a new animation will choose from the
|
|
||||||
/// two old animations the one that is closest to being fully mixed in and the other is discarded. Discarding an animation in
|
|
||||||
/// this way may cause keyed values to jump.</para>
|
|
||||||
/// <para>When true, any number of animations may be mixed at once without causing keyed values to jump. Mixing is done by mixing out
|
|
||||||
/// one or more animations while mixing in the newest one. When animations key the same value, this may cause "dipping", where
|
|
||||||
/// the value moves toward the setup pose as the old animation mixes out, then back to the keyed value as the new animation
|
|
||||||
/// mixes in.</para>
|
|
||||||
/// Defaults to false.</summary>
|
|
||||||
public bool MultipleMixing {
|
|
||||||
get { return multipleMixing; }
|
|
||||||
set {
|
|
||||||
multipleMixing = value;
|
|
||||||
animationsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float timeScale = 1;
|
private float timeScale = 1;
|
||||||
|
|
||||||
@ -122,16 +107,23 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (current.trackLast >= current.trackEnd && current.mixingFrom == null) {
|
||||||
// Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
|
// Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
|
||||||
if (current.trackLast >= current.trackEnd && current.mixingFrom == null) {
|
tracksItems[i] = null;
|
||||||
tracksItems[i] = null;
|
|
||||||
queue.End(current);
|
queue.End(current);
|
||||||
DisposeNext(current);
|
DisposeNext(current);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (current.mixingFrom != null && UpdateMixingFrom(current, delta, 2)) {
|
||||||
|
// End mixing from entries once all have completed.
|
||||||
|
var from = current.mixingFrom;
|
||||||
|
current.mixingFrom = null;
|
||||||
|
while (from != null) {
|
||||||
|
queue.End(from);
|
||||||
|
from = from.mixingFrom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UpdateMixingFrom(current, delta);
|
|
||||||
|
|
||||||
current.trackTime += currentDelta;
|
current.trackTime += currentDelta;
|
||||||
}
|
}
|
||||||
@ -139,22 +131,27 @@ namespace Spine {
|
|||||||
queue.Drain();
|
queue.Drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateMixingFrom (TrackEntry entry, float delta) {
|
/// <summary>Returns true when all mixing from entries are complete.</summary>
|
||||||
|
private bool UpdateMixingFrom (TrackEntry entry, float delta, int animationCount) {
|
||||||
TrackEntry from = entry.mixingFrom;
|
TrackEntry from = entry.mixingFrom;
|
||||||
if (from == null) return;
|
if (from == null) return true;
|
||||||
|
|
||||||
UpdateMixingFrom(from, delta);
|
bool finished = UpdateMixingFrom(from, delta, animationCount + 1);
|
||||||
|
|
||||||
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) {
|
// Require mixTime > 0 to ensure the mixing from entry was applied at least once.
|
||||||
entry.mixingFrom = null;
|
if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
|
||||||
queue.End(from);
|
if (animationCount > 6 && from.mixingFrom == null) { // Limit the mixing from linked list.
|
||||||
return;
|
entry.mixingFrom = null;
|
||||||
|
queue.End(from);
|
||||||
|
}
|
||||||
|
return finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
from.animationLast = from.nextAnimationLast;
|
from.animationLast = from.nextAnimationLast;
|
||||||
from.trackLast = from.nextTrackLast;
|
from.trackLast = from.nextTrackLast;
|
||||||
from.trackTime += delta * from.timeScale;
|
from.trackTime += delta * from.timeScale;
|
||||||
entry.mixTime += delta * entry.timeScale;
|
entry.mixTime += delta * entry.timeScale;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -188,19 +185,20 @@ namespace Spine {
|
|||||||
for (int ii = 0; ii < timelineCount; ii++)
|
for (int ii = 0; ii < timelineCount; ii++)
|
||||||
timelinesItems[ii].Apply(skeleton, animationLast, animationTime, events, 1, true, false);
|
timelinesItems[ii].Apply(skeleton, animationLast, animationTime, events, 1, true, false);
|
||||||
} else {
|
} else {
|
||||||
|
var timelineData = current.timelineData.Items;
|
||||||
|
|
||||||
bool firstFrame = current.timelinesRotation.Count == 0;
|
bool firstFrame = current.timelinesRotation.Count == 0;
|
||||||
if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1);
|
if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1);
|
||||||
var timelinesRotation = current.timelinesRotation.Items;
|
var timelinesRotation = current.timelinesRotation.Items;
|
||||||
|
|
||||||
var timelinesFirstItems = current.timelinesFirst.Items;
|
|
||||||
for (int ii = 0; ii < timelineCount; ii++) {
|
for (int ii = 0; ii < timelineCount; ii++) {
|
||||||
Timeline timeline = timelinesItems[ii];
|
Timeline timeline = timelinesItems[ii];
|
||||||
var rotateTimeline = timeline as RotateTimeline;
|
var rotateTimeline = timeline as RotateTimeline;
|
||||||
if (rotateTimeline != null) {
|
if (rotateTimeline != null) {
|
||||||
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelinesFirstItems[ii], timelinesRotation, ii << 1,
|
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1,
|
||||||
firstFrame);
|
firstFrame);
|
||||||
} else {
|
} else {
|
||||||
timeline.Apply(skeleton, animationLast, animationTime, events, mix, timelinesFirstItems[ii], false);
|
timeline.Apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,15 +211,15 @@ namespace Spine {
|
|||||||
queue.Drain();
|
queue.Drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float ApplyMixingFrom (TrackEntry entry, Skeleton skeleton) {
|
private float ApplyMixingFrom (TrackEntry to, Skeleton skeleton) {
|
||||||
TrackEntry from = entry.mixingFrom;
|
TrackEntry from = to.mixingFrom;
|
||||||
if (from.mixingFrom != null) ApplyMixingFrom(from, skeleton);
|
if (from.mixingFrom != null) ApplyMixingFrom(from, skeleton);
|
||||||
|
|
||||||
float mix;
|
float mix;
|
||||||
if (entry.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
||||||
mix = 1;
|
mix = 1;
|
||||||
else {
|
else {
|
||||||
mix = entry.mixTime / entry.mixDuration;
|
mix = to.mixTime / to.mixDuration;
|
||||||
if (mix > 1) mix = 1;
|
if (mix > 1) mix = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,36 +227,50 @@ namespace Spine {
|
|||||||
bool attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
|
bool attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
|
||||||
float animationLast = from.animationLast, animationTime = from.AnimationTime;
|
float animationLast = from.animationLast, animationTime = from.AnimationTime;
|
||||||
var timelines = from.animation.timelines;
|
var timelines = from.animation.timelines;
|
||||||
var timelinesItems = timelines.Items;
|
|
||||||
int timelineCount = timelines.Count;
|
int timelineCount = timelines.Count;
|
||||||
var timelinesFirst = from.timelinesFirst;
|
var timelinesItems = timelines.Items;
|
||||||
var timelinesFirstItems = timelinesFirst.Items;
|
var timelineData = from.timelineData.Items;
|
||||||
var timelinesLastItems = multipleMixing ? null : from.timelinesLast.Items;
|
var timelineDipMix = from.timelineDipMix.Items;
|
||||||
float alphaBase = from.alpha * entry.mixAlpha;
|
|
||||||
float alphaMix = alphaBase * (1 - mix);
|
|
||||||
|
|
||||||
bool firstFrame = entry.timelinesRotation.Count == 0;
|
bool firstFrame = from.timelinesRotation.Count == 0;
|
||||||
if (firstFrame) entry.timelinesRotation.EnsureCapacity(timelines.Count << 1);
|
if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
|
||||||
var timelinesRotation = entry.timelinesRotation.Items;
|
var timelinesRotation = from.timelinesRotation.Items;
|
||||||
|
|
||||||
|
bool first;
|
||||||
|
float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
|
||||||
for (int i = 0; i < timelineCount; i++) {
|
for (int i = 0; i < timelineCount; i++) {
|
||||||
Timeline timeline = timelinesItems[i];
|
Timeline timeline = timelinesItems[i];
|
||||||
bool setupPose = timelinesFirstItems[i];
|
switch (timelineData[i]) {
|
||||||
float alpha = timelinesLastItems != null && setupPose && !timelinesLastItems[i] ? alphaBase : alphaMix;
|
case SUBSEQUENT:
|
||||||
|
first = false;
|
||||||
|
alpha = alphaMix;
|
||||||
|
break;
|
||||||
|
case FIRST:
|
||||||
|
first = true;
|
||||||
|
alpha = alphaMix;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
first = true;
|
||||||
|
alpha = alphaDip;
|
||||||
|
var dipMix = timelineDipMix[i];
|
||||||
|
if (dipMix != null) alpha *= Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
var rotateTimeline = timeline as RotateTimeline;
|
var rotateTimeline = timeline as RotateTimeline;
|
||||||
if (rotateTimeline != null) {
|
if (rotateTimeline != null) {
|
||||||
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame);
|
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
|
||||||
} else {
|
} else {
|
||||||
if (!setupPose) {
|
if (!first) {
|
||||||
if (!attachments && timeline is AttachmentTimeline) continue;
|
if (!attachments && timeline is AttachmentTimeline) continue;
|
||||||
if (!drawOrder && timeline is DrawOrderTimeline) continue;
|
if (!drawOrder && timeline is DrawOrderTimeline) continue;
|
||||||
}
|
}
|
||||||
timeline.Apply(skeleton, animationLast, animationTime, eventBuffer, alpha, setupPose, true);
|
timeline.Apply(skeleton, animationLast, animationTime, eventBuffer, alpha, first, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.mixDuration > 0 ) QueueEvents(from, animationTime);
|
if (to.mixDuration > 0) QueueEvents(from, animationTime);
|
||||||
events.Clear(false);
|
this.events.Clear(false);
|
||||||
from.nextAnimationLast = animationTime;
|
from.nextAnimationLast = animationTime;
|
||||||
from.nextTrackLast = from.trackTime;
|
from.nextTrackLast = from.trackTime;
|
||||||
|
|
||||||
@ -411,29 +423,9 @@ namespace Spine {
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
|
|
||||||
//from.timelinesRotation.Clear();
|
// Store interrupted mix percentage.
|
||||||
var mixingFrom = from.mixingFrom;
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
|
current.interruptAlpha *= Math.Min(1, from.mixTime / from.mixDuration);
|
||||||
if (mixingFrom != null && from.mixDuration > 0) {
|
|
||||||
if (multipleMixing) {
|
|
||||||
// The interrupted mix will mix out from its current percentage to zero.
|
|
||||||
current.mixAlpha *= Math.Min(from.mixTime / from.mixDuration, 1);
|
|
||||||
} else {
|
|
||||||
// A mix was interrupted, mix from the closest animation.
|
|
||||||
if (from.mixTime / from.mixDuration < 0.5f && mixingFrom.animation != AnimationState.EmptyAnimation) {
|
|
||||||
current.mixingFrom = mixingFrom;
|
|
||||||
mixingFrom.mixingFrom = from;
|
|
||||||
mixingFrom.mixTime = from.mixDuration - from.mixTime;
|
|
||||||
mixingFrom.mixDuration = from.mixDuration;
|
|
||||||
from.mixingFrom = null;
|
|
||||||
from = mixingFrom;
|
|
||||||
}
|
|
||||||
|
|
||||||
from.mixAlpha = 0;
|
|
||||||
from.mixTime = 0;
|
|
||||||
from.mixDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
from.timelinesRotation.Clear(); // Reset rotation for mixing out, in case entry was mixed in.
|
from.timelinesRotation.Clear(); // Reset rotation for mixing out, in case entry was mixed in.
|
||||||
}
|
}
|
||||||
@ -595,7 +587,7 @@ namespace Spine {
|
|||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
|
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.interruptAlpha = 1;
|
||||||
entry.mixTime = 0;
|
entry.mixTime = 0;
|
||||||
entry.mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation);
|
entry.mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation);
|
||||||
return entry;
|
return entry;
|
||||||
@ -614,88 +606,20 @@ namespace Spine {
|
|||||||
animationsChanged = false;
|
animationsChanged = false;
|
||||||
|
|
||||||
var propertyIDs = this.propertyIDs;
|
var propertyIDs = this.propertyIDs;
|
||||||
|
|
||||||
// Set timelinesFirst for all entries, from lowest track to highest.
|
|
||||||
int i = 0, n = tracks.Count;
|
|
||||||
propertyIDs.Clear();
|
propertyIDs.Clear();
|
||||||
for (; i < n; i++) { // Find first non-null entry.
|
var mixingTo = this.mixingTo;
|
||||||
TrackEntry entry = tracks.Items[i];
|
|
||||||
if (entry == null) continue;
|
|
||||||
SetTimelinesFirst(entry);
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (; i < n; i++) { // Rest of entries.
|
|
||||||
TrackEntry entry = tracks.Items[i];
|
|
||||||
if (entry != null) CheckTimelinesFirst(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multipleMixing) return;
|
TrackEntry lastEntry = null;
|
||||||
|
var tracksItems = tracks.Items;
|
||||||
// Set timelinesLast for mixingFrom entries, from highest track to lowest that has mixingFrom.
|
for (int i = 0, n = tracks.Count; i < n; i++) {
|
||||||
propertyIDs.Clear();
|
var entry = tracksItems[i];
|
||||||
int lowestMixingFrom = n;
|
if (entry != null) {
|
||||||
for (i = 0; i < n; i++) { // Find lowest track with a mixingFrom entry.
|
entry.SetTimelineData(lastEntry, mixingTo, propertyIDs);
|
||||||
TrackEntry entry = tracks.Items[i];
|
lastEntry = entry;
|
||||||
if (entry == null || entry.mixingFrom == null) continue;
|
|
||||||
lowestMixingFrom = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (i = n - 1; i >= lowestMixingFrom; i--) { // Find first non-null entry.
|
|
||||||
TrackEntry entry = tracks.Items[i];
|
|
||||||
if (entry == null) continue;
|
|
||||||
|
|
||||||
// Store properties for non-mixingFrom entry but don't set timelinesLast, which is only used for mixingFrom entries.
|
|
||||||
var timelines = entry.animation.timelines;
|
|
||||||
var timelinesItems = timelines.Items;
|
|
||||||
for (int ii = 0, nn = timelines.Count; ii < nn; ii++)
|
|
||||||
propertyIDs.Add(timelinesItems[ii].PropertyId);
|
|
||||||
|
|
||||||
entry = entry.mixingFrom;
|
|
||||||
while (entry != null) {
|
|
||||||
CheckTimelinesUsage(entry, entry.timelinesLast);
|
|
||||||
entry = entry.mixingFrom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>From last to first mixingFrom entries, sets timelinesFirst to true on last, calls checkTimelineUsage on rest.</summary>
|
|
||||||
private void SetTimelinesFirst (TrackEntry entry) {
|
|
||||||
if (entry.mixingFrom != null) {
|
|
||||||
SetTimelinesFirst(entry.mixingFrom);
|
|
||||||
CheckTimelinesUsage(entry, entry.timelinesFirst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var propertyIDs = this.propertyIDs;
|
|
||||||
var timelines = entry.animation.timelines;
|
|
||||||
int n = timelines.Count;
|
|
||||||
entry.timelinesFirst.EnsureCapacity(n); // entry.timelinesFirst.setSize(n);
|
|
||||||
var usage = entry.timelinesFirst.Items;
|
|
||||||
var timelinesItems = timelines.Items;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
propertyIDs.Add(timelinesItems[i].PropertyId);
|
|
||||||
usage[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>From last to first mixingFrom entries, calls checkTimelineUsage.</summary>
|
|
||||||
private void CheckTimelinesFirst (TrackEntry entry) {
|
|
||||||
if (entry.mixingFrom != null) CheckTimelinesFirst(entry.mixingFrom);
|
|
||||||
CheckTimelinesUsage(entry, entry.timelinesFirst);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckTimelinesUsage (TrackEntry entry, ExposedList<bool> usageArray) {
|
|
||||||
var propertyIDs = this.propertyIDs;
|
|
||||||
var timelines = entry.animation.timelines;
|
|
||||||
int n = timelines.Count;
|
|
||||||
//var usageArray = entry.timelinesFirst;
|
|
||||||
usageArray.EnsureCapacity(n);
|
|
||||||
var usage = usageArray.Items;
|
|
||||||
var timelinesItems = timelines.Items;
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
usage[i] = propertyIDs.Add(timelinesItems[i].PropertyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns>
|
/// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns>
|
||||||
public TrackEntry GetCurrent (int trackIndex) {
|
public TrackEntry GetCurrent (int trackIndex) {
|
||||||
return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex];
|
return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex];
|
||||||
@ -731,9 +655,9 @@ namespace Spine {
|
|||||||
internal float eventThreshold, attachmentThreshold, drawOrderThreshold;
|
internal float eventThreshold, attachmentThreshold, drawOrderThreshold;
|
||||||
internal float animationStart, animationEnd, animationLast, nextAnimationLast;
|
internal float animationStart, animationEnd, animationLast, nextAnimationLast;
|
||||||
internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f;
|
internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f;
|
||||||
internal float alpha, mixTime, mixDuration, mixAlpha;
|
internal float alpha, mixTime, mixDuration, interruptAlpha;
|
||||||
internal readonly ExposedList<bool> timelinesFirst = new ExposedList<bool>();
|
internal readonly ExposedList<int> timelineData = new ExposedList<int>();
|
||||||
internal readonly ExposedList<bool> timelinesLast = new ExposedList<bool>();
|
internal readonly ExposedList<TrackEntry> timelineDipMix = new ExposedList<TrackEntry>();
|
||||||
internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
|
internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
|
||||||
|
|
||||||
// IPoolable.Reset()
|
// IPoolable.Reset()
|
||||||
@ -741,8 +665,8 @@ namespace Spine {
|
|||||||
next = null;
|
next = null;
|
||||||
mixingFrom = null;
|
mixingFrom = null;
|
||||||
animation = null;
|
animation = null;
|
||||||
timelinesFirst.Clear();
|
timelineData.Clear();
|
||||||
timelinesLast.Clear();
|
timelineDipMix.Clear();
|
||||||
timelinesRotation.Clear();
|
timelinesRotation.Clear();
|
||||||
|
|
||||||
Start = null;
|
Start = null;
|
||||||
@ -753,6 +677,49 @@ namespace Spine {
|
|||||||
Event = null;
|
Event = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <param name="to">May be null.</param>
|
||||||
|
internal TrackEntry SetTimelineData (TrackEntry to, ExposedList<TrackEntry> mixingToArray, HashSet<int> propertyIDs) {
|
||||||
|
if (to != null) mixingToArray.Add(to);
|
||||||
|
var lastEntry = mixingFrom != null ? mixingFrom.SetTimelineData(this, mixingToArray, propertyIDs) : this;
|
||||||
|
if (to != null) mixingToArray.RemoveAt(mixingToArray.Count - 1); // mixingToArray.pop();
|
||||||
|
|
||||||
|
var mixingTo = mixingToArray.Items;
|
||||||
|
int mixingToLast = mixingToArray.Count - 1;
|
||||||
|
var timelines = animation.timelines.Items;
|
||||||
|
int timelinesCount = animation.timelines.Count;
|
||||||
|
var timelineDataItems = this.timelineData.Resize(timelinesCount).Items; // timelineData.setSize(timelinesCount);
|
||||||
|
var timelineDipMixItems = this.timelineDipMix.Resize(timelinesCount).Items; //timelineDipMix.setSize(timelinesCount);
|
||||||
|
|
||||||
|
// outer:
|
||||||
|
for (int i = 0; i < timelinesCount; i++) {
|
||||||
|
int id = timelines[i].PropertyId;
|
||||||
|
if (!propertyIDs.Add(id)) {
|
||||||
|
timelineDataItems[i] = AnimationState.SUBSEQUENT;
|
||||||
|
} else if (to == null || !to.HasTimeline(id)) {
|
||||||
|
timelineDataItems[i] = AnimationState.FIRST;
|
||||||
|
} else {
|
||||||
|
timelineDataItems[i] = AnimationState.DIP;
|
||||||
|
for (int ii = mixingToLast; ii >= 0; ii--) {
|
||||||
|
var entry = mixingTo[ii];
|
||||||
|
if (!entry.HasTimeline(id)) {
|
||||||
|
timelineDipMixItems[i] = entry;
|
||||||
|
goto outer; // continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timelineDipMixItems[i] = null;
|
||||||
|
}
|
||||||
|
outer: {}
|
||||||
|
}
|
||||||
|
return lastEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasTimeline (int id) {
|
||||||
|
var timelines = animation.timelines.Items;
|
||||||
|
for (int i = 0, n = animation.timelines.Count; i < n; i++)
|
||||||
|
if (timelines[i].PropertyId == id) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>The index of the track where this entry is either current or queued.</summary>
|
/// <summary>The index of the track where this entry is either current or queued.</summary>
|
||||||
public int TrackIndex { get { return trackIndex; } }
|
public int TrackIndex { get { return trackIndex; } }
|
||||||
|
|
||||||
@ -870,17 +837,18 @@ namespace Spine {
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seconds from 0 to the mix duration when mixing from the previous animation to this animation. May be slightly more than
|
/// Seconds from 0 to the mix duration when mixing from the previous animation to this animation. May be slightly more than
|
||||||
/// <see cref="TrackEntry.MixDuration"/>.</summary>
|
/// <see cref="TrackEntry.MixDuration"/> when the mix is complete.</summary>
|
||||||
public float MixTime { get { return mixTime; } set { mixTime = value; } }
|
public float MixTime { get { return mixTime; } set { mixTime = value; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seconds for mixing from the previous animation to this animation. Defaults to the value provided by
|
/// Seconds for mixing from the previous animation to this animation. Defaults to the value provided by
|
||||||
/// <see cref="AnimationStateData"/> based on the animation before this animation (if any).
|
/// <see cref="AnimationStateData"/> based on the animation before this animation (if any).
|
||||||
///
|
///
|
||||||
/// The mix duration must be set before <see cref="AnimationState.Update(float)"/> is next called.
|
/// The mix duration can be set manually rather than use the value from AnimationStateData.GetMix.
|
||||||
|
/// In that case, the mixDuration must be set before <see cref="AnimationState.Update(float)"/> is next called.
|
||||||
/// <para>
|
/// <para>
|
||||||
/// When using <seealso cref="AnimationState.AddAnimation(int, Animation, bool, float)"/> with a
|
/// When using <seealso cref="AnimationState.AddAnimation(int, Animation, bool, float)"/> with a
|
||||||
/// <code>delay</code> <seealso cref="Delay"/> is set using the mix duration from the <see cref=" AnimationStateData"/>
|
/// <code>delay</code> less than or equal to 0, note the <seealso cref="Delay"/> is set using the mix duration from the <see cref=" AnimationStateData"/>
|
||||||
/// </para>
|
/// </para>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -888,7 +856,7 @@ namespace Spine {
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The track entry for the previous animation when mixing from the previous animation to this animation, or null if no
|
/// The track entry for the previous animation when mixing from the previous animation to this animation, or null if no
|
||||||
/// mixing is currently occuring.</summary>
|
/// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a linked list.</summary>
|
||||||
public TrackEntry MixingFrom { get { return mixingFrom; } }
|
public TrackEntry MixingFrom { get { return mixingFrom; } }
|
||||||
|
|
||||||
public event AnimationState.TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
|
public event AnimationState.TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
|
||||||
|
|||||||
@ -49,7 +49,7 @@ namespace Spine {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Adds an attachment to the skin for the specified slot index and name.</summary>
|
/// <summary>Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced.</summary>
|
||||||
public void AddAttachment (int slotIndex, string name, Attachment attachment) {
|
public void AddAttachment (int slotIndex, string name, Attachment attachment) {
|
||||||
if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
|
if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
|
||||||
attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
|
attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -1215,7 +1215,7 @@ var spine;
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
var dipMix = timelineDipMix[i];
|
var dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0)
|
if (dipMix != null)
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1569,8 @@ var spine;
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
var entry = mixingTo[ii];
|
var entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0)
|
||||||
|
timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1215,7 +1215,7 @@ var spine;
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
var dipMix = timelineDipMix[i];
|
var dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0)
|
if (dipMix != null)
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1569,8 @@ var spine;
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
var entry = mixingTo[ii];
|
var entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0)
|
||||||
|
timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1215,7 +1215,7 @@ var spine;
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
var dipMix = timelineDipMix[i];
|
var dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0)
|
if (dipMix != null)
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1569,8 @@ var spine;
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
var entry = mixingTo[ii];
|
var entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0)
|
||||||
|
timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1215,7 +1215,7 @@ var spine;
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
var dipMix = timelineDipMix[i];
|
var dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0)
|
if (dipMix != null)
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1569,8 @@ var spine;
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
var entry = mixingTo[ii];
|
var entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0)
|
||||||
|
timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1215,7 +1215,7 @@ var spine;
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
var dipMix = timelineDipMix[i];
|
var dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0)
|
if (dipMix != null)
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1569,8 @@ var spine;
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
var entry = mixingTo[ii];
|
var entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0)
|
||||||
|
timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1215,7 +1215,7 @@ var spine;
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
var dipMix = timelineDipMix[i];
|
var dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0)
|
if (dipMix != null)
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1569,8 @@ var spine;
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
var entry = mixingTo[ii];
|
var entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0)
|
||||||
|
timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -220,7 +220,7 @@ module spine {
|
|||||||
first = true;
|
first = true;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
let dipMix = timelineDipMix[i];
|
let dipMix = timelineDipMix[i];
|
||||||
if (dipMix != null && dipMix.mixDuration > 0) alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
if (dipMix != null) alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (timeline instanceof RotateTimeline)
|
if (timeline instanceof RotateTimeline)
|
||||||
@ -613,7 +613,7 @@ module spine {
|
|||||||
for (var ii = mixingToLast; ii >= 0; ii--) {
|
for (var ii = mixingToLast; ii >= 0; ii--) {
|
||||||
let entry = mixingTo[ii];
|
let entry = mixingTo[ii];
|
||||||
if (!entry.hasTimeline(id)) {
|
if (!entry.hasTimeline(id)) {
|
||||||
timelineDipMix[i] = entry;
|
if (entry.mixDuration > 0) timelineDipMix[i] = entry;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user