mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 22:34:53 +08:00
Okay, AnimationState is done, on to SkeletonJson and SkeletonBinary
This commit is contained in:
parent
af43d7cff1
commit
3fc2f08ff6
@ -70,7 +70,7 @@ namespace Spine
|
||||
|
||||
/// Applies all the animation's timelines to the specified skeleton.
|
||||
/// See also Timeline::apply(Skeleton&, float, float, Vector, float, MixPose, MixDirection)
|
||||
void apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
void apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
std::string getName();
|
||||
|
||||
|
||||
@ -297,181 +297,30 @@ namespace Spine
|
||||
|
||||
~AnimationState();
|
||||
|
||||
void setOnAnimationEventFunc(OnAnimationEventFunc inValue);
|
||||
|
||||
///
|
||||
/// Increments the track entry times, setting queued animations as current if needed
|
||||
/// @param delta delta time
|
||||
void update(float delta)
|
||||
{
|
||||
// delta *= timeScale;
|
||||
// var tracksItems = tracks.Items;
|
||||
// for (int i = 0, n = tracks.Count; i < n; i++) {
|
||||
// TrackEntry current = tracksItems[i];
|
||||
// if (current == NULL) continue;
|
||||
//
|
||||
// current.animationLast = current.nextAnimationLast;
|
||||
// current.trackLast = current.nextTrackLast;
|
||||
//
|
||||
// float currentDelta = delta * current.timeScale;
|
||||
//
|
||||
// if (current.delay > 0) {
|
||||
// current.delay -= currentDelta;
|
||||
// if (current.delay > 0) continue;
|
||||
// currentDelta = -current.delay;
|
||||
// current.delay = 0;
|
||||
// }
|
||||
//
|
||||
// TrackEntry next = current.next;
|
||||
// if (next != NULL) {
|
||||
// // When the next entry's delay is passed, change to the next entry, preserving leftover time.
|
||||
// float nextTime = current.trackLast - next.delay;
|
||||
// if (nextTime >= 0) {
|
||||
// next.delay = 0;
|
||||
// next.trackTime = nextTime + (delta * next.timeScale);
|
||||
// current.trackTime += currentDelta;
|
||||
// setCurrent(i, next, true);
|
||||
// while (next.mixingFrom != NULL) {
|
||||
// next.mixTime += currentDelta;
|
||||
// next = next.mixingFrom;
|
||||
// }
|
||||
// continue;
|
||||
// }
|
||||
// } 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.
|
||||
// tracksItems[i] = NULL;
|
||||
//
|
||||
// queue.end(current);
|
||||
// disposeNext(current);
|
||||
// continue;
|
||||
// }
|
||||
// if (current.mixingFrom != NULL && updateMixingFrom(current, delta)) {
|
||||
// // End mixing from entries once all have completed.
|
||||
// var from = current.mixingFrom;
|
||||
// current.mixingFrom = NULL;
|
||||
// while (from != NULL) {
|
||||
// queue.end(from);
|
||||
// from = from.mixingFrom;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// current.trackTime += currentDelta;
|
||||
// }
|
||||
//
|
||||
// queue.drain();
|
||||
}
|
||||
void update(float delta);
|
||||
|
||||
///
|
||||
/// Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the
|
||||
/// animation state can be applied to multiple skeletons to pose them identically.
|
||||
bool apply(Skeleton& skeleton)
|
||||
{
|
||||
// if (animationsChanged) animationsChanged();
|
||||
//
|
||||
// var events = _events;
|
||||
//
|
||||
bool applied = false;
|
||||
// var tracksItems = tracks.Items;
|
||||
// for (int i = 0, m = tracks.Count; i < m; i++) {
|
||||
// TrackEntry current = tracksItems[i];
|
||||
// if (current == NULL || current.delay > 0) continue;
|
||||
// applied = true;
|
||||
// MixPose currentPose = i == 0 ? MixPose.Current : MixPose.CurrentLayered;
|
||||
//
|
||||
// // apply mixing from entries first.
|
||||
// float mix = current.alpha;
|
||||
// if (current.mixingFrom != NULL)
|
||||
// mix *= applyMixingFrom(current, skeleton, currentPose);
|
||||
// else if (current.trackTime >= current.trackEnd && current.next == NULL) //
|
||||
// mix = 0; // Set to setup pose the last time the entry will be applied.
|
||||
//
|
||||
// // apply current entry.
|
||||
// float animationLast = current.animationLast, animationTime = current.AnimationTime;
|
||||
// int timelineCount = current.animation.timelines.Count;
|
||||
// var timelines = current.animation.timelines;
|
||||
// var timelinesItems = timelines.Items;
|
||||
// if (mix == 1) {
|
||||
// for (int ii = 0; ii < timelineCount; ii++)
|
||||
// timelinesItems[ii].apply(skeleton, animationLast, animationTime, events, 1, MixPose.Setup, MixDirection.In);
|
||||
// } else {
|
||||
// var timelineData = current.timelineData.Items;
|
||||
//
|
||||
// bool firstFrame = current.timelinesRotation.Count == 0;
|
||||
// if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1);
|
||||
// var timelinesRotation = current.timelinesRotation.Items;
|
||||
//
|
||||
// for (int ii = 0; ii < timelineCount; ii++) {
|
||||
// Timeline timeline = timelinesItems[ii];
|
||||
// MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose;
|
||||
// var rotateTimeline = timeline as RotateTimeline;
|
||||
// if (rotateTimeline != NULL)
|
||||
// applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
|
||||
// else
|
||||
// timeline.apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection.In);
|
||||
// }
|
||||
// }
|
||||
// queueEvents(current, animationTime);
|
||||
// events.clear(false);
|
||||
// current.nextAnimationLast = animationTime;
|
||||
// current.nextTrackLast = current.trackTime;
|
||||
// }
|
||||
//
|
||||
// queue.drain();
|
||||
return applied;
|
||||
}
|
||||
bool apply(Skeleton& skeleton);
|
||||
|
||||
///
|
||||
/// Removes all animations from all tracks, leaving skeletons in their previous pose.
|
||||
/// It may be desired to use AnimationState.setEmptyAnimations(float) to mix the skeletons back to the setup pose,
|
||||
/// rather than leaving them in their previous pose.
|
||||
void clearTracks()
|
||||
{
|
||||
// bool olddrainDisabled = queue.drainDisabled;
|
||||
// queue.drainDisabled = true;
|
||||
// for (int i = 0, n = tracks.Count; i < n; i++) {
|
||||
// clearTrack(i);
|
||||
// }
|
||||
// tracks.clear();
|
||||
// queue.drainDisabled = olddrainDisabled;
|
||||
// queue.drain();
|
||||
}
|
||||
void clearTracks();
|
||||
|
||||
///
|
||||
/// Removes all animations from the tracks, leaving skeletons in their previous pose.
|
||||
/// It may be desired to use AnimationState.setEmptyAnimations(float) to mix the skeletons back to the setup pose,
|
||||
/// rather than leaving them in their previous pose.
|
||||
void clearTrack(int trackIndex)
|
||||
{
|
||||
// if (trackIndex >= tracks.Count) return;
|
||||
// TrackEntry current = tracks.Items[trackIndex];
|
||||
// if (current == NULL) return;
|
||||
//
|
||||
// queue.end(current);
|
||||
//
|
||||
// disposeNext(current);
|
||||
//
|
||||
// TrackEntry entry = current;
|
||||
// while (true) {
|
||||
// TrackEntry from = entry.mixingFrom;
|
||||
// if (from == NULL) break;
|
||||
// queue.end(from);
|
||||
// entry.mixingFrom = NULL;
|
||||
// entry = from;
|
||||
// }
|
||||
//
|
||||
// tracks.Items[current.trackIndex] = NULL;
|
||||
//
|
||||
// queue.drain();
|
||||
}
|
||||
void clearTrack(int trackIndex);
|
||||
|
||||
/// Sets an animation by name. setAnimation(int, Animation, bool)
|
||||
TrackEntry* setAnimation(int trackIndex, std::string animationName, bool loop)
|
||||
{
|
||||
// Animation animation = data.skeletonData.FindAnimation(animationName);
|
||||
// if (animation == NULL) throw new ArgumentException("Animation not found: " + animationName, "animationName");
|
||||
// return setAnimation(trackIndex, animation, loop);
|
||||
return NULL;
|
||||
}
|
||||
TrackEntry* setAnimation(int trackIndex, std::string animationName, bool loop);
|
||||
|
||||
/// Sets the current animation for a track, discarding any queued animations.
|
||||
/// @param loop If true, the animation will repeat.
|
||||
@ -480,39 +329,11 @@ namespace Spine
|
||||
/// @return
|
||||
/// A track entry to allow further customization of animation playback. References to the track entry must not be kept
|
||||
/// after AnimationState.Dispose.
|
||||
TrackEntry* setAnimation(int trackIndex, Animation& animation, bool loop)
|
||||
{
|
||||
// bool interrupt = true;
|
||||
// TrackEntry current = expandToIndex(trackIndex);
|
||||
// if (current != NULL) {
|
||||
// if (current.nextTrackLast == -1) {
|
||||
// // Don't mix from an entry that was never applied.
|
||||
// tracks.Items[trackIndex] = current.mixingFrom;
|
||||
// queue.interrupt(current);
|
||||
// queue.end(current);
|
||||
// disposeNext(current);
|
||||
// current = current.mixingFrom;
|
||||
// interrupt = false;
|
||||
// } else {
|
||||
// disposeNext(current);
|
||||
// }
|
||||
// }
|
||||
// TrackEntry entry = newTrackEntry(trackIndex, animation, loop, current);
|
||||
// setCurrent(trackIndex, entry, interrupt);
|
||||
// queue.drain();
|
||||
// return entry;
|
||||
return NULL;
|
||||
}
|
||||
TrackEntry* setAnimation(int trackIndex, Animation* animation, bool loop);
|
||||
|
||||
/// Queues an animation by name.
|
||||
/// addAnimation(int, Animation, bool, float)
|
||||
TrackEntry* addAnimation(int trackIndex, std::string animationName, bool loop, float delay)
|
||||
{
|
||||
// Animation animation = data.skeletonData.FindAnimation(animationName);
|
||||
// if (animation == NULL) throw new ArgumentException("Animation not found: " + animationName, "animationName");
|
||||
// return addAnimation(trackIndex, animation, loop, delay);
|
||||
return NULL;
|
||||
}
|
||||
TrackEntry* addAnimation(int trackIndex, std::string animationName, bool loop, float delay);
|
||||
|
||||
/// Adds an animation to be played delay seconds after the current or last queued animation
|
||||
/// for a track. If the track is empty, it is equivalent to calling setAnimation.
|
||||
@ -522,44 +343,11 @@ namespace Spine
|
||||
///
|
||||
/// @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
|
||||
/// after AnimationState.Dispose
|
||||
TrackEntry* addAnimation(int trackIndex, Animation& animation, bool loop, float delay)
|
||||
{
|
||||
// TrackEntry last = expandToIndex(trackIndex);
|
||||
// if (last != NULL) {
|
||||
// while (last.next != NULL)
|
||||
// last = last.next;
|
||||
// }
|
||||
//
|
||||
// TrackEntry entry = newTrackEntry(trackIndex, animation, loop, last);
|
||||
//
|
||||
// if (last == NULL) {
|
||||
// setCurrent(trackIndex, entry, true);
|
||||
// queue.drain();
|
||||
// } else {
|
||||
// last.next = entry;
|
||||
// if (delay <= 0) {
|
||||
// float duration = last.animationEnd - last.animationStart;
|
||||
// if (duration != 0)
|
||||
// delay += duration * (1 + (int)(last.trackTime / duration)) - data.GetMix(last.animation, animation);
|
||||
// else
|
||||
// delay = 0;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// entry.delay = delay;
|
||||
// return entry;
|
||||
return NULL;
|
||||
}
|
||||
TrackEntry* addAnimation(int trackIndex, Animation* animation, bool loop, float delay);
|
||||
|
||||
///
|
||||
/// Sets an empty animation for a track, discarding any queued animations, and mixes to it over the specified mix duration.
|
||||
TrackEntry* setEmptyAnimation(int trackIndex, float mixDuration)
|
||||
{
|
||||
TrackEntry* entry = setAnimation(trackIndex, AnimationState::getEmptyAnimation(), false);
|
||||
entry->_mixDuration = mixDuration;
|
||||
entry->_trackEnd = mixDuration;
|
||||
return entry;
|
||||
}
|
||||
TrackEntry* setEmptyAnimation(int trackIndex, float mixDuration);
|
||||
|
||||
///
|
||||
/// Adds an empty animation to be played after the current or last queued animation for a track, and mixes to it over the
|
||||
@ -571,44 +359,22 @@ namespace Spine
|
||||
/// @param mixDuration Mix duration.
|
||||
/// @param delay Seconds to begin this animation after the start of the previous animation. May be <= 0 to use the animation
|
||||
/// duration of the previous track minus any mix duration plus the negative delay.
|
||||
TrackEntry* addEmptyAnimation(int trackIndex, float mixDuration, float delay)
|
||||
{
|
||||
if (delay <= 0)
|
||||
{
|
||||
delay -= mixDuration;
|
||||
}
|
||||
|
||||
TrackEntry* entry = addAnimation(trackIndex, AnimationState::getEmptyAnimation(), false, delay);
|
||||
entry->_mixDuration = mixDuration;
|
||||
entry->_trackEnd = mixDuration;
|
||||
return entry;
|
||||
}
|
||||
TrackEntry* addEmptyAnimation(int trackIndex, float mixDuration, float delay);
|
||||
|
||||
///
|
||||
/// Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix duration.
|
||||
void setEmptyAnimations(float mixDuration)
|
||||
{
|
||||
// bool olddrainDisabled = queue.drainDisabled;
|
||||
// queue.drainDisabled = true;
|
||||
// for (int i = 0, n = tracks.Count; i < n; i++)
|
||||
// {
|
||||
// TrackEntry current = tracks.Items[i];
|
||||
// if (current != NULL) setEmptyAnimation(i, mixDuration);
|
||||
// }
|
||||
// queue.drainDisabled = olddrainDisabled;
|
||||
// queue.drain();
|
||||
}
|
||||
void setEmptyAnimations(float mixDuration);
|
||||
|
||||
/// @return The track entry for the animation currently playing on the track, or NULL if no animation is currently playing.
|
||||
TrackEntry* getCurrent(int trackIndex)
|
||||
{
|
||||
return trackIndex >= _tracks.size() ? NULL : _tracks[trackIndex];
|
||||
}
|
||||
TrackEntry* getCurrent(int trackIndex);
|
||||
|
||||
// AnimationStateData Data { get { return data; } }
|
||||
// /// A list of tracks that have animations, which may contain NULLs.
|
||||
// Vector<TrackEntry> Tracks { get { return tracks; } }
|
||||
// float TimeScale { get { return timeScale; } set { timeScale = value; } }
|
||||
AnimationStateData& getData();
|
||||
|
||||
/// A list of tracks that have animations, which may contain NULLs.
|
||||
Vector<TrackEntry*> getTracks();
|
||||
float getTimeScale();
|
||||
void setTimeScale(float inValue);
|
||||
void setOnAnimationEventFunc(OnAnimationEventFunc inValue);
|
||||
|
||||
private:
|
||||
static const int Subsequent, First, Dip, DipMix;
|
||||
@ -617,306 +383,41 @@ namespace Spine
|
||||
|
||||
Pool<TrackEntry> _trackEntryPool;
|
||||
Vector<TrackEntry*> _tracks;
|
||||
Vector<Event> _events;
|
||||
Vector<Event*> _events;
|
||||
EventQueue* _queue;
|
||||
|
||||
Vector<int> _propertyIDs;
|
||||
Vector<TrackEntry> _mixingTo;
|
||||
Vector<TrackEntry*> _mixingTo;
|
||||
bool _animationsChanged;
|
||||
|
||||
OnAnimationEventFunc _onAnimationEventFunc;
|
||||
|
||||
float _timeScale;
|
||||
|
||||
static Animation& getEmptyAnimation();
|
||||
static Animation* getEmptyAnimation();
|
||||
|
||||
static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose,
|
||||
Vector<float>& timelinesRotation, int i, bool firstFrame)
|
||||
{
|
||||
// if (firstFrame) timelinesRotation[i] = 0;
|
||||
//
|
||||
// if (alpha == 1) {
|
||||
// rotateTimeline.apply(skeleton, 0, time, NULL, 1, pose, MixDirection.In);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Bone bone = skeleton.bones.Items[rotateTimeline.boneIndex];
|
||||
// float[] frames = rotateTimeline.frames;
|
||||
// if (time < frames[0]) {
|
||||
// if (pose == MixPose.Setup) bone.rotation = bone.data.rotation;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// float r2;
|
||||
// if (time >= frames[frames.Length - RotateTimeline.ENTRIES]) // Time is after last frame.
|
||||
// r2 = bone.data.rotation + frames[frames.Length + RotateTimeline.PREV_ROTATION];
|
||||
// else {
|
||||
// // Interpolate between the previous frame and the current frame.
|
||||
// int frame = Animation.BinarySearch(frames, time, RotateTimeline.ENTRIES);
|
||||
// float prevRotation = frames[frame + RotateTimeline.PREV_ROTATION];
|
||||
// float frameTime = frames[frame];
|
||||
// float percent = rotateTimeline.GetCurvePercent((frame >> 1) - 1,
|
||||
// 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime));
|
||||
//
|
||||
// r2 = frames[frame + RotateTimeline.ROTATION] - prevRotation;
|
||||
// r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
||||
// r2 = prevRotation + r2 * percent + bone.data.rotation;
|
||||
// r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
||||
// }
|
||||
//
|
||||
// // Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
||||
// float r1 = pose == MixPose.Setup ? bone.data.rotation : bone.rotation;
|
||||
// float total, diff = r2 - r1;
|
||||
// if (diff == 0) {
|
||||
// total = timelinesRotation[i];
|
||||
// } else {
|
||||
// diff -= (16384 - (int)(16384.499999999996 - diff / 360)) * 360;
|
||||
// float lastTotal, lastDiff;
|
||||
// if (firstFrame) {
|
||||
// lastTotal = 0;
|
||||
// lastDiff = diff;
|
||||
// } else {
|
||||
// lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.
|
||||
// lastDiff = timelinesRotation[i + 1]; // Difference between bones.
|
||||
// }
|
||||
// bool current = diff > 0, dir = lastTotal >= 0;
|
||||
// // Detect cross at 0 (not 180).
|
||||
// if (Math.Sign(lastDiff) != Math.Sign(diff) && Math.Abs(lastDiff) <= 90) {
|
||||
// // A cross after a 360 rotation is a loop.
|
||||
// if (Math.Abs(lastTotal) > 180) lastTotal += 360 * Math.Sign(lastTotal);
|
||||
// dir = current;
|
||||
// }
|
||||
// total = diff + lastTotal - lastTotal % 360; // Store loops as part of lastTotal.
|
||||
// if (dir != current) total += 360 * Math.Sign(lastTotal);
|
||||
// timelinesRotation[i] = total;
|
||||
// }
|
||||
// timelinesRotation[i + 1] = diff;
|
||||
// r1 += total * alpha;
|
||||
// bone.rotation = r1 - (16384 - (int)(16384.499999999996 - r1 / 360)) * 360;
|
||||
}
|
||||
static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose, Vector<float>& timelinesRotation, int i, bool firstFrame);
|
||||
|
||||
/// Returns true when all mixing from entries are complete.
|
||||
bool updateMixingFrom(TrackEntry to, float delta)
|
||||
{
|
||||
// TrackEntry from = to.mixingFrom;
|
||||
// if (from == NULL) return true;
|
||||
//
|
||||
// bool finished = updateMixingFrom(from, delta);
|
||||
//
|
||||
// // Require mixTime > 0 to ensure the mixing from entry was applied at least once.
|
||||
// if (to.mixTime > 0 && (to.mixTime >= to.mixDuration || to.timeScale == 0)) {
|
||||
// // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
|
||||
// if (from.totalAlpha == 0 || to.mixDuration == 0) {
|
||||
// to.mixingFrom = from.mixingFrom;
|
||||
// to.interruptAlpha = from.interruptAlpha;
|
||||
// queue.end(from);
|
||||
// }
|
||||
// return finished;
|
||||
// }
|
||||
//
|
||||
// from.animationLast = from.nextAnimationLast;
|
||||
// from.trackLast = from.nextTrackLast;
|
||||
// from.trackTime += delta * from.timeScale;
|
||||
// to.mixTime += delta * to.timeScale;
|
||||
return false;
|
||||
}
|
||||
bool updateMixingFrom(TrackEntry* to, float delta);
|
||||
|
||||
float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose)
|
||||
{
|
||||
// TrackEntry from = to.mixingFrom;
|
||||
// if (from.mixingFrom != NULL) applyMixingFrom(from, skeleton, currentPose);
|
||||
//
|
||||
// float mix;
|
||||
// if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
|
||||
// mix = 1;
|
||||
// currentPose = MixPose.Setup;
|
||||
// } else {
|
||||
// mix = to.mixTime / to.mixDuration;
|
||||
// if (mix > 1) mix = 1;
|
||||
// }
|
||||
//
|
||||
// var eventBuffer = mix < from.eventThreshold ? _events : NULL;
|
||||
// bool attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
|
||||
// float animationLast = from.animationLast, animationTime = from.AnimationTime;
|
||||
// var timelines = from.animation.timelines;
|
||||
// int timelineCount = timelines.Count;
|
||||
// var timelinesItems = timelines.Items;
|
||||
// var timelineData = from.timelineData.Items;
|
||||
// var timelineDipMix = from.timelineDipMix.Items;
|
||||
//
|
||||
// bool firstFrame = from.timelinesRotation.Count == 0;
|
||||
// if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
|
||||
// var timelinesRotation = from.timelinesRotation.Items;
|
||||
//
|
||||
// MixPose pose;
|
||||
// float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
|
||||
// from.totalAlpha = 0;
|
||||
// for (int i = 0; i < timelineCount; i++) {
|
||||
// Timeline timeline = timelinesItems[i];
|
||||
// switch (timelineData[i]) {
|
||||
// case Subsequent:
|
||||
// if (!attachments && timeline is AttachmentTimeline) continue;
|
||||
// if (!drawOrder && timeline is DrawOrderTimeline) continue;
|
||||
// pose = currentPose;
|
||||
// alpha = alphaMix;
|
||||
// break;
|
||||
// case First:
|
||||
// pose = MixPose.Setup;
|
||||
// alpha = alphaMix;
|
||||
// break;
|
||||
// case Dip:
|
||||
// pose = MixPose.Setup;
|
||||
// alpha = alphaDip;
|
||||
// break;
|
||||
// default:
|
||||
// pose = MixPose.Setup;
|
||||
// TrackEntry dipMix = timelineDipMix[i];
|
||||
// alpha = alphaDip * Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||
// break;
|
||||
// }
|
||||
// from.totalAlpha += alpha;
|
||||
// var rotateTimeline = timeline as RotateTimeline;
|
||||
// if (rotateTimeline != NULL) {
|
||||
// applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
|
||||
// } else {
|
||||
// timeline.apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection.Out);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (to.mixDuration > 0) queueEvents(from, animationTime);
|
||||
// _events.clear(false);
|
||||
// from.nextAnimationLast = animationTime;
|
||||
// from.nextTrackLast = from.trackTime;
|
||||
//
|
||||
// return mix;
|
||||
return 0;
|
||||
}
|
||||
float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose);
|
||||
|
||||
void queueEvents(TrackEntry* entry, float animationTime)
|
||||
{
|
||||
// float animationStart = entry.animationStart, animationEnd = entry.animationEnd;
|
||||
// float duration = animationEnd - animationStart;
|
||||
// float trackLastWrapped = entry.trackLast % duration;
|
||||
//
|
||||
// // Queue events before complete.
|
||||
// var events = _events;
|
||||
// var eventsItems = events.Items;
|
||||
// int i = 0, n = events.Count;
|
||||
// for (; i < n; i++) {
|
||||
// var e = eventsItems[i];
|
||||
// if (e.time < trackLastWrapped) break;
|
||||
// if (e.time > animationEnd) continue; // Discard events outside animation start/end.
|
||||
// queue.event(entry, e);
|
||||
// }
|
||||
//
|
||||
// // Queue complete if completed a loop iteration or the animation.
|
||||
// if (entry.loop ? (trackLastWrapped > entry.trackTime % duration)
|
||||
// : (animationTime >= animationEnd && entry.animationLast < animationEnd)) {
|
||||
// queue.complete(entry);
|
||||
// }
|
||||
//
|
||||
// // Queue events after complete.
|
||||
// for (; i < n; i++) {
|
||||
// Event e = eventsItems[i];
|
||||
// if (e.time < animationStart) continue; // Discard events outside animation start/end.
|
||||
// queue.event(entry, eventsItems[i]);
|
||||
// }
|
||||
}
|
||||
void queueEvents(TrackEntry* entry, float animationTime);
|
||||
|
||||
/// Sets the active TrackEntry for a given track number.
|
||||
void setCurrent(int index, TrackEntry* current, bool interrupt)
|
||||
{
|
||||
// TrackEntry from = expandToIndex(index);
|
||||
// tracks.Items[index] = current;
|
||||
//
|
||||
// if (from != NULL) {
|
||||
// if (interrupt) queue.interrupt(from);
|
||||
// current.mixingFrom = from;
|
||||
// current.mixTime = 0;
|
||||
//
|
||||
// // Store interrupted mix percentage.
|
||||
// if (from.mixingFrom != NULL && from.mixDuration > 0)
|
||||
// current.interruptAlpha *= Math.Min(1, from.mixTime / from.mixDuration);
|
||||
//
|
||||
// from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
|
||||
// }
|
||||
//
|
||||
// queue.start(current); // triggers animationsChanged
|
||||
}
|
||||
void setCurrent(int index, TrackEntry* current, bool interrupt);
|
||||
|
||||
TrackEntry* expandToIndex(int index)
|
||||
{
|
||||
// if (index < tracks.Count) return tracks.Items[index];
|
||||
// while (index >= tracks.Count)
|
||||
// {
|
||||
// tracks.Add(NULL);
|
||||
// }
|
||||
return NULL;
|
||||
}
|
||||
TrackEntry* expandToIndex(int index);
|
||||
|
||||
/// Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values.
|
||||
/// @param last May be NULL.
|
||||
TrackEntry* newTrackEntry(int trackIndex, Animation* animation, bool loop, TrackEntry* last)
|
||||
{
|
||||
// TrackEntry entry = trackEntryPool.Obtain(); // Pooling
|
||||
// entry.trackIndex = trackIndex;
|
||||
// entry.animation = animation;
|
||||
// entry.loop = loop;
|
||||
//
|
||||
// entry.eventThreshold = 0;
|
||||
// entry.attachmentThreshold = 0;
|
||||
// entry.drawOrderThreshold = 0;
|
||||
//
|
||||
// entry.animationStart = 0;
|
||||
// entry.animationEnd = animation.Duration;
|
||||
// entry.animationLast = -1;
|
||||
// entry.nextAnimationLast = -1;
|
||||
//
|
||||
// entry.delay = 0;
|
||||
// entry.trackTime = 0;
|
||||
// entry.trackLast = -1;
|
||||
// entry.nextTrackLast = -1; // nextTrackLast == -1 signifies a TrackEntry that wasn't applied yet.
|
||||
// entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration;
|
||||
// entry.timeScale = 1;
|
||||
//
|
||||
// entry.alpha = 1;
|
||||
// entry.interruptAlpha = 1;
|
||||
// entry.mixTime = 0;
|
||||
// entry.mixDuration = (last == NULL) ? 0 : data.GetMix(last.animation, animation);
|
||||
// return entry;
|
||||
return NULL;
|
||||
}
|
||||
TrackEntry* newTrackEntry(int trackIndex, Animation* animation, bool loop, TrackEntry* last);
|
||||
|
||||
/// Dispose all track entries queued after the given TrackEntry.
|
||||
void disposeNext(TrackEntry* entry)
|
||||
{
|
||||
// TrackEntry next = entry.next;
|
||||
// while (next != NULL)
|
||||
// {
|
||||
// queue.dispose(next);
|
||||
// next = next.next;
|
||||
// }
|
||||
// entry.next = NULL;
|
||||
}
|
||||
void disposeNext(TrackEntry* entry);
|
||||
|
||||
void animationsChanged()
|
||||
{
|
||||
// animationsChanged = false;
|
||||
//
|
||||
// var propertyIDs = _propertyIDs;
|
||||
// propertyIDs.clear();
|
||||
// var mixingTo = _mixingTo;
|
||||
//
|
||||
// var tracksItems = tracks.Items;
|
||||
// for (int i = 0, n = tracks.Count; i < n; i++)
|
||||
// {
|
||||
// var entry = tracksItems[i];
|
||||
// if (entry != NULL)
|
||||
// {
|
||||
// entry.setTimelineData(NULL, mixingTo, propertyIDs);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
void animationsChanged();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@ namespace Spine
|
||||
/// Stores mix (crossfade) durations to be applied when AnimationState animations are changed.
|
||||
class AnimationStateData
|
||||
{
|
||||
friend class AnimationState;
|
||||
|
||||
public:
|
||||
/// The SkeletonData to look up animations when they are specified by name.
|
||||
SkeletonData& getSkeletonData();
|
||||
|
||||
@ -51,7 +51,7 @@ namespace Spine
|
||||
public:
|
||||
AttachmentTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -49,6 +49,8 @@ namespace Spine
|
||||
{
|
||||
RTTI_DECL;
|
||||
|
||||
friend class AnimationState;
|
||||
|
||||
friend class RotateTimeline;
|
||||
friend class IkConstraint;
|
||||
friend class TransformConstraint;
|
||||
|
||||
@ -39,6 +39,8 @@ namespace Spine
|
||||
{
|
||||
class BoneData
|
||||
{
|
||||
friend class AnimationState;
|
||||
|
||||
friend class RotateTimeline;
|
||||
friend class ScaleTimeline;
|
||||
friend class ShearTimeline;
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
|
||||
ColorTimeline (int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ namespace Spine
|
||||
public:
|
||||
CurveTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction) = 0;
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction) = 0;
|
||||
|
||||
virtual int getPropertyId() = 0;
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
public:
|
||||
DeformTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Spine
|
||||
public:
|
||||
DrawOrderTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -40,6 +40,8 @@ namespace Spine
|
||||
/// Stores the current pose values for an Event.
|
||||
class Event
|
||||
{
|
||||
friend class AnimationState;
|
||||
|
||||
public:
|
||||
Event(float time, const EventData& data);
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Spine
|
||||
public:
|
||||
EventTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
|
||||
IkConstraintTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -50,6 +50,12 @@
|
||||
|
||||
namespace Spine
|
||||
{
|
||||
template <typename T>
|
||||
int sign(T val)
|
||||
{
|
||||
return (T(0) < val) - (val < T(0));
|
||||
}
|
||||
|
||||
inline bool areFloatsPracticallyEqual(float A, float B, float maxDiff = 0.0000000000000001f, float maxRelDiff = FLT_EPSILON)
|
||||
{
|
||||
// Check if the numbers are really close -- needed
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
|
||||
PathConstraintMixTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
|
||||
PathConstraintPositionTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Spine
|
||||
public:
|
||||
PathConstraintSpacingTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
};
|
||||
|
||||
@ -37,6 +37,8 @@ namespace Spine
|
||||
{
|
||||
class RotateTimeline : public CurveTimeline
|
||||
{
|
||||
friend class AnimationState;
|
||||
|
||||
RTTI_DECL;
|
||||
|
||||
public:
|
||||
@ -44,7 +46,7 @@ namespace Spine
|
||||
|
||||
RotateTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Spine
|
||||
public:
|
||||
ScaleTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
};
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Spine
|
||||
public:
|
||||
ShearTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
};
|
||||
|
||||
@ -51,6 +51,7 @@ namespace Spine
|
||||
|
||||
class Skeleton
|
||||
{
|
||||
friend class AnimationState;
|
||||
friend class SkeletonBounds;
|
||||
friend class SkeletonClipping;
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ namespace Spine
|
||||
/// apply animations on top of each other (layered).
|
||||
/// @param pose Controls how mixing is applied when alpha is than 1.
|
||||
/// @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions such as DrawOrderTimeline and AttachmentTimeline.
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction) = 0;
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction) = 0;
|
||||
|
||||
virtual int getPropertyId() = 0;
|
||||
};
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
|
||||
TransformConstraintTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ namespace Spine
|
||||
|
||||
TranslateTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine
|
||||
|
||||
TwoColorTimeline(int frameCount);
|
||||
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
|
||||
virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
|
||||
virtual int getPropertyId();
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ namespace Spine
|
||||
assert(_name.length() > 0);
|
||||
}
|
||||
|
||||
void Animation::apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void Animation::apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
if (loop && _duration != 0)
|
||||
{
|
||||
@ -60,7 +60,7 @@ namespace Spine
|
||||
|
||||
for (int i = 0, n = static_cast<int>(_timelines.size()); i < n; ++i)
|
||||
{
|
||||
_timelines[i]->apply(skeleton, lastTime, time, events, alpha, pose, direction);
|
||||
_timelines[i]->apply(skeleton, lastTime, time, pEvents, alpha, pose, direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,11 @@
|
||||
#include <spine/RotateTimeline.h>
|
||||
|
||||
#include <spine/Timeline.h>
|
||||
#include <spine/SkeletonData.h>
|
||||
#include <spine/Bone.h>
|
||||
#include <spine/BoneData.h>
|
||||
#include <spine/AttachmentTimeline.h>
|
||||
#include <spine/DrawOrderTimeline.h>
|
||||
|
||||
#include <spine/MathUtil.h>
|
||||
#include <spine/ContainerUtil.h>
|
||||
@ -325,6 +330,7 @@ namespace Spine
|
||||
case EventType_Dispose:
|
||||
trackEntry->_onAnimationEventFunc(state, EventType_Dispose, trackEntry, NULL);
|
||||
state._onAnimationEventFunc(state, EventType_Dispose, trackEntry, NULL);
|
||||
trackEntry->reset();
|
||||
_trackEntryPool.free(trackEntry);
|
||||
break;
|
||||
case EventType_Event:
|
||||
@ -357,15 +363,748 @@ namespace Spine
|
||||
DESTROY(EventQueue, _queue);
|
||||
}
|
||||
|
||||
void AnimationState::update(float delta)
|
||||
{
|
||||
delta *= _timeScale;
|
||||
for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
|
||||
{
|
||||
TrackEntry* currentP = _tracks[i];
|
||||
if (currentP == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TrackEntry& current = *currentP;
|
||||
|
||||
current._animationLast = current._nextAnimationLast;
|
||||
current._trackLast = current._nextTrackLast;
|
||||
|
||||
float currentDelta = delta * current._timeScale;
|
||||
|
||||
if (current._delay > 0)
|
||||
{
|
||||
current._delay -= currentDelta;
|
||||
if (current._delay > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
currentDelta = -current._delay;
|
||||
current._delay = 0;
|
||||
}
|
||||
|
||||
TrackEntry* next = current._next;
|
||||
if (next != NULL)
|
||||
{
|
||||
// When the next entry's delay is passed, change to the next entry, preserving leftover time.
|
||||
float nextTime = current._trackLast - next->_delay;
|
||||
if (nextTime >= 0)
|
||||
{
|
||||
next->_delay = 0;
|
||||
next->_trackTime = nextTime + (delta * next->_timeScale);
|
||||
current._trackTime += currentDelta;
|
||||
setCurrent(i, next, true);
|
||||
while (next->_mixingFrom != NULL)
|
||||
{
|
||||
next->_mixTime += currentDelta;
|
||||
next = next->_mixingFrom;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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.
|
||||
_tracks[i] = NULL;
|
||||
|
||||
_queue->end(currentP);
|
||||
disposeNext(currentP);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current._mixingFrom != NULL && updateMixingFrom(currentP, delta))
|
||||
{
|
||||
// End mixing from entries once all have completed.
|
||||
TrackEntry* from = current._mixingFrom;
|
||||
current._mixingFrom = NULL;
|
||||
while (from != NULL)
|
||||
{
|
||||
_queue->end(from);
|
||||
from = from->_mixingFrom;
|
||||
}
|
||||
}
|
||||
|
||||
current._trackTime += currentDelta;
|
||||
}
|
||||
|
||||
_queue->drain();
|
||||
}
|
||||
|
||||
bool AnimationState::apply(Skeleton& skeleton)
|
||||
{
|
||||
if (_animationsChanged)
|
||||
{
|
||||
animationsChanged();
|
||||
}
|
||||
|
||||
bool applied = false;
|
||||
for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
|
||||
{
|
||||
TrackEntry* currentP = _tracks[i];
|
||||
if (currentP == NULL || currentP->_delay > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TrackEntry& current = *currentP;
|
||||
|
||||
applied = true;
|
||||
MixPose currentPose = i == 0 ? MixPose_Current : MixPose_CurrentLayered;
|
||||
|
||||
// apply mixing from entries first.
|
||||
float mix = current._alpha;
|
||||
if (current._mixingFrom != NULL)
|
||||
{
|
||||
mix *= applyMixingFrom(currentP, skeleton, currentPose);
|
||||
}
|
||||
else if (current._trackTime >= current._trackEnd && current._next == NULL) //
|
||||
{
|
||||
mix = 0; // Set to setup pose the last time the entry will be applied.
|
||||
}
|
||||
|
||||
// apply current entry.
|
||||
float animationLast = current._animationLast, animationTime = current.getAnimationTime();
|
||||
int timelineCount = static_cast<int>(current._animation->_timelines.size());
|
||||
Vector<Timeline*>& timelines = current._animation->_timelines;
|
||||
if (mix == 1)
|
||||
{
|
||||
for (int ii = 0; ii < timelineCount; ++ii)
|
||||
{
|
||||
timelines[ii]->apply(skeleton, animationLast, animationTime, &_events, 1, MixPose_Setup, MixDirection_In);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector<int>& timelineData = current._timelineData;
|
||||
|
||||
bool firstFrame = current._timelinesRotation.size() == 0;
|
||||
if (firstFrame)
|
||||
{
|
||||
current._timelinesRotation.reserve(timelines.size() << 1);
|
||||
}
|
||||
Vector<float>& timelinesRotation = current._timelinesRotation;
|
||||
|
||||
for (int ii = 0; ii < timelineCount; ++ii)
|
||||
{
|
||||
Timeline* timeline = timelines[ii];
|
||||
assert(timeline);
|
||||
|
||||
MixPose pose = timelineData[ii] >= AnimationState::First ? MixPose_Setup : currentPose;
|
||||
|
||||
RotateTimeline* rotateTimeline = NULL;
|
||||
if (timeline->getRTTI().derivesFrom(RotateTimeline::rtti))
|
||||
{
|
||||
rotateTimeline = static_cast<RotateTimeline*>(timeline);
|
||||
}
|
||||
|
||||
if (rotateTimeline != NULL)
|
||||
{
|
||||
applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeline->apply(skeleton, animationLast, animationTime, &_events, mix, pose, MixDirection_In);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queueEvents(currentP, animationTime);
|
||||
_events.clear();
|
||||
current._nextAnimationLast = animationTime;
|
||||
current._nextTrackLast = current._trackTime;
|
||||
}
|
||||
|
||||
_queue->drain();
|
||||
return applied;
|
||||
}
|
||||
|
||||
void AnimationState::clearTracks()
|
||||
{
|
||||
bool oldDrainDisabled = _queue->_drainDisabled;
|
||||
_queue->_drainDisabled = true;
|
||||
for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
|
||||
{
|
||||
clearTrack(i);
|
||||
}
|
||||
_tracks.clear();
|
||||
_queue->_drainDisabled = oldDrainDisabled;
|
||||
_queue->drain();
|
||||
}
|
||||
|
||||
void AnimationState::clearTrack(int trackIndex)
|
||||
{
|
||||
if (trackIndex >= _tracks.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TrackEntry* current = _tracks[trackIndex];
|
||||
if (current == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_queue->end(current);
|
||||
|
||||
disposeNext(current);
|
||||
|
||||
TrackEntry* entry = current;
|
||||
while (true)
|
||||
{
|
||||
TrackEntry* from = entry->_mixingFrom;
|
||||
if (from == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_queue->end(from);
|
||||
entry->_mixingFrom = NULL;
|
||||
entry = from;
|
||||
}
|
||||
|
||||
_tracks[current->_trackIndex] = NULL;
|
||||
|
||||
_queue->drain();
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::setAnimation(int trackIndex, std::string animationName, bool loop)
|
||||
{
|
||||
Animation* animation = _data._skeletonData.findAnimation(animationName);
|
||||
assert(animation != NULL);
|
||||
|
||||
return setAnimation(trackIndex, animation, loop);
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::setAnimation(int trackIndex, Animation* animation, bool loop)
|
||||
{
|
||||
assert(animation != NULL);
|
||||
|
||||
bool interrupt = true;
|
||||
TrackEntry* current = expandToIndex(trackIndex);
|
||||
if (current != NULL)
|
||||
{
|
||||
if (current->_nextTrackLast == -1)
|
||||
{
|
||||
// Don't mix from an entry that was never applied.
|
||||
_tracks[trackIndex] = current->_mixingFrom;
|
||||
_queue->interrupt(current);
|
||||
_queue->end(current);
|
||||
disposeNext(current);
|
||||
current = current->_mixingFrom;
|
||||
interrupt = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
disposeNext(current);
|
||||
}
|
||||
}
|
||||
|
||||
TrackEntry* entry = newTrackEntry(trackIndex, animation, loop, current);
|
||||
setCurrent(trackIndex, entry, interrupt);
|
||||
_queue->drain();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::addAnimation(int trackIndex, std::string animationName, bool loop, float delay)
|
||||
{
|
||||
Animation* animation = _data._skeletonData.findAnimation(animationName);
|
||||
assert(animation != NULL);
|
||||
|
||||
return addAnimation(trackIndex, animation, loop, delay);
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::addAnimation(int trackIndex, Animation* animation, bool loop, float delay)
|
||||
{
|
||||
assert(animation != NULL);
|
||||
|
||||
TrackEntry* last = expandToIndex(trackIndex);
|
||||
if (last != NULL)
|
||||
{
|
||||
while (last->_next != NULL)
|
||||
{
|
||||
last = last->_next;
|
||||
}
|
||||
}
|
||||
|
||||
TrackEntry* entry = newTrackEntry(trackIndex, animation, loop, last);
|
||||
|
||||
if (last == NULL)
|
||||
{
|
||||
setCurrent(trackIndex, entry, true);
|
||||
_queue->drain();
|
||||
}
|
||||
else
|
||||
{
|
||||
last->_next = entry;
|
||||
if (delay <= 0)
|
||||
{
|
||||
float duration = last->_animationEnd - last->_animationStart;
|
||||
if (duration != 0)
|
||||
{
|
||||
delay += duration * (1 + (int)(last->_trackTime / duration)) - _data.getMix(last->_animation, animation);
|
||||
}
|
||||
else
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry->_delay = delay;
|
||||
return entry;
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::setEmptyAnimation(int trackIndex, float mixDuration)
|
||||
{
|
||||
TrackEntry* entry = setAnimation(trackIndex, AnimationState::getEmptyAnimation(), false);
|
||||
entry->_mixDuration = mixDuration;
|
||||
entry->_trackEnd = mixDuration;
|
||||
return entry;
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::addEmptyAnimation(int trackIndex, float mixDuration, float delay)
|
||||
{
|
||||
if (delay <= 0)
|
||||
{
|
||||
delay -= mixDuration;
|
||||
}
|
||||
|
||||
TrackEntry* entry = addAnimation(trackIndex, AnimationState::getEmptyAnimation(), false, delay);
|
||||
entry->_mixDuration = mixDuration;
|
||||
entry->_trackEnd = mixDuration;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void AnimationState::setEmptyAnimations(float mixDuration)
|
||||
{
|
||||
bool oldDrainDisabled = _queue->_drainDisabled;
|
||||
_queue->_drainDisabled = true;
|
||||
for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
|
||||
{
|
||||
TrackEntry* current = _tracks[i];
|
||||
if (current != NULL)
|
||||
{
|
||||
setEmptyAnimation(i, mixDuration);
|
||||
}
|
||||
}
|
||||
_queue->_drainDisabled = oldDrainDisabled;
|
||||
_queue->drain();
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::getCurrent(int trackIndex)
|
||||
{
|
||||
return trackIndex >= _tracks.size() ? NULL : _tracks[trackIndex];
|
||||
}
|
||||
|
||||
AnimationStateData& AnimationState::getData()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
Vector<TrackEntry*> AnimationState::getTracks()
|
||||
{
|
||||
return _tracks;
|
||||
}
|
||||
|
||||
float AnimationState::getTimeScale()
|
||||
{
|
||||
return _timeScale;
|
||||
}
|
||||
|
||||
void AnimationState::setTimeScale(float inValue)
|
||||
{
|
||||
_timeScale = inValue;
|
||||
}
|
||||
|
||||
void AnimationState::setOnAnimationEventFunc(OnAnimationEventFunc inValue)
|
||||
{
|
||||
_onAnimationEventFunc = inValue;
|
||||
}
|
||||
|
||||
Animation& AnimationState::getEmptyAnimation()
|
||||
Animation* AnimationState::getEmptyAnimation()
|
||||
{
|
||||
static Vector<Timeline*> timelines;
|
||||
static Animation ret(std::string("<empty>"), timelines, 0);
|
||||
return ret;
|
||||
return &ret;
|
||||
}
|
||||
|
||||
void AnimationState::applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose, Vector<float>& timelinesRotation, int i, bool firstFrame)
|
||||
{
|
||||
if (firstFrame)
|
||||
{
|
||||
timelinesRotation[i] = 0;
|
||||
}
|
||||
|
||||
if (alpha == 1)
|
||||
{
|
||||
rotateTimeline->apply(skeleton, 0, time, NULL, 1, pose, MixDirection_In);
|
||||
return;
|
||||
}
|
||||
|
||||
Bone* bone = skeleton._bones[rotateTimeline->_boneIndex];
|
||||
Vector<float> frames = rotateTimeline->_frames;
|
||||
if (time < frames[0])
|
||||
{
|
||||
if (pose == MixPose_Setup)
|
||||
{
|
||||
bone->_rotation = bone->_data._rotation;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float r2;
|
||||
if (time >= frames[frames.size() - RotateTimeline::ENTRIES]) // Time is after last frame.
|
||||
{
|
||||
r2 = bone->_data._rotation + frames[frames.size() + RotateTimeline::PREV_ROTATION];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
int frame = Animation::binarySearch(frames, time, RotateTimeline::ENTRIES);
|
||||
float prevRotation = frames[frame + RotateTimeline::PREV_ROTATION];
|
||||
float frameTime = frames[frame];
|
||||
float percent = rotateTimeline->getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline::PREV_TIME] - frameTime));
|
||||
|
||||
r2 = frames[frame + RotateTimeline::ROTATION] - prevRotation;
|
||||
r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
||||
r2 = prevRotation + r2 * percent + bone->_data._rotation;
|
||||
r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
||||
}
|
||||
|
||||
// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
||||
float r1 = pose == MixPose_Setup ? bone->_data._rotation : bone->_rotation;
|
||||
float total, diff = r2 - r1;
|
||||
if (diff == 0)
|
||||
{
|
||||
total = timelinesRotation[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
diff -= (16384 - (int)(16384.499999999996 - diff / 360)) * 360;
|
||||
float lastTotal, lastDiff;
|
||||
if (firstFrame)
|
||||
{
|
||||
lastTotal = 0;
|
||||
lastDiff = diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.
|
||||
lastDiff = timelinesRotation[i + 1]; // Difference between bones.
|
||||
}
|
||||
|
||||
bool current = diff > 0, dir = lastTotal >= 0;
|
||||
// Detect cross at 0 (not 180).
|
||||
if (sign(lastDiff) != sign(diff) && abs(lastDiff) <= 90)
|
||||
{
|
||||
// A cross after a 360 rotation is a loop.
|
||||
if (abs(lastTotal) > 180)
|
||||
{
|
||||
lastTotal += 360 * sign(lastTotal);
|
||||
}
|
||||
dir = current;
|
||||
}
|
||||
|
||||
total = diff + lastTotal - fmod(lastTotal, 360); // Store loops as part of lastTotal.
|
||||
if (dir != current)
|
||||
{
|
||||
total += 360 * sign(lastTotal);
|
||||
}
|
||||
timelinesRotation[i] = total;
|
||||
}
|
||||
timelinesRotation[i + 1] = diff;
|
||||
r1 += total * alpha;
|
||||
bone->_rotation = r1 - (16384 - (int)(16384.499999999996 - r1 / 360)) * 360;
|
||||
}
|
||||
|
||||
bool AnimationState::updateMixingFrom(TrackEntry* to, float delta)
|
||||
{
|
||||
TrackEntry* from = to->_mixingFrom;
|
||||
if (from == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool finished = updateMixingFrom(from, delta);
|
||||
|
||||
// Require mixTime > 0 to ensure the mixing from entry was applied at least once.
|
||||
if (to->_mixTime > 0 && (to->_mixTime >= to->_mixDuration || to->_timeScale == 0))
|
||||
{
|
||||
// Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
|
||||
if (from->_totalAlpha == 0 || to->_mixDuration == 0)
|
||||
{
|
||||
to->_mixingFrom = from->_mixingFrom;
|
||||
to->_interruptAlpha = from->_interruptAlpha;
|
||||
_queue->end(from);
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
from->_animationLast = from->_nextAnimationLast;
|
||||
from->_trackLast = from->_nextTrackLast;
|
||||
from->_trackTime += delta * from->_timeScale;
|
||||
to->_mixTime += delta * to->_timeScale;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float AnimationState::applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose)
|
||||
{
|
||||
TrackEntry* from = to->_mixingFrom;
|
||||
if (from->_mixingFrom != NULL)
|
||||
{
|
||||
applyMixingFrom(from, skeleton, currentPose);
|
||||
}
|
||||
|
||||
float mix;
|
||||
if (to->_mixDuration == 0)
|
||||
{
|
||||
// Single frame mix to undo mixingFrom changes.
|
||||
mix = 1;
|
||||
currentPose = MixPose_Setup;
|
||||
}
|
||||
else
|
||||
{
|
||||
mix = to->_mixTime / to->_mixDuration;
|
||||
if (mix > 1)
|
||||
{
|
||||
mix = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Event*>* eventBuffer = mix < from->_eventThreshold ? &_events : NULL;
|
||||
bool attachments = mix < from->_attachmentThreshold, drawOrder = mix < from->_drawOrderThreshold;
|
||||
float animationLast = from->_animationLast, animationTime = from->getAnimationTime();
|
||||
Vector<Timeline*>& timelines = from->_animation->_timelines;
|
||||
int timelineCount = static_cast<int>(timelines.size());
|
||||
Vector<int>& timelineData = from->_timelineData;
|
||||
Vector<TrackEntry*>& timelineDipMix = from->_timelineDipMix;
|
||||
|
||||
bool firstFrame = from->_timelinesRotation.size() == 0;
|
||||
if (firstFrame)
|
||||
{
|
||||
// from.timelinesRotation.setSize
|
||||
from->_timelinesRotation.reserve(timelines.size() << 1);
|
||||
}
|
||||
|
||||
Vector<float>& timelinesRotation = from->_timelinesRotation;
|
||||
|
||||
MixPose pose;
|
||||
float alphaDip = from->_alpha * to->_interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
|
||||
from->_totalAlpha = 0;
|
||||
for (int i = 0; i < timelineCount; ++i)
|
||||
{
|
||||
Timeline* timeline = timelines[i];
|
||||
switch (timelineData[i])
|
||||
{
|
||||
case Subsequent:
|
||||
if (!attachments && timeline->getRTTI().derivesFrom(AttachmentTimeline::rtti))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!drawOrder && timeline->getRTTI().derivesFrom(DrawOrderTimeline::rtti))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pose = currentPose;
|
||||
alpha = alphaMix;
|
||||
break;
|
||||
case First:
|
||||
pose = MixPose_Setup;
|
||||
alpha = alphaMix;
|
||||
break;
|
||||
case Dip:
|
||||
pose = MixPose_Setup;
|
||||
alpha = alphaDip;
|
||||
break;
|
||||
default:
|
||||
pose = MixPose_Setup;
|
||||
TrackEntry* dipMix = timelineDipMix[i];
|
||||
alpha = alphaDip * MAX(0, 1 - dipMix->_mixTime / dipMix->_mixDuration);
|
||||
break;
|
||||
}
|
||||
from->_totalAlpha += alpha;
|
||||
|
||||
RotateTimeline* rotateTimeline = NULL;
|
||||
if (timeline->getRTTI().derivesFrom(RotateTimeline::rtti))
|
||||
{
|
||||
rotateTimeline = static_cast<RotateTimeline*>(timeline);
|
||||
}
|
||||
|
||||
if (rotateTimeline != NULL)
|
||||
{
|
||||
applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeline->apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection_Out);
|
||||
}
|
||||
}
|
||||
|
||||
if (to->_mixDuration > 0)
|
||||
{
|
||||
queueEvents(from, animationTime);
|
||||
}
|
||||
|
||||
_events.clear();
|
||||
from->_nextAnimationLast = animationTime;
|
||||
from->_nextTrackLast = from->_trackTime;
|
||||
|
||||
return mix;
|
||||
}
|
||||
|
||||
void AnimationState::queueEvents(TrackEntry* entry, float animationTime)
|
||||
{
|
||||
float animationStart = entry->_animationStart, animationEnd = entry->_animationEnd;
|
||||
float duration = animationEnd - animationStart;
|
||||
float trackLastWrapped = fmodf(entry->_trackLast, duration);
|
||||
|
||||
// Queue events before complete.
|
||||
int i = 0, n = static_cast<int>(_events.size());
|
||||
for (; i < n; ++i)
|
||||
{
|
||||
Event* e = _events[i];
|
||||
if (e->_time < trackLastWrapped)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (e->_time > animationEnd)
|
||||
{
|
||||
// Discard events outside animation start/end.
|
||||
continue;
|
||||
}
|
||||
_queue->event(entry, e);
|
||||
}
|
||||
|
||||
// Queue complete if completed a loop iteration or the animation.
|
||||
if (entry->_loop ? (trackLastWrapped > fmod(entry->_trackTime, duration)) : (animationTime >= animationEnd && entry->_animationLast < animationEnd))
|
||||
{
|
||||
_queue->complete(entry);
|
||||
}
|
||||
|
||||
// Queue events after complete.
|
||||
for (; i < n; ++i)
|
||||
{
|
||||
Event* e = _events[i];
|
||||
if (e->_time < animationStart)
|
||||
{
|
||||
// Discard events outside animation start/end.
|
||||
continue;
|
||||
}
|
||||
_queue->event(entry, _events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationState::setCurrent(int index, TrackEntry* current, bool interrupt)
|
||||
{
|
||||
TrackEntry* from = expandToIndex(index);
|
||||
_tracks[index] = current;
|
||||
|
||||
if (from != NULL)
|
||||
{
|
||||
if (interrupt)
|
||||
{
|
||||
_queue->interrupt(from);
|
||||
}
|
||||
|
||||
current->_mixingFrom = from;
|
||||
current->_mixTime = 0;
|
||||
|
||||
// Store interrupted mix percentage.
|
||||
if (from->_mixingFrom != NULL && from->_mixDuration > 0)
|
||||
{
|
||||
current->_interruptAlpha *= MIN(1, from->_mixTime / from->_mixDuration);
|
||||
}
|
||||
|
||||
from->_timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
|
||||
}
|
||||
|
||||
_queue->start(current); // triggers animationsChanged
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::expandToIndex(int index)
|
||||
{
|
||||
if (index < _tracks.size())
|
||||
{
|
||||
return _tracks[index];
|
||||
}
|
||||
|
||||
while (index >= _tracks.size())
|
||||
{
|
||||
_tracks.push_back(NULL);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TrackEntry* AnimationState::newTrackEntry(int trackIndex, Animation* animation, bool loop, TrackEntry* last)
|
||||
{
|
||||
TrackEntry* entryP = _trackEntryPool.obtain(); // Pooling
|
||||
TrackEntry& entry = *entryP;
|
||||
|
||||
entry._trackIndex = trackIndex;
|
||||
entry._animation = animation;
|
||||
entry._loop = loop;
|
||||
|
||||
entry._eventThreshold = 0;
|
||||
entry._attachmentThreshold = 0;
|
||||
entry._drawOrderThreshold = 0;
|
||||
|
||||
entry._animationStart = 0;
|
||||
entry._animationEnd = animation->getDuration();
|
||||
entry._animationLast = -1;
|
||||
entry._nextAnimationLast = -1;
|
||||
|
||||
entry._delay = 0;
|
||||
entry._trackTime = 0;
|
||||
entry._trackLast = -1;
|
||||
entry._nextTrackLast = -1; // nextTrackLast == -1 signifies a TrackEntry that wasn't applied yet.
|
||||
entry._trackEnd = std::numeric_limits<float>::max(); // loop ? float.MaxValue : animation.Duration;
|
||||
entry._timeScale = 1;
|
||||
|
||||
entry._alpha = 1;
|
||||
entry._interruptAlpha = 1;
|
||||
entry._mixTime = 0;
|
||||
entry._mixDuration = (last == NULL) ? 0 : _data.getMix(last->_animation, animation);
|
||||
|
||||
return entryP;
|
||||
}
|
||||
|
||||
void AnimationState::disposeNext(TrackEntry* entry)
|
||||
{
|
||||
TrackEntry* next = entry->_next;
|
||||
while (next != NULL)
|
||||
{
|
||||
_queue->dispose(next);
|
||||
next = next->_next;
|
||||
}
|
||||
entry->_next = NULL;
|
||||
}
|
||||
|
||||
void AnimationState::animationsChanged()
|
||||
{
|
||||
_animationsChanged = false;
|
||||
|
||||
_propertyIDs.clear();
|
||||
|
||||
for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
|
||||
{
|
||||
TrackEntry* entry = _tracks[i];
|
||||
if (entry != NULL)
|
||||
{
|
||||
entry->setTimelineData(NULL, _mixingTo, _propertyIDs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ namespace Spine
|
||||
_attachmentNames.reserve(frameCount);
|
||||
}
|
||||
|
||||
void AttachmentTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void AttachmentTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
assert(_slotIndex < skeleton._slots.size());
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void ColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void ColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Slot* slotP = skeleton._slots[_slotIndex];
|
||||
Slot& slot = *slotP;
|
||||
|
||||
@ -50,7 +50,7 @@ namespace Spine
|
||||
_frameVertices.reserve(frameCount);
|
||||
}
|
||||
|
||||
void DeformTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void DeformTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Slot* slotP = skeleton._slots[_slotIndex];
|
||||
Slot& slot = *slotP;
|
||||
|
||||
@ -48,7 +48,7 @@ namespace Spine
|
||||
_drawOrders.reserve(frameCount);
|
||||
}
|
||||
|
||||
void DrawOrderTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void DrawOrderTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Vector<Slot*>& drawOrder = skeleton._drawOrder;
|
||||
Vector<Slot*>& slots = skeleton._slots;
|
||||
|
||||
@ -49,8 +49,15 @@ namespace Spine
|
||||
_events.reserve(frameCount);
|
||||
}
|
||||
|
||||
void EventTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void EventTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
if (pEvents == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<Event*>& events = *pEvents;
|
||||
|
||||
if (events.size() == 0)
|
||||
{
|
||||
return;
|
||||
@ -61,7 +68,7 @@ namespace Spine
|
||||
if (lastTime > time)
|
||||
{
|
||||
// Fire events after last time for looped animations.
|
||||
apply(skeleton, lastTime, std::numeric_limits<int>::max(), events, alpha, pose, direction);
|
||||
apply(skeleton, lastTime, std::numeric_limits<int>::max(), pEvents, alpha, pose, direction);
|
||||
lastTime = -1.0f;
|
||||
}
|
||||
else if (lastTime >= _frames[frameCount - 1]) // Last time is after last frame.
|
||||
|
||||
@ -56,7 +56,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void IkConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void IkConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
IkConstraint* constraintP = skeleton._ikConstraints[_ikConstraintIndex];
|
||||
IkConstraint& constraint = *constraintP;
|
||||
|
||||
@ -56,7 +56,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void PathConstraintMixTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void PathConstraintMixTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
PathConstraint* constraintP = skeleton._pathConstraints[_pathConstraintIndex];
|
||||
PathConstraint& constraint = *constraintP;
|
||||
|
||||
@ -54,7 +54,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void PathConstraintPositionTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void PathConstraintPositionTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
PathConstraint* constraintP = skeleton._pathConstraints[_pathConstraintIndex];
|
||||
PathConstraint& constraint = *constraintP;
|
||||
|
||||
@ -49,7 +49,7 @@ namespace Spine
|
||||
// Empty
|
||||
}
|
||||
|
||||
void PathConstraintSpacingTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void PathConstraintSpacingTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
PathConstraint* constraintP = skeleton._pathConstraints[_pathConstraintIndex];
|
||||
PathConstraint& constraint = *constraintP;
|
||||
|
||||
@ -47,7 +47,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount << 1);
|
||||
}
|
||||
|
||||
void RotateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void RotateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Bone* bone = skeleton.getBones()[_boneIndex];
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ namespace Spine
|
||||
// Empty
|
||||
}
|
||||
|
||||
void ScaleTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void ScaleTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Bone* boneP = skeleton._bones[_boneIndex];
|
||||
Bone& bone = *boneP;
|
||||
|
||||
@ -49,7 +49,7 @@ namespace Spine
|
||||
// Empty
|
||||
}
|
||||
|
||||
void ShearTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void ShearTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Bone* boneP = skeleton._bones[_boneIndex];
|
||||
Bone& bone = *boneP;
|
||||
|
||||
@ -60,7 +60,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void TransformConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void TransformConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
TransformConstraint* constraintP = skeleton._transformConstraints[_transformConstraintIndex];
|
||||
TransformConstraint& constraint = *constraintP;
|
||||
|
||||
@ -56,7 +56,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void TranslateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void TranslateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Bone* boneP = skeleton._bones[_boneIndex];
|
||||
Bone& bone = *boneP;
|
||||
|
||||
@ -64,7 +64,7 @@ namespace Spine
|
||||
_frames.reserve(frameCount * ENTRIES);
|
||||
}
|
||||
|
||||
void TwoColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
|
||||
void TwoColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
|
||||
{
|
||||
Slot* slotP = skeleton._slots[_slotIndex];
|
||||
Slot& slot = *slotP;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user