AnimationState.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated January 1, 2020. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2020, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #ifndef Spine_AnimationState_h
  30. #define Spine_AnimationState_h
  31. #include <spine/Vector.h>
  32. #include <spine/Pool.h>
  33. #include <spine/MixBlend.h>
  34. #include <spine/SpineObject.h>
  35. #include <spine/SpineString.h>
  36. #include <spine/HasRendererObject.h>
  37. #ifdef SPINE_USE_STD_FUNCTION
  38. #include <functional>
  39. #endif
  40. namespace spine {
  41. enum EventType {
  42. EventType_Start,
  43. EventType_Interrupt,
  44. EventType_End,
  45. EventType_Complete,
  46. EventType_Dispose,
  47. EventType_Event
  48. };
  49. class AnimationState;
  50. class TrackEntry;
  51. class Animation;
  52. class Event;
  53. class AnimationStateData;
  54. class Skeleton;
  55. class RotateTimeline;
  56. #ifdef SPINE_USE_STD_FUNCTION
  57. typedef std::function<void (AnimationState* state, EventType type, TrackEntry* entry, Event* event)> AnimationStateListener;
  58. #else
  59. typedef void (*AnimationStateListener) (AnimationState* state, EventType type, TrackEntry* entry, Event* event);
  60. #endif
  61. /// Abstract class to inherit from to create a callback object
  62. class SP_API AnimationStateListenerObject {
  63. public:
  64. AnimationStateListenerObject() { };
  65. virtual ~AnimationStateListenerObject() { };
  66. public:
  67. /// The callback function to be called
  68. virtual void callback(AnimationState* state, EventType type, TrackEntry* entry, Event* event) = 0;
  69. };
  70. /// State for the playback of an animation
  71. class SP_API TrackEntry : public SpineObject, public HasRendererObject {
  72. friend class EventQueue;
  73. friend class AnimationState;
  74. public:
  75. TrackEntry();
  76. virtual ~TrackEntry();
  77. /// The index of the track where this entry is either current or queued.
  78. int getTrackIndex();
  79. /// The animation to apply for this track entry.
  80. Animation* getAnimation();
  81. /// If true, the animation will repeat. If false, it will not, instead its last frame is applied if played beyond its duration.
  82. bool getLoop();
  83. void setLoop(bool inValue);
  84. /// If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead
  85. /// of being mixed out.
  86. ///
  87. /// When mixing between animations that key the same property, if a lower track also keys that property then the value will
  88. /// briefly dip toward the lower track value during the mix. This happens because the first animation mixes from 100% to 0%
  89. /// while the second animation mixes from 0% to 100%. Setting holdPrevious to true applies the first animation
  90. /// at 100% during the mix so the lower track value is overwritten. Such dipping does not occur on the lowest track which
  91. /// keys the property, only when a higher track also keys the property.
  92. ///
  93. /// Snapping will occur if holdPrevious is true and this animation does not key all the same properties as the
  94. /// previous animation.
  95. bool getHoldPrevious();
  96. void setHoldPrevious(bool inValue);
  97. /// Seconds to postpone playing the animation. When a track entry is the current track entry, delay postpones incrementing
  98. /// the track time. When a track entry is queued, delay is the time from the start of the previous animation to when the
  99. /// track entry will become the current track entry.
  100. float getDelay();
  101. void setDelay(float inValue);
  102. /// Current time in seconds this track entry has been the current track entry. The track time determines
  103. /// TrackEntry.AnimationTime. The track time can be set to start the animation at a time other than 0, without affecting looping.
  104. float getTrackTime();
  105. void setTrackTime(float inValue);
  106. /// The track time in seconds when this animation will be removed from the track. Defaults to the animation duration for
  107. /// non-looping animations and to int.MaxValue for looping animations. If the track end time is reached and no
  108. /// other animations are queued for playback, and mixing from any previous animations is complete, properties keyed by the animation,
  109. /// are set to the setup pose and the track is cleared.
  110. ///
  111. /// It may be desired to use AnimationState.addEmptyAnimation(int, float, float) to mix the properties back to the
  112. /// setup pose over time, rather than have it happen instantly.
  113. float getTrackEnd();
  114. void setTrackEnd(float inValue);
  115. /// Seconds when this animation starts, both initially and after looping. Defaults to 0.
  116. ///
  117. /// When changing the animation start time, it often makes sense to set TrackEntry.AnimationLast to the same value to
  118. /// prevent timeline keys before the start time from triggering.
  119. float getAnimationStart();
  120. void setAnimationStart(float inValue);
  121. /// Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will
  122. /// loop back to TrackEntry.AnimationStart at this time. Defaults to the animation duration.
  123. float getAnimationEnd();
  124. void setAnimationEnd(float inValue);
  125. /// The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this
  126. /// animation is applied, event timelines will fire all events between the animation last time (exclusive) and animation time
  127. /// (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation is applied.
  128. float getAnimationLast();
  129. void setAnimationLast(float inValue);
  130. /// Uses TrackEntry.TrackTime to compute the animation time between TrackEntry.AnimationStart. and
  131. /// TrackEntry.AnimationEnd. When the track time is 0, the animation time is equal to the animation start time.
  132. float getAnimationTime();
  133. /// Multiplier for the delta time when the animation state is updated, causing time for this animation to play slower or
  134. /// faster. Defaults to 1.
  135. float getTimeScale();
  136. void setTimeScale(float inValue);
  137. /// Values less than 1 mix this animation with the last skeleton pose. Defaults to 1, which overwrites the last skeleton pose with
  138. /// this animation.
  139. ///
  140. /// Typically track 0 is used to completely pose the skeleton, then alpha can be used on higher tracks. It doesn't make sense
  141. /// to use alpha on track 0 if the skeleton pose is from the last frame render.
  142. float getAlpha();
  143. void setAlpha(float inValue);
  144. ///
  145. /// When the mix percentage (mix time / mix duration) is less than the event threshold, event timelines for the animation
  146. /// being mixed out will be applied. Defaults to 0, so event timelines are not applied for an animation being mixed out.
  147. float getEventThreshold();
  148. void setEventThreshold(float inValue);
  149. /// When the mix percentage (mix time / mix duration) is less than the attachment threshold, attachment timelines for the
  150. /// animation being mixed out will be applied. Defaults to 0, so attachment timelines are not applied for an animation being
  151. /// mixed out.
  152. float getAttachmentThreshold();
  153. void setAttachmentThreshold(float inValue);
  154. /// When the mix percentage (mix time / mix duration) is less than the draw order threshold, draw order timelines for the
  155. /// animation being mixed out will be applied. Defaults to 0, so draw order timelines are not applied for an animation being
  156. /// mixed out.
  157. float getDrawOrderThreshold();
  158. void setDrawOrderThreshold(float inValue);
  159. /// The animation queued to start after this animation, or NULL.
  160. TrackEntry* getNext();
  161. /// Returns true if at least one loop has been completed.
  162. bool isComplete();
  163. /// Seconds from 0 to the mix duration when mixing from the previous animation to this animation. May be slightly more than
  164. /// TrackEntry.MixDuration when the mix is complete.
  165. float getMixTime();
  166. void setMixTime(float inValue);
  167. /// Seconds for mixing from the previous animation to this animation. Defaults to the value provided by
  168. /// AnimationStateData based on the animation before this animation (if any).
  169. ///
  170. /// The mix duration can be set manually rather than use the value from AnimationStateData.GetMix.
  171. /// In that case, the mixDuration must be set before AnimationState.update(float) is next called.
  172. ///
  173. /// When using AnimationState::addAnimation(int, Animation, bool, float) with a delay
  174. /// less than or equal to 0, note the Delay is set using the mix duration from the AnimationStateData
  175. float getMixDuration();
  176. void setMixDuration(float inValue);
  177. MixBlend getMixBlend();
  178. void setMixBlend(MixBlend blend);
  179. /// The track entry for the previous animation when mixing from the previous animation to this animation, or NULL if no
  180. /// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a double linked list with MixingTo.
  181. TrackEntry* getMixingFrom();
  182. /// The track entry for the next animation when mixing from this animation, or NULL if no mixing is currently occuring.
  183. /// When mixing from multiple animations, MixingTo makes up a double linked list with MixingFrom.
  184. TrackEntry* getMixingTo();
  185. /// Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the
  186. /// long way around when using alpha and starting animations on other tracks.
  187. ///
  188. /// Mixing involves finding a rotation between two others, which has two possible solutions: the short way or the long way around.
  189. /// The two rotations likely change over time, so which direction is the short or long way also changes.
  190. /// If the short way was always chosen, bones would flip to the other side when that direction became the long way.
  191. /// TrackEntry chooses the short way the first time it is applied and remembers that direction.
  192. void resetRotationDirections();
  193. void setListener(AnimationStateListener listener);
  194. void setListener(AnimationStateListenerObject* listener);
  195. private:
  196. Animation* _animation;
  197. TrackEntry* _next;
  198. TrackEntry* _mixingFrom;
  199. TrackEntry* _mixingTo;
  200. int _trackIndex;
  201. bool _loop, _holdPrevious;
  202. float _eventThreshold, _attachmentThreshold, _drawOrderThreshold;
  203. float _animationStart, _animationEnd, _animationLast, _nextAnimationLast;
  204. float _delay, _trackTime, _trackLast, _nextTrackLast, _trackEnd, _timeScale;
  205. float _alpha, _mixTime, _mixDuration, _interruptAlpha, _totalAlpha;
  206. MixBlend _mixBlend;
  207. Vector<int> _timelineMode;
  208. Vector<TrackEntry*> _timelineHoldMix;
  209. Vector<float> _timelinesRotation;
  210. AnimationStateListener _listener;
  211. AnimationStateListenerObject* _listenerObject;
  212. void reset();
  213. };
  214. class SP_API EventQueueEntry : public SpineObject {
  215. friend class EventQueue;
  216. public:
  217. EventType _type;
  218. TrackEntry* _entry;
  219. Event* _event;
  220. EventQueueEntry(EventType eventType, TrackEntry* trackEntry, Event* event = NULL);
  221. };
  222. class SP_API EventQueue : public SpineObject {
  223. friend class AnimationState;
  224. private:
  225. Vector<EventQueueEntry> _eventQueueEntries;
  226. AnimationState& _state;
  227. Pool<TrackEntry>& _trackEntryPool;
  228. bool _drainDisabled;
  229. static EventQueue* newEventQueue(AnimationState& state, Pool<TrackEntry>& trackEntryPool);
  230. static EventQueueEntry newEventQueueEntry(EventType eventType, TrackEntry* entry, Event* event = NULL);
  231. EventQueue(AnimationState& state, Pool<TrackEntry>& trackEntryPool);
  232. ~EventQueue();
  233. void start(spine::TrackEntry* entry);
  234. void interrupt(spine::TrackEntry* entry);
  235. void end(spine::TrackEntry* entry);
  236. void dispose(spine::TrackEntry* entry);
  237. void complete(spine::TrackEntry* entry);
  238. void event(TrackEntry* entry, Event* event);
  239. /// Raises all events in the queue and drains the queue.
  240. void drain();
  241. };
  242. class SP_API AnimationState : public SpineObject, public HasRendererObject {
  243. friend class TrackEntry;
  244. friend class EventQueue;
  245. public:
  246. explicit AnimationState(AnimationStateData* data);
  247. ~AnimationState();
  248. /// Increments the track entry times, setting queued animations as current if needed
  249. /// @param delta delta time
  250. void update(float delta);
  251. /// Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the
  252. /// animation state can be applied to multiple skeletons to pose them identically.
  253. bool apply(Skeleton& skeleton);
  254. /// Removes all animations from all tracks, leaving skeletons in their previous pose.
  255. /// It may be desired to use AnimationState.setEmptyAnimations(float) to mix the skeletons back to the setup pose,
  256. /// rather than leaving them in their previous pose.
  257. void clearTracks();
  258. /// Removes all animations from the tracks, leaving skeletons in their previous pose.
  259. /// It may be desired to use AnimationState.setEmptyAnimations(float) to mix the skeletons back to the setup pose,
  260. /// rather than leaving them in their previous pose.
  261. void clearTrack(size_t trackIndex);
  262. /// Sets an animation by name. setAnimation(int, Animation, bool)
  263. TrackEntry* setAnimation(size_t trackIndex, const String& animationName, bool loop);
  264. /// Sets the current animation for a track, discarding any queued animations.
  265. /// @param loop If true, the animation will repeat.
  266. /// If false, it will not, instead its last frame is applied if played beyond its duration.
  267. /// In either case TrackEntry.TrackEnd determines when the track is cleared.
  268. /// @return
  269. /// A track entry to allow further customization of animation playback. References to the track entry must not be kept
  270. /// after AnimationState.Dispose.
  271. TrackEntry* setAnimation(size_t trackIndex, Animation* animation, bool loop);
  272. /// Queues an animation by name.
  273. /// addAnimation(int, Animation, bool, float)
  274. TrackEntry* addAnimation(size_t trackIndex, const String& animationName, bool loop, float delay);
  275. /// Adds an animation to be played delay seconds after the current or last queued animation
  276. /// for a track. If the track is empty, it is equivalent to calling setAnimation.
  277. /// @param delay
  278. /// Seconds to begin this animation after the start of the previous animation. May be &lt;= 0 to use the animation
  279. /// duration of the previous track minus any mix duration plus the negative delay.
  280. ///
  281. /// @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
  282. /// after AnimationState.Dispose
  283. TrackEntry* addAnimation(size_t trackIndex, Animation* animation, bool loop, float delay);
  284. /// Sets an empty animation for a track, discarding any queued animations, and mixes to it over the specified mix duration.
  285. TrackEntry* setEmptyAnimation(size_t trackIndex, float mixDuration);
  286. /// Adds an empty animation to be played after the current or last queued animation for a track, and mixes to it over the
  287. /// specified mix duration.
  288. /// @return
  289. /// A track entry to allow further customization of animation playback. References to the track entry must not be kept after AnimationState.Dispose.
  290. ///
  291. /// @param trackIndex Track number.
  292. /// @param mixDuration Mix duration.
  293. /// @param delay Seconds to begin this animation after the start of the previous animation. May be &lt;= 0 to use the animation
  294. /// duration of the previous track minus any mix duration plus the negative delay.
  295. TrackEntry* addEmptyAnimation(size_t trackIndex, float mixDuration, float delay);
  296. /// Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix duration.
  297. void setEmptyAnimations(float mixDuration);
  298. /// @return The track entry for the animation currently playing on the track, or NULL if no animation is currently playing.
  299. TrackEntry* getCurrent(size_t trackIndex);
  300. AnimationStateData* getData();
  301. /// A list of tracks that have animations, which may contain NULLs.
  302. Vector<TrackEntry*> &getTracks();
  303. float getTimeScale();
  304. void setTimeScale(float inValue);
  305. void setListener(AnimationStateListener listener);
  306. void setListener(AnimationStateListenerObject* listener);
  307. void disableQueue();
  308. void enableQueue();
  309. private:
  310. AnimationStateData* _data;
  311. Pool<TrackEntry> _trackEntryPool;
  312. Vector<TrackEntry*> _tracks;
  313. Vector<Event*> _events;
  314. EventQueue* _queue;
  315. HashMap<int, bool> _propertyIDs;
  316. bool _animationsChanged;
  317. AnimationStateListener _listener;
  318. AnimationStateListenerObject* _listenerObject;
  319. float _timeScale;
  320. static Animation* getEmptyAnimation();
  321. static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixBlend pose, Vector<float>& timelinesRotation, size_t i, bool firstFrame);
  322. /// Returns true when all mixing from entries are complete.
  323. bool updateMixingFrom(TrackEntry* to, float delta);
  324. float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixBlend currentPose);
  325. void queueEvents(TrackEntry* entry, float animationTime);
  326. /// Sets the active TrackEntry for a given track number.
  327. void setCurrent(size_t index, TrackEntry *current, bool interrupt);
  328. TrackEntry* expandToIndex(size_t index);
  329. /// Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values.
  330. /// @param last May be NULL.
  331. TrackEntry* newTrackEntry(size_t trackIndex, Animation *animation, bool loop, TrackEntry *last);
  332. /// Dispose all track entries queued after the given TrackEntry.
  333. void disposeNext(spine::TrackEntry* entry);
  334. void animationsChanged();
  335. void computeHold(TrackEntry *entry);
  336. void computeNotLast(TrackEntry *entry);
  337. };
  338. }
  339. #endif /* Spine_AnimationState_h */