diff --git a/CHANGELOG.md b/CHANGELOG.md index 816e47aa3..1e94e2bab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ - **Additions** - Added `spine_slider` and `spine_slider_data` types for slider constraints + - Regenerated C bindings for the AnimationState additive/hold rework and Skin placeholder name rename in spine-cpp. + +- **Breaking changes** + - `spine_track_entry_get_mix_blend()` / `spine_track_entry_set_mix_blend()` removed. Use `spine_track_entry_get_additive()` / `spine_track_entry_set_additive()` instead. + - `spine_track_entry_get_hold_previous()` / `spine_track_entry_set_hold_previous()` removed. + - `spine_skin_entry_get_name()` renamed to `spine_skin_entry_get_placeholder_name()`. + - Timeline `apply()` signature changed: `spine_mix_blend` and `spine_mix_direction` parameters replaced with `bool fromSetup, bool add, bool out`. + - `spine_animation_apply()` signature changed to match. + - `spine_curve_timeline1_get_absolute_value()`, `spine_curve_timeline1_get_relative_value()`, `spine_curve_timeline1_get_scale_value()` signatures changed. - Added `spine_slider_timeline` and `spine_slider_mix_timeline` for animating sliders - Added new pose system with `spine_bone_local`, `spine_bone_pose`, and related types - Added `spine_pose`, `spine_posed`, and `spine_posed_active` base types @@ -77,11 +86,23 @@ - Added `HasRendererObject` interface for attachments with renderer-specific data - Ported the latest parser fixes from spine-libgdx, including the 4.3 path constraint flag fix and the weighted mesh binary vertex allocation/count fix. - Ported the latest additive timeline updates and alpha/RGB timeline flicker fixes from spine-libgdx. + - Ported the AnimationState additive/hold rework from spine-libgdx. `MixBlend` and `MixDirection` are no longer used by timelines. The new system uses `bool fromSetup, bool add, bool out` parameters and a bitmask-based hold system that replaces `holdPrevious` and `interruptAlpha`. + - Added `Timeline::getAdditive()` and `Timeline::getInstant()` to query timeline blending capabilities. + - Added `TrackEntry::getAdditive()` / `TrackEntry::setAdditive()` to control additive blending per track entry. + - Ported the Skin placeholder name rename from spine-libgdx. `Skin::AttachmentMap::Entry::_name` renamed to `_placeholderName`. + - Fixed `SkeletonBinary::readLong()` sign extension bug that truncated 64-bit hash values to 32 bits. - Ported the sequence attachment refactor from spine-libgdx. `Sequence` now precomputes per-frame regions, UVs, and region offsets, and `RegionAttachment` / `MeshAttachment` now mirror the libgdx implementation. - **Breaking changes** - Headers reorganized from `spine-cpp/spine-cpp/include/spine/` to `spine-cpp/include/spine/` - - Timeline `apply()` methods now take an additional `appliedPose` parameter + - Timeline `apply()` signature changed: `MixBlend blend, MixDirection direction` replaced with `bool fromSetup, bool add, bool out`. All timeline subclasses updated. + - `Animation::apply()` signature changed to match the new timeline parameters. + - `CurveTimeline1::getRelativeValue()`, `getAbsoluteValue()`, and `getScaleValue()` signatures changed from `MixBlend`/`MixDirection` to `bool fromSetup, bool add, bool out`. + - `TrackEntry::getHoldPrevious()` / `setHoldPrevious()` removed. Use `TrackEntry::getAdditive()` / `setAdditive()` instead for additive blending. + - `TrackEntry::getMixBlend()` / `setMixBlend()` removed. + - `TrackEntry::_interruptAlpha` removed. + - `Skin::AttachmentMap::Entry::_name` renamed to `_placeholderName`. All `Skin` methods use `placeholderName` parameter names instead of `name`/`attachmentName`. + - `AnimationState` hold constants changed: `HoldSubsequent` and `HoldMix` removed, replaced with bitmask system (`Subsequent=0, First=1, Hold=2, HoldFirst=3`). - `Bone` now extends `PosedActive` with separate pose, constrained, and applied states - Renamed timeline constraint index methods to use unified `getConstraintIndex()` - Changed timeline class hierarchy with new base classes `BoneTimeline`, `SlotCurveTimeline`, and `ConstraintTimeline` @@ -598,6 +619,19 @@ - **Additions** - Added `Slider` and `SliderData` classes for slider constraints + - Reworked AnimationState hold system. Replaced `MixBlend`/`MixDirection` in timeline `apply()` with `boolean fromSetup, boolean add, boolean out`. The new bitmask-based hold system prevents dipping during crossfades without requiring `holdPrevious`. + - Added `Timeline.getAdditive()` and `Timeline.getInstant()` to query timeline blending capabilities. + - Added `TrackEntry.getAdditive()` / `TrackEntry.setAdditive()` for additive blending per track entry. + - Renamed `Skin.SkinEntry.getName()` to `getPlaceholderName()`. All `Skin` methods now use `placeholderName` parameter names. + +- **Breaking changes (since previous 4.3 beta)** + - `TrackEntry.getHoldPrevious()` / `setHoldPrevious()` removed. + - `TrackEntry.getMixBlend()` / `setMixBlend()` removed. Use `TrackEntry.getAdditive()` / `setAdditive()` for additive blending. + - `MixBlend` and `MixDirection` enums removed from `Animation`. + - Timeline `apply()` signature changed: `MixBlend blend, MixDirection direction` replaced with `boolean fromSetup, boolean add, boolean out`. + - `Animation.apply()` signature changed to match. + - `CurveTimeline1.getRelativeValue()`, `getAbsoluteValue()`, `getScaleValue()` signatures changed. + - `Skin.SkinEntry.getName()` renamed to `getPlaceholderName()`. - Added `SliderTimeline` and `SliderMixTimeline` for animating sliders - Added new pose system with `BoneLocal`, `BonePose`, and related classes - Added `Pose`, `Posed`, and `PosedActive` base classes for unified pose management diff --git a/spine-cpp/include/spine/Animation.h b/spine-cpp/include/spine/Animation.h index 362c538a4..cc5d78573 100644 --- a/spine-cpp/include/spine/Animation.h +++ b/spine-cpp/include/spine/Animation.h @@ -32,8 +32,6 @@ #include #include -#include -#include #include #include #include @@ -122,25 +120,28 @@ namespace spine { /// Applies the animation's timelines to the specified skeleton. /// /// See Timeline::apply(). - /// @param skeleton The skeleton the animation is being applied to. This provides access to the bones, slots, and other skeleton + /// @param skeleton The skeleton the animation is applied to. This provides access to the bones, slots, and other skeleton /// components the timelines may change. - /// @param lastTime The last time in seconds this animation was applied. Some timelines trigger only at specific times rather - /// than every frame. Pass -1 the first time an animation is applied to ensure frame 0 is triggered. - /// @param time The time in seconds the skeleton is being posed for. Most timelines find the frame before and the frame after - /// this time and interpolate between the frame values. If beyond the getDuration() and loop is - /// true then the animation will repeat, else the last frame will be applied. - /// @param loop If true, the animation repeats after the getDuration(). - /// @param events If any events are fired, they are added to this list. Can be null to ignore fired events or if no timelines + /// @param lastTime The last time in seconds this animation was applied. Some timelines trigger only at discrete times, in + /// which case all keys are triggered between lastTime (exclusive) and time (inclusive). Pass -1 the first time an + /// animation is applied to ensure frame 0 is triggered. + /// @param time The time in seconds the skeleton is being posed for. Timelines find the frame before and after this time and + /// interpolate between the frame values. + /// @param loop True if time beyond the getDuration() repeats the animation, else the last frame is used. + /// @param events If any events are fired, they are added to this list. Can be NULL to ignore fired events or if no timelines /// fire events. - /// @param alpha 0 applies the current or setup values (depending on blend). 1 applies the timeline values. Between - /// 0 and 1 applies values between the current or setup values and the timeline values. By adjusting - /// alpha over time, an animation can be mixed in or out. alpha can also be useful to apply - /// animations on top of each other (layering). - /// @param blend Controls how mixing is applied when alpha < 1. - /// @param direction Indicates whether the timelines are mixing in or out. Used by timelines which perform instant transitions, - /// such as DrawOrderTimeline or AttachmentTimeline. - void apply(Skeleton &skeleton, float lastTime, float time, bool loop, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose); + /// @param alpha 0 applies setup or current values (depending on fromSetup), 1 uses timeline values, and intermediate values + /// interpolate between them. Adjusting alpha over time can mix an animation in or out. + /// @param fromSetup If true, alpha transitions between setup and timeline values, setup values are used before the first + /// frame (current values are not used). If false, alpha transitions between current and timeline values, no change + /// is made before the first frame. + /// @param add If true, for timelines that support it, their values are added to the setup or current values (depending on + /// fromSetup). + /// @param out True when the animation is mixing out, else it is mixing in. Used by timelines that perform instant + /// transitions. + /// @param appliedPose True to modify the applied pose, else the pose is modified. + void apply(Skeleton &skeleton, float lastTime, float time, bool loop, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose); /// The animation's name, which is unique across all animations in the skeleton. const String &getName(); diff --git a/spine-cpp/include/spine/AnimationState.h b/spine-cpp/include/spine/AnimationState.h index ff7835b4b..71ad924e7 100644 --- a/spine-cpp/include/spine/AnimationState.h +++ b/spine-cpp/include/spine/AnimationState.h @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -116,20 +115,11 @@ namespace spine { void setLoop(bool inValue); - /// If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead - /// of being mixed out. - /// - /// When mixing between animations that key the same property, if a lower track also keys that property then the value will - /// briefly dip toward the lower track value during the mix. This happens because the first animation mixes from 100% to 0% - /// while the second animation mixes from 0% to 100%. Setting holdPrevious to true applies the first animation - /// at 100% during the mix so the lower track value is overwritten. Such dipping does not occur on the lowest track which - /// keys the property, only when a higher track also keys the property. - /// - /// Snapping will occur if holdPrevious is true and this animation does not key all the same properties as the - /// previous animation. - bool getHoldPrevious(); + /// When true, timelines in this animation that support additive have their values added to the setup or current pose values + /// instead of replacing them. Additive can be set for a new track entry only before AnimationState::apply() is next called. + bool getAdditive(); - void setHoldPrevious(bool inValue); + void setAdditive(bool inValue); bool getReverse(); @@ -285,16 +275,12 @@ namespace spine { /// entry is looping, its next loop completion is used instead of its duration. void setMixDuration(float mixDuration, float delay); - MixBlend getMixBlend(); - - void setMixBlend(MixBlend blend); - - /// The track entry for the previous animation when mixing from the previous animation to this animation, or NULL if no - /// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a double linked list with MixingTo. + /// The track entry for the previous animation when mixing to this animation, or NULL if no mixing is currently occurring. + /// When mixing from multiple animations, MixingFrom makes up a doubly linked list with MixingTo. TrackEntry *getMixingFrom(); - /// The track entry for the next animation when mixing from this animation, or NULL if no mixing is currently occuring. - /// When mixing from multiple animations, MixingTo makes up a double linked list with MixingFrom. + /// The track entry for the next animation when mixing from this animation, or NULL if no mixing is currently occurring. + /// When mixing to multiple animations, MixingTo makes up a doubly linked list with MixingFrom. TrackEntry *getMixingTo(); /// Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the @@ -347,12 +333,11 @@ namespace spine { TrackEntry *_mixingTo; int _trackIndex; - bool _loop, _holdPrevious, _reverse, _shortestRotation; + bool _loop, _additive, _reverse, _shortestRotation, _keepHold; float _eventThreshold, _mixAttachmentThreshold, _alphaAttachmentThreshold, _mixDrawOrderThreshold; float _animationStart, _animationEnd, _animationLast, _nextAnimationLast; float _delay, _trackTime, _trackLast, _nextTrackLast, _trackEnd, _timeScale; - float _alpha, _mixTime, _mixDuration, _interruptAlpha, _totalAlpha; - MixBlend _mixBlend; + float _alpha, _mixTime, _mixDuration, _totalAlpha; Array _timelineMode; Array _timelineHoldMix; Array _timelinesRotation; @@ -551,9 +536,8 @@ namespace spine { private: static const int Subsequent = 0; static const int First = 1; - static const int HoldSubsequent = 2; + static const int Hold = 2; static const int HoldFirst = 3; - static const int HoldMix = 4; static const int Setup = 1; static const int Current = 2; @@ -584,14 +568,14 @@ namespace spine { /// Applies the rotate timeline, mixing with the current pose while keeping the same rotation direction chosen as the shortest /// the first time the mixing was applied. - static void applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha, MixBlend pose, + static void applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha, bool fromSetup, Array &timelinesRotation, size_t i, bool firstFrame); /// Applies the attachment timeline and sets Slot::attachmentState. /// @param attachments False when: 1) the attachment timeline is mixing out, 2) mix < attachmentThreshold, and 3) the timeline /// is not the last timeline to set the slot's attachment. In that case the timeline is applied only so subsequent /// timelines see any deform. - void applyAttachmentTimeline(AttachmentTimeline *attachmentTimeline, Skeleton &skeleton, float animationTime, MixBlend pose, bool out, + void applyAttachmentTimeline(AttachmentTimeline *attachmentTimeline, Skeleton &skeleton, float animationTime, bool fromSetup, bool out, bool attachments); /// Returns true when all mixing from entries are complete. diff --git a/spine-cpp/include/spine/AnimationStateData.h b/spine-cpp/include/spine/AnimationStateData.h index 54b1d5a71..407c6f59d 100644 --- a/spine-cpp/include/spine/AnimationStateData.h +++ b/spine-cpp/include/spine/AnimationStateData.h @@ -41,7 +41,7 @@ namespace spine { class Animation; - /// Stores mix (crossfade) durations to be applied when AnimationState animations are changed. + /// Stores mix (crossfade) durations to be applied when AnimationState animations are changed on the same track. class SP_API AnimationStateData : public SpineObject { friend class AnimationState; @@ -63,7 +63,7 @@ namespace spine { /// See TrackEntry.MixDuration. void setMix(Animation &from, Animation &to, float duration); - /// The mix duration to use when changing from the specified animation to the other, + /// Returns the mix duration to use when changing from the specified animation to the other on the same track, /// or the DefaultMix if no mix duration has been set. float getMix(Animation &from, Animation &to); diff --git a/spine-cpp/include/spine/AttachmentTimeline.h b/spine-cpp/include/spine/AttachmentTimeline.h index a32ed73db..b62b66d96 100644 --- a/spine-cpp/include/spine/AttachmentTimeline.h +++ b/spine-cpp/include/spine/AttachmentTimeline.h @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include @@ -60,8 +58,8 @@ namespace spine { virtual ~AttachmentTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; /// Sets the time and attachment name for the specified frame. /// @param frame Between 0 and frameCount, inclusive. diff --git a/spine-cpp/include/spine/Bone.h b/spine-cpp/include/spine/Bone.h index 2e3695883..fb3c24688 100644 --- a/spine-cpp/include/spine/Bone.h +++ b/spine-cpp/include/spine/Bone.h @@ -38,11 +38,12 @@ #include namespace spine { - /// The current pose for a bone, before constraints are applied. - /// - /// A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a - /// local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a - /// constraint or application code modifies the world transform after it was computed from the local transform. + /// A bone has a number of poses: + /// - BoneData::getSetupPose(): The setup pose. + /// - getPose(): The local pose. Set by animations and app code. + /// - getAppliedPose(): The applied local pose. This is the local pose modified by constraints and app code. + /// - The world transform on the applied pose, computed by Skeleton::updateWorldTransform(Physics) and + /// BonePose::updateWorldTransform(Skeleton). class SP_API Bone : public PosedGeneric, public PosedActive, public Update { friend class AnimationState; friend class RotateTimeline; diff --git a/spine-cpp/include/spine/BoneData.h b/spine-cpp/include/spine/BoneData.h index c8916b434..dbf5e29cf 100644 --- a/spine-cpp/include/spine/BoneData.h +++ b/spine-cpp/include/spine/BoneData.h @@ -69,10 +69,10 @@ namespace spine { public: BoneData(int index, const String &name, BoneData *parent = NULL); - /// The index of the bone in Skeleton.Bones + /// The Skeleton::getBones() index. int getIndex(); - /// May be NULL. + /// The parent bone, or NULL if this bone is the root. BoneData *getParent(); float getLength(); @@ -81,6 +81,7 @@ namespace spine { Color &getColor(); + /// The bone icon name as it was in Spine, or empty if nonessential data was not exported. const String &getIcon(); void setIcon(const String &icon); diff --git a/spine-cpp/include/spine/BonePose.h b/spine-cpp/include/spine/BonePose.h index 1f78fab1b..b706607bf 100644 --- a/spine-cpp/include/spine/BonePose.h +++ b/spine-cpp/include/spine/BonePose.h @@ -38,8 +38,15 @@ namespace spine { class Bone; class Skeleton; - /// The applied pose for a bone. This is the Bone pose with constraints applied and the world transform computed by - /// Skeleton::updateWorldTransform(Physics). + /// The applied local pose and world transform for a bone. This is the Bone::getPose() with constraints applied and the + /// world transform computed by Skeleton::updateWorldTransform(Physics) and updateWorldTransform(Skeleton). + /// + /// If the world transform is changed, call updateLocalTransform(Skeleton) before using the local transform. The local + /// transform may be needed by other code (eg to apply another constraint). + /// + /// After changing the world transform, call updateWorldTransform(Skeleton) on every descendant bone. It may be more + /// convenient to modify the local transform instead, then call Skeleton::updateWorldTransform(Physics) to update the world + /// transforms for all bones and apply constraints. class SP_API BonePose : public BoneLocal, public Update { friend class IkConstraint; friend class PathConstraint; @@ -72,7 +79,8 @@ namespace spine { /// Called by Skeleton::updateCache() to compute the world transform, if needed. virtual void update(Skeleton &skeleton, Physics physics) override; - /// Computes the world transform using the parent bone's applied pose and this pose. Child bones are not updated. + /// Computes the world transform using the parent bone's world transform and this applied local pose. Child bones are not + /// updated. /// /// See World transforms in the Spine /// Runtimes Guide. @@ -80,42 +88,40 @@ namespace spine { /// Computes the local transform values from the world transform. /// - /// If the world transform is modified (by a constraint, rotateWorld(), etc) then this method should be called so - /// the local transform matches the world transform. The local transform may be needed by other code (eg to apply another - /// constraint). - /// /// Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The local transform after /// calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. void updateLocalTransform(Skeleton &skeleton); - /// If the world transform has been modified and the local transform no longer matches, updateLocalTransform() is called. + /// If the world transform has been modified by constraints and the local transform no longer matches, + /// updateLocalTransform() is called. Call this after Skeleton::updateWorldTransform(Physics) before using the applied + /// local transform. void validateLocalTransform(Skeleton &skeleton); void modifyLocal(Skeleton &skeleton); void modifyWorld(int update); void resetWorld(int update); - /// Part of the world transform matrix for the X axis. If changed, updateLocalTransform() should be called. + /// Part of the world transform matrix for the X axis. float getA(); void setA(float a); - /// Part of the world transform matrix for the Y axis. If changed, updateLocalTransform() should be called. + /// Part of the world transform matrix for the Y axis. float getB(); void setB(float b); - /// Part of the world transform matrix for the X axis. If changed, updateLocalTransform() should be called. + /// Part of the world transform matrix for the X axis. float getC(); void setC(float c); - /// Part of the world transform matrix for the Y axis. If changed, updateLocalTransform() should be called. + /// Part of the world transform matrix for the Y axis. float getD(); void setD(float d); - /// The world X position. If changed, updateLocalTransform() should be called. + /// The world X position. float getWorldX(); void setWorldX(float worldX); - /// The world Y position. If changed, updateLocalTransform() should be called. + /// The world Y position. float getWorldY(); void setWorldY(float worldY); @@ -150,9 +156,6 @@ namespace spine { float localToWorldRotation(float localRotation); /// Rotates the world transform the specified amount. - /// - /// After changes are made to the world transform, updateLocalTransform() should be called on this bone and any - /// child bones, recursively. void rotateWorld(float degrees); protected: diff --git a/spine-cpp/include/spine/BoneTimeline.h b/spine-cpp/include/spine/BoneTimeline.h index 4b4126693..7b70b919c 100644 --- a/spine-cpp/include/spine/BoneTimeline.h +++ b/spine-cpp/include/spine/BoneTimeline.h @@ -66,8 +66,8 @@ namespace spine { public: BoneTimeline1(size_t frameCount, size_t bezierCount, int boneIndex, Property property); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; virtual int getBoneIndex() const override { return _boneIndex; @@ -79,7 +79,7 @@ namespace spine { protected: /// Applies changes to the pose based on the timeline values. - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) = 0; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) = 0; int _boneIndex; }; @@ -95,8 +95,8 @@ namespace spine { public: BoneTimeline2(size_t frameCount, size_t bezierCount, int boneIndex, Property property1, Property property2); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; virtual int getBoneIndex() const override { return _boneIndex; @@ -110,7 +110,7 @@ namespace spine { protected: /// Applies changes to the pose based on the timeline values. - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) = 0; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) = 0; int _boneIndex; diff --git a/spine-cpp/include/spine/ClippingAttachment.h b/spine-cpp/include/spine/ClippingAttachment.h index 3e5136178..411e8eaee 100644 --- a/spine-cpp/include/spine/ClippingAttachment.h +++ b/spine-cpp/include/spine/ClippingAttachment.h @@ -48,6 +48,8 @@ namespace spine { public: explicit ClippingAttachment(const String &name); + /// Clipping is performed between the clipping attachment's slot and the end slot. If NULL, clipping is done until + /// the end of the skeleton's rendering. SlotData *getEndSlot(); void setEndSlot(SlotData *inValue); diff --git a/spine-cpp/include/spine/ColorTimeline.h b/spine-cpp/include/spine/ColorTimeline.h index 9802e4059..43796a644 100644 --- a/spine-cpp/include/spine/ColorTimeline.h +++ b/spine-cpp/include/spine/ColorTimeline.h @@ -34,7 +34,7 @@ #include namespace spine { - /// Changes a slot's SlotPose::getColor(). + /// Changes SlotPose::getColor(). class SP_API RGBATimeline : public SlotCurveTimeline { friend class SkeletonBinary; @@ -53,7 +53,7 @@ namespace spine { void setFrame(int frame, float time, float r, float g, float b, float a); protected: - virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) override; + virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) override; static const int ENTRIES = 5; static const int R = 1; @@ -62,7 +62,7 @@ namespace spine { static const int A = 4; }; - /// Changes the RGB for a slot's SlotPose::getColor(). + /// Changes RGB for a slot's SlotPose::getColor(). class SP_API RGBTimeline : public SlotCurveTimeline { friend class SkeletonBinary; @@ -81,7 +81,7 @@ namespace spine { void setFrame(int frame, float time, float r, float g, float b); protected: - virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) override; + virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) override; static const int ENTRIES = 4; static const int R = 1; @@ -101,8 +101,8 @@ namespace spine { virtual ~AlphaTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; virtual int getSlotIndex() override; @@ -112,7 +112,7 @@ namespace spine { int _slotIndex; }; - /// Changes a slot's SlotPose::getColor() and SlotPose::getDarkColor() for two color tinting. + /// Changes SlotPose::getColor() and SlotPose::getDarkColor() for two color tinting. class SP_API RGBA2Timeline : public SlotCurveTimeline { friend class SkeletonBinary; @@ -131,7 +131,7 @@ namespace spine { void setFrame(int frame, float time, float r, float g, float b, float a, float r2, float g2, float b2); protected: - virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) override; + virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) override; static const int ENTRIES = 8; static const int R = 1; @@ -143,7 +143,7 @@ namespace spine { static const int B2 = 7; }; - /// Changes the RGB for a slot's SlotPose::getColor() and SlotPose::getDarkColor() for two color tinting. + /// Changes RGB for a slot's SlotPose::getColor() and SlotPose::getDarkColor() for two color tinting. class SP_API RGB2Timeline : public SlotCurveTimeline { friend class SkeletonBinary; @@ -162,7 +162,7 @@ namespace spine { void setFrame(int frame, float time, float r, float g, float b, float r2, float g2, float b2); protected: - virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) override; + virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) override; static const int ENTRIES = 7; static const int R = 1; diff --git a/spine-cpp/include/spine/ConstraintTimeline1.h b/spine-cpp/include/spine/ConstraintTimeline1.h index d556a7105..b7b73151a 100644 --- a/spine-cpp/include/spine/ConstraintTimeline1.h +++ b/spine-cpp/include/spine/ConstraintTimeline1.h @@ -35,7 +35,7 @@ #include namespace spine { - /// Base class for single-value constraint timelines. + /// The base class for timelines that change 1 constraint property with a curve. class SP_API ConstraintTimeline1 : public CurveTimeline1, public ConstraintTimeline { RTTI_DECL diff --git a/spine-cpp/include/spine/CurveTimeline.h b/spine-cpp/include/spine/CurveTimeline.h index e1a03bb2e..084d5b1f0 100644 --- a/spine-cpp/include/spine/CurveTimeline.h +++ b/spine-cpp/include/spine/CurveTimeline.h @@ -82,13 +82,13 @@ namespace spine { /// Returns the interpolated value for the specified time. float getCurveValue(float time); - float getRelativeValue(float time, float alpha, MixBlend blend, float current, float setup); + float getRelativeValue(float time, float alpha, bool fromSetup, bool add, float current, float setup); - float getAbsoluteValue(float time, float alpha, MixBlend blend, float current, float setup); + float getAbsoluteValue(float time, float alpha, bool fromSetup, bool add, float current, float setup); - float getAbsoluteValue(float time, float alpha, MixBlend blend, float current, float setup, float value); + float getAbsoluteValue(float time, float alpha, bool fromSetup, bool add, float current, float setup, float value); - float getScaleValue(float time, float alpha, MixBlend blend, MixDirection direction, float current, float setup); + float getScaleValue(float time, float alpha, bool fromSetup, bool add, bool out, float current, float setup); protected: static const int ENTRIES = 2; diff --git a/spine-cpp/include/spine/DeformTimeline.h b/spine-cpp/include/spine/DeformTimeline.h index e56071439..51e4ad2cd 100644 --- a/spine-cpp/include/spine/DeformTimeline.h +++ b/spine-cpp/include/spine/DeformTimeline.h @@ -35,7 +35,7 @@ namespace spine { class VertexAttachment; - /// Changes a slot's SlotPose::getDeform() to deform a VertexAttachment. + /// Changes SlotPose::getDeform() to deform a VertexAttachment. class SP_API DeformTimeline : public SlotCurveTimeline { friend class SkeletonBinary; @@ -67,7 +67,7 @@ namespace spine { } protected: - void _apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) override; + void _apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) override; private: Array> _vertices; diff --git a/spine-cpp/include/spine/DrawOrderFolderTimeline.h b/spine-cpp/include/spine/DrawOrderFolderTimeline.h index 34e29dee8..4dabf2dd1 100644 --- a/spine-cpp/include/spine/DrawOrderFolderTimeline.h +++ b/spine-cpp/include/spine/DrawOrderFolderTimeline.h @@ -33,7 +33,7 @@ #include namespace spine { - /// Changes a subset of a skeleton's Skeleton::getDrawOrder(). + /// Changes a subset of Skeleton::getDrawOrder(). class SP_API DrawOrderFolderTimeline : public Timeline { friend class SkeletonBinary; @@ -44,8 +44,8 @@ namespace spine { public: DrawOrderFolderTimeline(size_t frameCount, Array &slots, size_t slotCount); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; size_t getFrameCount(); diff --git a/spine-cpp/include/spine/DrawOrderTimeline.h b/spine-cpp/include/spine/DrawOrderTimeline.h index 62ea54637..865444233 100644 --- a/spine-cpp/include/spine/DrawOrderTimeline.h +++ b/spine-cpp/include/spine/DrawOrderTimeline.h @@ -33,7 +33,7 @@ #include namespace spine { - /// Changes a skeleton's Skeleton::getDrawOrder(). + /// Changes Skeleton::getDrawOrder(). class SP_API DrawOrderTimeline : public Timeline { friend class SkeletonBinary; @@ -46,8 +46,8 @@ namespace spine { explicit DrawOrderTimeline(size_t frameCount); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; size_t getFrameCount(); diff --git a/spine-cpp/include/spine/Event.h b/spine-cpp/include/spine/Event.h index 3e749b91d..fd9c495bc 100644 --- a/spine-cpp/include/spine/Event.h +++ b/spine-cpp/include/spine/Event.h @@ -39,7 +39,7 @@ namespace spine { /// Stores the current pose values for an Event. /// /// See Timeline::apply(), AnimationStateListener::event(), and - /// @see https://esotericsoftware.com/spine-events Events in the Spine User Guide. + /// https://esotericsoftware.com/spine-events Events in the Spine User Guide. class SP_API Event : public SpineObject { friend class SkeletonBinary; diff --git a/spine-cpp/include/spine/EventData.h b/spine-cpp/include/spine/EventData.h index 6a8c612dd..d1a1109d7 100644 --- a/spine-cpp/include/spine/EventData.h +++ b/spine-cpp/include/spine/EventData.h @@ -45,7 +45,7 @@ namespace spine { public: explicit EventData(const String &name); - /// The name of the event, which is unique within the skeleton. + /// The name of the event, unique across all events in the skeleton. const String &getName() const; int getInt() const; diff --git a/spine-cpp/include/spine/EventTimeline.h b/spine-cpp/include/spine/EventTimeline.h index 1ef07dc41..f1a8d0070 100644 --- a/spine-cpp/include/spine/EventTimeline.h +++ b/spine-cpp/include/spine/EventTimeline.h @@ -47,8 +47,8 @@ namespace spine { ~EventTimeline(); /// Fires events for frames > lastTime and <= time. - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; size_t getFrameCount(); diff --git a/spine-cpp/include/spine/IkConstraintTimeline.h b/spine-cpp/include/spine/IkConstraintTimeline.h index 4dbf789c9..f71bfa10c 100644 --- a/spine-cpp/include/spine/IkConstraintTimeline.h +++ b/spine-cpp/include/spine/IkConstraintTimeline.h @@ -35,7 +35,7 @@ namespace spine { - /// Changes an IK constraint's IkConstraintPose::getMix(), IkConstraintPose::getSoftness(), + /// Changes IkConstraintPose::getMix(), IkConstraintPose::getSoftness(), /// IkConstraintPose::getBendDirection(), IkConstraintPose::getStretch(), and IkConstraintPose::getCompress(). class SP_API IkConstraintTimeline : public CurveTimeline, public ConstraintTimeline { friend class SkeletonBinary; @@ -49,8 +49,8 @@ namespace spine { virtual ~IkConstraintTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; /// Sets the time, mix, softness, bend direction, compress, and stretch for the specified frame. /// @param frame Between 0 and frameCount, inclusive. diff --git a/spine-cpp/include/spine/InheritTimeline.h b/spine-cpp/include/spine/InheritTimeline.h index 7aa970720..af70d263f 100644 --- a/spine-cpp/include/spine/InheritTimeline.h +++ b/spine-cpp/include/spine/InheritTimeline.h @@ -56,8 +56,8 @@ namespace spine { /// @param time The frame time in seconds. void setFrame(int frame, float time, Inherit inherit); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; virtual int getBoneIndex() const override { diff --git a/spine-cpp/include/spine/MeshAttachment.h b/spine-cpp/include/spine/MeshAttachment.h index aff94e276..e034bc107 100644 --- a/spine-cpp/include/spine/MeshAttachment.h +++ b/spine-cpp/include/spine/MeshAttachment.h @@ -74,9 +74,14 @@ namespace spine { Color &getColor(); + /// The parent mesh if this is a linked mesh, else NULL. A linked mesh shares the bones, vertices, regionUVs, + /// triangles, hullLength, edges, width, and height with the parent mesh, but may have a different name or path, + /// and therefore a different texture region. MeshAttachment *getParentMesh(); void setParentMesh(MeshAttachment *inValue); + /// Vertex index pairs describing edges for controlling triangulation, or empty if nonessential data was not + /// exported. Mesh triangles do not cross edges. Triangulation is not performed at runtime. Array &getEdges(); void setEdges(Array &inValue); diff --git a/spine-cpp/include/spine/MixBlend.h b/spine-cpp/include/spine/MixBlend.h deleted file mode 100644 index 7fc4dda3f..000000000 --- a/spine-cpp/include/spine/MixBlend.h +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated April 5, 2025. Replaces all prior versions. - * - * Copyright (c) 2013-2025, Esoteric Software LLC - * - * Integration of the Spine Runtimes into software or otherwise creating - * derivative works of the Spine Runtimes is permitted under the terms and - * conditions of Section 2 of the Spine Editor License Agreement: - * http://esotericsoftware.com/spine-editor-license - * - * Otherwise, it is permitted to integrate the Spine Runtimes into software - * or otherwise create derivative works of the Spine Runtimes (collectively, - * "Products"), provided that each user of the Products must obtain their own - * Spine Editor license and redistribution of the Products in any form must - * include this license and copyright notice. - * - * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, - * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef Spine_MixPose_h -#define Spine_MixPose_h - -namespace spine { - - /// Controls how timeline values are mixed with setup pose values or current pose values when a timeline is applied with - /// alpha < 1. - /// - /// See Timeline::apply(). - enum MixBlend { - /// Transitions between the setup and timeline values (the current value is not used). Before the first frame, the setup - /// value is used. - /// - /// MixBlend_Setup is intended to transition to or from the setup pose, not for animations layered on top of others. - MixBlend_Setup = 0, - /// Transitions between the current and timeline values. Before the first frame, transitions between the current and setup - /// values. Timelines which perform instant transitions, such as DrawOrderTimeline or AttachmentTimeline, use - /// the setup value before the first frame. - /// - /// MixBlend_First is intended for the first animations applied, not for animations layered on top of others. - MixBlend_First, - /// Transitions between the current and timeline values. No change is made before the first frame. - /// - /// MixBlend_Replace is intended for animations layered on top of others, not for the first animations applied. - MixBlend_Replace, - /// Transitions between the current value and the current plus timeline values. No change is made before the first frame. - /// - /// MixBlend_Add is intended for animations layered on top of others, not for the first animations applied. - /// - /// Properties set by additive animations must be set manually or by another animation before applying the additive - /// animations, else the property values will increase each time the additive animations are applied. - MixBlend_Add - }; -} - -#endif /* Spine_MixPose_h */ diff --git a/spine-cpp/include/spine/MixDirection.h b/spine-cpp/include/spine/MixDirection.h deleted file mode 100644 index 47a3b4ba2..000000000 --- a/spine-cpp/include/spine/MixDirection.h +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated April 5, 2025. Replaces all prior versions. - * - * Copyright (c) 2013-2025, Esoteric Software LLC - * - * Integration of the Spine Runtimes into software or otherwise creating - * derivative works of the Spine Runtimes is permitted under the terms and - * conditions of Section 2 of the Spine Editor License Agreement: - * http://esotericsoftware.com/spine-editor-license - * - * Otherwise, it is permitted to integrate the Spine Runtimes into software - * or otherwise create derivative works of the Spine Runtimes (collectively, - * "Products"), provided that each user of the Products must obtain their own - * Spine Editor license and redistribution of the Products in any form must - * include this license and copyright notice. - * - * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, - * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef Spine_MixDirection_h -#define Spine_MixDirection_h - -namespace spine { - - /// Indicates whether a timeline's alpha is mixing out over time toward 0 (the setup or current pose value) or - /// mixing in toward 1 (the timeline's value). Some timelines use this to decide how values are applied. - /// - /// See Timeline::apply(). - enum MixDirection { - MixDirection_In = 0, - MixDirection_Out - }; - -} - -#endif /* Spine_MixDirection_h */ diff --git a/spine-cpp/include/spine/PathAttachment.h b/spine-cpp/include/spine/PathAttachment.h index f0ebbcc1d..f70f82e87 100644 --- a/spine-cpp/include/spine/PathAttachment.h +++ b/spine-cpp/include/spine/PathAttachment.h @@ -53,6 +53,8 @@ namespace spine { void setClosed(bool inValue); + /// If true, additional calculations are performed to make computing positions along the path more accurate so + /// movement along the path has a constant speed. bool getConstantSpeed(); void setConstantSpeed(bool inValue); diff --git a/spine-cpp/include/spine/PathConstraintMixTimeline.h b/spine-cpp/include/spine/PathConstraintMixTimeline.h index 44fdf8fcd..808d7709d 100644 --- a/spine-cpp/include/spine/PathConstraintMixTimeline.h +++ b/spine-cpp/include/spine/PathConstraintMixTimeline.h @@ -35,7 +35,7 @@ namespace spine { - /// Changes a path constraint's PathConstraintPose::getMixRotate(), PathConstraintPose::getMixX(), and + /// Changes PathConstraintPose::getMixRotate(), PathConstraintPose::getMixX(), and /// PathConstraintPose::getMixY(). class SP_API PathConstraintMixTimeline : public CurveTimeline, public ConstraintTimeline { friend class SkeletonBinary; @@ -49,8 +49,8 @@ namespace spine { virtual ~PathConstraintMixTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; /// Sets the time and color for the specified frame. /// @param frame Between 0 and frameCount, inclusive. diff --git a/spine-cpp/include/spine/PathConstraintPositionTimeline.h b/spine-cpp/include/spine/PathConstraintPositionTimeline.h index 2ddd67bcd..6345be93a 100644 --- a/spine-cpp/include/spine/PathConstraintPositionTimeline.h +++ b/spine-cpp/include/spine/PathConstraintPositionTimeline.h @@ -34,7 +34,7 @@ namespace spine { - /// Changes a path constraint's PathConstraintPose::getPosition(). + /// Changes PathConstraintPose::getPosition(). class SP_API PathConstraintPositionTimeline : public ConstraintTimeline1 { friend class SkeletonBinary; @@ -49,8 +49,8 @@ namespace spine { virtual ~PathConstraintPositionTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; }; }// namespace spine diff --git a/spine-cpp/include/spine/PathConstraintSpacingTimeline.h b/spine-cpp/include/spine/PathConstraintSpacingTimeline.h index 443f07380..9f4854586 100644 --- a/spine-cpp/include/spine/PathConstraintSpacingTimeline.h +++ b/spine-cpp/include/spine/PathConstraintSpacingTimeline.h @@ -33,7 +33,7 @@ #include namespace spine { - /// Changes a path constraint's PathConstraintPose::getSpacing(). + /// Changes PathConstraintPose::getSpacing(). class SP_API PathConstraintSpacingTimeline : public ConstraintTimeline1 { friend class SkeletonBinary; @@ -46,8 +46,8 @@ namespace spine { virtual ~PathConstraintSpacingTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; }; } diff --git a/spine-cpp/include/spine/PhysicsConstraintTimeline.h b/spine-cpp/include/spine/PhysicsConstraintTimeline.h index 9fe0c946e..88e245772 100644 --- a/spine-cpp/include/spine/PhysicsConstraintTimeline.h +++ b/spine-cpp/include/spine/PhysicsConstraintTimeline.h @@ -50,8 +50,8 @@ namespace spine { /// @param constraintIndex -1 for all physics constraints in the skeleton. explicit PhysicsConstraintTimeline(size_t frameCount, size_t bezierCount, int constraintIndex, Property property); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; virtual int getConstraintIndex() const override { return _constraintIndex; @@ -67,10 +67,9 @@ namespace spine { virtual bool global(PhysicsConstraintData &constraintData) = 0; int _constraintIndex; - bool _additive; }; - /// Changes a physics constraint's PhysicsConstraintPose::getInertia(). + /// Changes PhysicsConstraintPose::getInertia(). class SP_API PhysicsConstraintInertiaTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -96,7 +95,7 @@ namespace spine { } }; - /// Changes a physics constraint's PhysicsConstraintPose::getStrength(). + /// Changes PhysicsConstraintPose::getStrength(). class SP_API PhysicsConstraintStrengthTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -122,7 +121,7 @@ namespace spine { } }; - /// Changes a physics constraint's PhysicsConstraintPose::getDamping(). + /// Changes PhysicsConstraintPose::getDamping(). class SP_API PhysicsConstraintDampingTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -148,8 +147,7 @@ namespace spine { } }; - /// Changes a physics constraint's PhysicsConstraintPose::getMassInverse(). The - /// timeline values are not inverted. + /// Changes PhysicsConstraintPose::getMassInverse(). The timeline values are not inverted. class SP_API PhysicsConstraintMassTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -175,7 +173,7 @@ namespace spine { } }; - /// Changes a physics constraint's PhysicsConstraintPose::getWind(). + /// Changes PhysicsConstraintPose::getWind(). class SP_API PhysicsConstraintWindTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -203,7 +201,7 @@ namespace spine { } }; - /// Changes a physics constraint's PhysicsConstraintPose::getGravity(). + /// Changes PhysicsConstraintPose::getGravity(). class SP_API PhysicsConstraintGravityTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -231,7 +229,7 @@ namespace spine { } }; - /// Changes a physics constraint's PhysicsConstraintPose::getMix(). + /// Changes PhysicsConstraintPose::getMix(). class SP_API PhysicsConstraintMixTimeline : public PhysicsConstraintTimeline { friend class SkeletonBinary; @@ -271,10 +269,11 @@ namespace spine { : Timeline(frameCount, 1), ConstraintTimeline(), _constraintIndex(constraintIndex) { PropertyId ids[] = {((PropertyId) Property_PhysicsConstraintReset) << 32}; setPropertyIds(ids, 1); + _instant = true; } - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; int getFrameCount() { return (int) _frames.size(); diff --git a/spine-cpp/include/spine/PointAttachment.h b/spine-cpp/include/spine/PointAttachment.h index 5e162b487..c5f33e037 100644 --- a/spine-cpp/include/spine/PointAttachment.h +++ b/spine-cpp/include/spine/PointAttachment.h @@ -53,22 +53,27 @@ namespace spine { public: explicit PointAttachment(const String &name); + /// The local X position. float getX(); void setX(float inValue); + /// The local Y position. float getY(); void setY(float inValue); + /// The local rotation in degrees, counter clockwise. float getRotation(); void setRotation(float inValue); Color &getColor(); + /// Computes the world position from the local position. void computeWorldPosition(BonePose &bone, float &ox, float &oy); + /// Computes the world rotation from the local rotation. float computeWorldRotation(BonePose &bone); virtual Attachment ©() override; diff --git a/spine-cpp/include/spine/PosedActive.h b/spine-cpp/include/spine/PosedActive.h index 02bdef531..78f6eb381 100644 --- a/spine-cpp/include/spine/PosedActive.h +++ b/spine-cpp/include/spine/PosedActive.h @@ -44,6 +44,9 @@ namespace spine { virtual ~PosedActive() { } + /// Returns false when this won't be updated by Skeleton::updateWorldTransform(Physics) because a skin is + /// required and the active skin does not contain this item. See Skin::getBones(), Skin::getConstraints(), + /// PosedData::getSkinRequired(), and Skeleton::updateCache(). bool isActive() const { return _active; } diff --git a/spine-cpp/include/spine/PosedData.h b/spine-cpp/include/spine/PosedData.h index 1b765c46a..35ee4eef4 100644 --- a/spine-cpp/include/spine/PosedData.h +++ b/spine-cpp/include/spine/PosedData.h @@ -66,7 +66,6 @@ namespace spine { PosedData(const String &name); virtual ~PosedData(); - /// The constraint's name, which is unique across all constraints in the skeleton of the same type. const String &getName() const { return _name; }; diff --git a/spine-cpp/include/spine/RegionAttachment.h b/spine-cpp/include/spine/RegionAttachment.h index 449c7449c..3069f4659 100644 --- a/spine-cpp/include/spine/RegionAttachment.h +++ b/spine-cpp/include/spine/RegionAttachment.h @@ -79,6 +79,7 @@ namespace spine { float getScaleY(); void setScaleY(float inValue); + /// The local rotation in degrees, counter clockwise. float getRotation(); void setRotation(float inValue); diff --git a/spine-cpp/include/spine/RotateTimeline.h b/spine-cpp/include/spine/RotateTimeline.h index 9998866a2..4b56f50bd 100644 --- a/spine-cpp/include/spine/RotateTimeline.h +++ b/spine-cpp/include/spine/RotateTimeline.h @@ -47,7 +47,7 @@ namespace spine { explicit RotateTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; } diff --git a/spine-cpp/include/spine/ScaleTimeline.h b/spine-cpp/include/spine/ScaleTimeline.h index 60e2d47e8..4f2c3db8c 100644 --- a/spine-cpp/include/spine/ScaleTimeline.h +++ b/spine-cpp/include/spine/ScaleTimeline.h @@ -45,7 +45,7 @@ namespace spine { explicit ScaleTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; /// Changes a bone's local BoneLocal::getScaleX(). @@ -60,7 +60,7 @@ namespace spine { explicit ScaleXTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; /// Changes a bone's local BoneLocal::getScaleY(). @@ -75,7 +75,7 @@ namespace spine { explicit ScaleYTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; } diff --git a/spine-cpp/include/spine/SequenceTimeline.h b/spine-cpp/include/spine/SequenceTimeline.h index f5e2f7bd9..b7ec22857 100644 --- a/spine-cpp/include/spine/SequenceTimeline.h +++ b/spine-cpp/include/spine/SequenceTimeline.h @@ -38,7 +38,7 @@ namespace spine { class Attachment; class HasTextureRegion; - /// Changes a slot's SlotPose::getSequenceIndex() for an attachment's Sequence. + /// Changes SlotPose::getSequenceIndex() for an attachment's Sequence. class SP_API SequenceTimeline : public Timeline, public SlotTimeline { friend class SkeletonBinary; @@ -51,8 +51,8 @@ namespace spine { virtual ~SequenceTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; /// Sets the time, mode, index, and frame time for the specified frame. /// @param frame Between 0 and frameCount, inclusive. diff --git a/spine-cpp/include/spine/ShearTimeline.h b/spine-cpp/include/spine/ShearTimeline.h index 2c5377d3f..ff653cd2e 100644 --- a/spine-cpp/include/spine/ShearTimeline.h +++ b/spine-cpp/include/spine/ShearTimeline.h @@ -45,7 +45,7 @@ namespace spine { explicit ShearTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; /// Changes a bone's local BoneLocal::getShearX(). @@ -60,7 +60,7 @@ namespace spine { explicit ShearXTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; /// Changes a bone's local BoneLocal::getShearY(). @@ -75,7 +75,7 @@ namespace spine { explicit ShearYTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; } diff --git a/spine-cpp/include/spine/Skeleton.h b/spine-cpp/include/spine/Skeleton.h index f51f5a4de..86b3cacf4 100644 --- a/spine-cpp/include/spine/Skeleton.h +++ b/spine-cpp/include/spine/Skeleton.h @@ -200,6 +200,7 @@ namespace spine { /// @return May be NULL. Slot *findSlot(const String &slotName); + /// The skeleton's slots in the order they should be drawn. The returned array may be modified to change the draw order. Array &getDrawOrder(); Skin *getSkin(); @@ -310,6 +311,9 @@ namespace spine { /// Calls {@link PhysicsConstraint#rotate(float, float, float)} for each physics constraint. */ void physicsRotate(float x, float y, float degrees); + /// Returns the skeleton's time, used for time-based manipulations, such as PhysicsConstraint. + /// + /// See update(). float getTime(); void setTime(float time); diff --git a/spine-cpp/include/spine/SkeletonBinary.h b/spine-cpp/include/spine/SkeletonBinary.h index ac48b87bf..7a40bf123 100644 --- a/spine-cpp/include/spine/SkeletonBinary.h +++ b/spine-cpp/include/spine/SkeletonBinary.h @@ -171,9 +171,9 @@ namespace spine { } inline long long readLong() { - unsigned long long result = (unsigned long long) readInt(); + unsigned long long result = (unsigned int) readInt(); result <<= 32; - result |= (unsigned long long) readInt(); + result |= (unsigned int) readInt(); return (long long) result; } diff --git a/spine-cpp/include/spine/Skin.h b/spine-cpp/include/spine/Skin.h index 0093bbc0e..65f1f85ba 100644 --- a/spine-cpp/include/spine/Skin.h +++ b/spine-cpp/include/spine/Skin.h @@ -43,7 +43,7 @@ namespace spine { class ConstraintData; - /// Stores attachments by slot index and attachment name. + /// Stores attachments by slot index and placeholder name. /// See SkeletonData::getDefaultSkin, Skeleton::getSkin, and /// http://esotericsoftware.com/spine-runtime-skins in the Spine Runtimes Guide. class SP_API Skin : public SpineObject { @@ -56,10 +56,11 @@ namespace spine { public: struct SP_API Entry { size_t _slotIndex; - String _name; + String _placeholderName; Attachment *_attachment; - Entry(size_t slotIndex, const String &name, Attachment *attachment) : _slotIndex(slotIndex), _name(name), _attachment(attachment) { + Entry(size_t slotIndex, const String &placeholderName, Attachment *attachment) + : _slotIndex(slotIndex), _placeholderName(placeholderName), _attachment(attachment) { } }; @@ -95,11 +96,11 @@ namespace spine { size_t _bucketIndex; }; - void put(size_t slotIndex, const String &attachmentName, Attachment *attachment); + void put(size_t slotIndex, const String &placeholderName, Attachment *attachment); - Attachment *get(size_t slotIndex, const String &attachmentName); + Attachment *get(size_t slotIndex, const String &placeholderName); - void remove(size_t slotIndex, const String &attachmentName); + void remove(size_t slotIndex, const String &placeholderName); Entries getEntries(); @@ -107,7 +108,7 @@ namespace spine { AttachmentMap(); private: - int findInBucket(Array &, const String &attachmentName); + int findInBucket(Array &, const String &placeholderName); Array> _buckets; }; @@ -116,19 +117,19 @@ namespace spine { ~Skin(); - /// 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. - void setAttachment(size_t slotIndex, const String &name, Attachment *attachment); + /// Adds an attachment to the skin for the specified slot index and placeholder name. + /// If the placeholder name already exists for the slot, the previous value is replaced. + void setAttachment(size_t slotIndex, const String &placeholderName, Attachment *attachment); - /// Returns the attachment for the specified slot index and name, or NULL. - Attachment *getAttachment(size_t slotIndex, const String &name); + /// Returns the attachment for the specified slot index and placeholder name, or NULL. + Attachment *getAttachment(size_t slotIndex, const String &placeholderName); // Removes the attachment from the skin. - void removeAttachment(size_t slotIndex, const String &name); + void removeAttachment(size_t slotIndex, const String &placeholderName); - /// Finds the skin keys for a given slot. The results are added to the passed array of names. + /// Finds the placeholder names for a given slot. The results are added to the passed array. /// @param slotIndex The target slotIndex. To find the slot index, use SkeletonData::findSlot and SlotData::getIndex. - /// @param names Found skin key names will be added to this array. + /// @param names Found placeholder names will be added to this array. void findNamesForSlot(size_t slotIndex, Array &names); /// Finds the attachments for a given slot. The results are added to the passed array of Attachments. diff --git a/spine-cpp/include/spine/SliderMixTimeline.h b/spine-cpp/include/spine/SliderMixTimeline.h index 542af4134..a18d09b0a 100644 --- a/spine-cpp/include/spine/SliderMixTimeline.h +++ b/spine-cpp/include/spine/SliderMixTimeline.h @@ -33,7 +33,7 @@ #include namespace spine { - /// Changes a slider's SliderPose::getMix(). + /// Changes SliderPose::getMix(). class SP_API SliderMixTimeline : public ConstraintTimeline1 { friend class SkeletonBinary; friend class SkeletonJson; @@ -45,8 +45,8 @@ namespace spine { virtual ~SliderMixTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; }; } diff --git a/spine-cpp/include/spine/SliderTimeline.h b/spine-cpp/include/spine/SliderTimeline.h index 281713ef4..a0d9af5b2 100644 --- a/spine-cpp/include/spine/SliderTimeline.h +++ b/spine-cpp/include/spine/SliderTimeline.h @@ -33,7 +33,7 @@ #include namespace spine { - /// Changes a slider's SliderPose::getTime(). + /// Changes SliderPose::getTime(). class SP_API SliderTimeline : public ConstraintTimeline1 { friend class SkeletonBinary; friend class SkeletonJson; @@ -45,8 +45,8 @@ namespace spine { virtual ~SliderTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; }; } diff --git a/spine-cpp/include/spine/SlotCurveTimeline.h b/spine-cpp/include/spine/SlotCurveTimeline.h index e009330d8..f234dffb4 100644 --- a/spine-cpp/include/spine/SlotCurveTimeline.h +++ b/spine-cpp/include/spine/SlotCurveTimeline.h @@ -49,8 +49,8 @@ namespace spine { virtual ~SlotCurveTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; virtual int getSlotIndex() override; @@ -58,7 +58,7 @@ namespace spine { protected: /// Applies the timeline to the slot pose. - virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) = 0; + virtual void _apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) = 0; int _slotIndex; }; diff --git a/spine-cpp/include/spine/SlotData.h b/spine-cpp/include/spine/SlotData.h index 373291131..27d082ba5 100644 --- a/spine-cpp/include/spine/SlotData.h +++ b/spine-cpp/include/spine/SlotData.h @@ -67,7 +67,7 @@ namespace spine { public: SlotData(int index, const String &name, BoneData &boneData); - /// The index of the slot in Skeleton::getSlots(). + /// The Skeleton::getSlots() index. int getIndex(); /// The bone this slot belongs to. diff --git a/spine-cpp/include/spine/Timeline.h b/spine-cpp/include/spine/Timeline.h index 777ee3c9d..ca8adfe75 100644 --- a/spine-cpp/include/spine/Timeline.h +++ b/spine-cpp/include/spine/Timeline.h @@ -32,8 +32,6 @@ #include #include -#include -#include #include #include @@ -50,19 +48,38 @@ namespace spine { virtual ~Timeline(); - /// Sets the value(s) for the specified time. - /// @param skeleton The skeleton the timeline is being applied to. This provides access to the bones, slots, and other skeleton components the timeline may change. - /// @param lastTime lastTime The time this timeline was last applied. Timelines such as EventTimeline trigger only at specific times rather than every frame. In that case, the timeline triggers everything between lastTime (exclusive) and time (inclusive). - /// @param time The time within the animation. Most timelines find the key before and the key after this time so they can interpolate between the keys. - /// @param events If any events are fired, they are added to this array. Can be NULL to ignore firing events or if the timeline does not fire events. May be NULL. - /// @param alpha alpha 0 applies the current or setup pose value (depending on pose parameter). 1 applies the timeline - /// value. Between 0 and 1 applies a value between the current or setup pose and the timeline value. By adjusting alpha over - /// time, an animation can be mixed in or out. alpha can also be useful to apply animations on top of each other (layered). - /// @param blend 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. - /// @param appliedPose True to modify the applied pose. - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) = 0; + /// Applies this timeline to the skeleton. + /// @param skeleton The skeleton the timeline is applied to. This provides access to the bones, slots, and other skeleton + /// components the timelines may change. + /// @param lastTime The last time in seconds this timeline was applied. Some timelines trigger only at discrete times, in + /// which case all keys are triggered between lastTime (exclusive) and time (inclusive). Pass -1 the first time a + /// timeline is applied to ensure frame 0 is triggered. + /// @param time The time in seconds the skeleton is being posed for. Timelines find the frame before and after this time and + /// interpolate between the frame values. + /// @param events If any events are fired, they are added to this list. Can be NULL to ignore fired events or if no timelines + /// fire events. + /// @param alpha 0 applies setup or current values (depending on fromSetup), 1 uses timeline values, and intermediate values + /// interpolate between them. Adjusting alpha over time can mix a timeline in or out. + /// @param fromSetup If true, alpha transitions between setup and timeline values, setup values are used before the first + /// frame (current values are not used). If false, alpha transitions between current and timeline values, no change + /// is made before the first frame. + /// @param add If true, for timelines that support it, their values are added to the setup or current values (depending on + /// fromSetup). + /// @param out True when the animation is mixing out, else it is mixing in. Used by timelines that perform instant + /// transitions. + /// @param appliedPose True to modify the applied pose, else the pose is modified. + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) = 0; + + /// True if this timeline supports additive blending. + bool getAdditive() { + return _additive; + } + + /// True if this timeline sets values instantaneously and does not support interpolation between frames. + bool getInstant() { + return _instant; + } size_t getFrameEntries(); @@ -80,6 +97,8 @@ namespace spine { Array _propertyIds; Array _frames; size_t _frameEntries; + bool _additive; + bool _instant; }; } diff --git a/spine-cpp/include/spine/TransformConstraintTimeline.h b/spine-cpp/include/spine/TransformConstraintTimeline.h index 097f63503..33c33f67b 100644 --- a/spine-cpp/include/spine/TransformConstraintTimeline.h +++ b/spine-cpp/include/spine/TransformConstraintTimeline.h @@ -35,7 +35,7 @@ namespace spine { - /// Changes a transform constraint's TransformConstraintPose::getMixRotate(), TransformConstraintPose::getMixX(), + /// Changes TransformConstraintPose::getMixRotate(), TransformConstraintPose::getMixX(), /// TransformConstraintPose::getMixY(), TransformConstraintPose::getMixScaleX(), /// TransformConstraintPose::getMixScaleY(), and TransformConstraintPose::getMixShearY(). class SP_API TransformConstraintTimeline : public CurveTimeline, public ConstraintTimeline { @@ -50,8 +50,8 @@ namespace spine { virtual ~TransformConstraintTimeline(); - virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) override; + virtual void apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) override; /// Sets the time, rotate mix, translate mix, scale mix, and shear mix for the specified frame. /// @param frame Between 0 and frameCount, inclusive. diff --git a/spine-cpp/include/spine/TranslateTimeline.h b/spine-cpp/include/spine/TranslateTimeline.h index f642d777c..b83806311 100644 --- a/spine-cpp/include/spine/TranslateTimeline.h +++ b/spine-cpp/include/spine/TranslateTimeline.h @@ -46,7 +46,7 @@ namespace spine { explicit TranslateTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; /// Changes a bone's local X translation. @@ -61,7 +61,7 @@ namespace spine { explicit TranslateXTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; /// Changes a bone's local Y translation. @@ -76,7 +76,7 @@ namespace spine { explicit TranslateYTimeline(size_t frameCount, size_t bezierCount, int boneIndex); protected: - virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) override; + virtual void _apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) override; }; } diff --git a/spine-cpp/include/spine/VertexAttachment.h b/spine-cpp/include/spine/VertexAttachment.h index 9fa7c0922..b836b2e2f 100644 --- a/spine-cpp/include/spine/VertexAttachment.h +++ b/spine-cpp/include/spine/VertexAttachment.h @@ -38,7 +38,7 @@ namespace spine { class Slot; class Skeleton; - /// An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's + /// An attachment with vertices that are transformed by one or more bones and can be deformed by /// SlotPose::getDeform(). class SP_API VertexAttachment : public Attachment { friend class SkeletonBinary; @@ -55,8 +55,8 @@ namespace spine { virtual ~VertexAttachment(); - /// Transforms the attachment's local vertices to world coordinates. If the slot's SlotPose::getDeform() - /// is not empty, it is used to deform the vertices. + /// Transforms the attachment's local vertices to world coordinates. If the SlotPose::getDeform() is not + /// empty, it is used to deform the vertices. /// /// See https://esotericsoftware.com/spine-runtime-skeletons#World-transforms World transforms in the Spine /// Runtimes Guide. @@ -74,10 +74,16 @@ namespace spine { /// Gets a unique ID for this attachment. int getId(); + /// The bones that affect the vertices. The entries are, for each vertex, the number of bones affecting the + /// vertex followed by that many bone indices, which is the Skeleton::getBones() index. Empty if this attachment + /// has no weights. Array &getBones(); void setBones(Array &bones); + /// The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are x,y pairs + /// for each vertex. For a weighted attachment, the values are x,y,weight triplets for each bone affecting each + /// vertex. Array &getVertices(); void setVertices(Array &vertices); diff --git a/spine-cpp/include/spine/spine.h b/spine-cpp/include/spine/spine.h index 4b43f782d..38a59b0ab 100644 --- a/spine-cpp/include/spine/spine.h +++ b/spine-cpp/include/spine/spine.h @@ -73,8 +73,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/spine-cpp/src/spine/Animation.cpp b/spine-cpp/src/spine/Animation.cpp index 6428fceed..d7ff4aa7f 100644 --- a/spine-cpp/src/spine/Animation.cpp +++ b/spine-cpp/src/spine/Animation.cpp @@ -57,8 +57,8 @@ Animation::~Animation() { ArrayUtils::deleteElements(_timelines); } -void Animation::apply(Skeleton &skeleton, float lastTime, float time, bool loop, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void Animation::apply(Skeleton &skeleton, float lastTime, float time, bool loop, Array *events, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { if (loop && _duration != 0) { time = MathUtil::fmod(time, _duration); if (lastTime > 0) { @@ -67,7 +67,7 @@ void Animation::apply(Skeleton &skeleton, float lastTime, float time, bool loop, } for (size_t i = 0, n = _timelines.size(); i < n; ++i) { - _timelines[i]->apply(skeleton, lastTime, time, events, alpha, blend, direction, appliedPose); + _timelines[i]->apply(skeleton, lastTime, time, events, alpha, fromSetup, add, out, appliedPose); } } diff --git a/spine-cpp/src/spine/AnimationState.cpp b/spine-cpp/src/spine/AnimationState.cpp index b92c86b28..1e1f0c8ed 100644 --- a/spine-cpp/src/spine/AnimationState.cpp +++ b/spine-cpp/src/spine/AnimationState.cpp @@ -73,11 +73,11 @@ void dummyOnAnimationEventFunc(AnimationState *state, spine::EventType type, Tra #endif TrackEntry::TrackEntry() - : _animation(NULL), _previous(NULL), _next(NULL), _mixingFrom(NULL), _mixingTo(0), _trackIndex(0), _loop(false), _holdPrevious(false), - _reverse(false), _shortestRotation(false), _eventThreshold(0), _mixAttachmentThreshold(0), _alphaAttachmentThreshold(0), + : _animation(NULL), _previous(NULL), _next(NULL), _mixingFrom(NULL), _mixingTo(0), _trackIndex(0), _loop(false), _additive(false), + _reverse(false), _shortestRotation(false), _keepHold(false), _eventThreshold(0), _mixAttachmentThreshold(0), _alphaAttachmentThreshold(0), _mixDrawOrderThreshold(0), _animationStart(0), _animationEnd(0), _animationLast(0), _nextAnimationLast(0), _delay(0), _trackTime(0), - _trackLast(0), _nextTrackLast(0), _trackEnd(0), _timeScale(1.0f), _alpha(0), _mixTime(0), _mixDuration(0), _interruptAlpha(0), _totalAlpha(0), - _mixBlend(MixBlend_Replace), _listener(dummyOnAnimationEventFunc), SP_ANIMATION_LISTENER_USER_DATA_CTOR _listenerObject(NULL), _state(NULL) { + _trackLast(0), _nextTrackLast(0), _trackEnd(0), _timeScale(1.0f), _alpha(0), _mixTime(0), _mixDuration(0), _totalAlpha(0), + _listener(dummyOnAnimationEventFunc), SP_ANIMATION_LISTENER_USER_DATA_CTOR _listenerObject(NULL), _state(NULL) { } TrackEntry::~TrackEntry() { @@ -107,12 +107,12 @@ void TrackEntry::setLoop(bool inValue) { _loop = inValue; } -bool TrackEntry::getHoldPrevious() { - return _holdPrevious; +bool TrackEntry::getAdditive() { + return _additive; } -void TrackEntry::setHoldPrevious(bool inValue) { - _holdPrevious = inValue; +void TrackEntry::setAdditive(bool inValue) { + _additive = inValue; } bool TrackEntry::getReverse() { @@ -267,12 +267,7 @@ void TrackEntry::setMixDuration(float inValue) { void TrackEntry::setMixDuration(float mixDuration, float delay) { _mixDuration = mixDuration; - if (delay <= 0) { - if (_previous != nullptr) - delay = MathUtil::max(delay + _previous->getTrackComplete() - mixDuration, 0.0f); - else - delay = 0; - } + if (delay <= 0) delay = _previous == nullptr ? 0 : MathUtil::max(delay + _previous->getTrackComplete() - mixDuration, 0.0f); this->_delay = delay; } @@ -284,14 +279,6 @@ TrackEntry *TrackEntry::getMixingTo() { return _mixingTo; } -void TrackEntry::setMixBlend(MixBlend blend) { - _mixBlend = blend; -} - -MixBlend TrackEntry::getMixBlend() { - return _mixBlend; -} - void TrackEntry::resetRotationDirections() { _timelinesRotation.clear(); } @@ -569,20 +556,15 @@ bool AnimationState::apply(Skeleton &skeleton) { applied = true; - // Track 0 animations aren't for layering, so never use current values before the first key. - MixBlend blend = i == 0 ? MixBlend_First : current._mixBlend; - - // apply mixing from entries first. + // Apply mixing from entries first. float alpha = current._alpha; if (current._mixingFrom != NULL) { alpha *= applyMixingFrom(currentP, skeleton); } else if (current._trackTime >= current._trackEnd && current._next == NULL) { alpha = 0;// Set to setup pose the last time the entry will be applied. } - bool attachments = alpha >= current._alphaAttachmentThreshold; - - // apply current entry. + // Apply current entry. float animationLast = current._animationLast, animationTime = current.getAnimationTime(); float applyTime = animationTime; Array *applyEvents = &_events; @@ -592,19 +574,18 @@ bool AnimationState::apply(Skeleton &skeleton) { } size_t timelineCount = current._animation->_timelines.size(); Array &timelines = current._animation->_timelines; - if ((i == 0 && alpha == 1) || blend == MixBlend_Add) { - if (i == 0) attachments = true; + if (i == 0 && alpha == 1) { for (size_t ii = 0; ii < timelineCount; ++ii) { Timeline *timeline = timelines[ii]; if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) - applyAttachmentTimeline(static_cast(timeline), skeleton, applyTime, blend, false, attachments); + applyAttachmentTimeline(static_cast(timeline), skeleton, applyTime, true, false, true); else - timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection_In, false); + timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, true, false, false, false); } } else { Array &timelineMode = current._timelineMode; - - bool shortestRotation = current._shortestRotation; + bool attachments = alpha >= current._alphaAttachmentThreshold; + bool add = current._additive, shortestRotation = add || current._shortestRotation; bool firstFrame = !shortestRotation && current._timelinesRotation.size() != timelines.size() << 1; if (firstFrame) current._timelinesRotation.setSize(timelines.size() << 1, 0); Array &timelinesRotation = current._timelinesRotation; @@ -613,15 +594,15 @@ bool AnimationState::apply(Skeleton &skeleton) { Timeline *timeline = timelines[ii]; assert(timeline); - MixBlend timelineBlend = timelineMode[ii] == Subsequent ? current._mixBlend : MixBlend_Setup; + bool fromSetup = (timelineMode[ii] & First) != 0; if (!shortestRotation && timeline->getRTTI().isExactly(RotateTimeline::rtti)) - applyRotateTimeline(static_cast(timeline), skeleton, applyTime, alpha, timelineBlend, timelinesRotation, - ii << 1, firstFrame); + applyRotateTimeline(static_cast(timeline), skeleton, applyTime, alpha, fromSetup, timelinesRotation, ii << 1, + firstFrame); else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) - applyAttachmentTimeline(static_cast(timeline), skeleton, applyTime, blend, false, attachments); + applyAttachmentTimeline(static_cast(timeline), skeleton, applyTime, fromSetup, false, attachments); else - timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend, MixDirection_In, false); + timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, fromSetup, add, false, false); } } @@ -833,18 +814,16 @@ Animation *AnimationState::getEmptyAnimation() { return &ret; } -void AnimationState::applyAttachmentTimeline(AttachmentTimeline *attachmentTimeline, Skeleton &skeleton, float time, MixBlend blend, bool out, +void AnimationState::applyAttachmentTimeline(AttachmentTimeline *attachmentTimeline, Skeleton &skeleton, float time, bool fromSetup, bool out, bool attachments) { Slot *slot = skeleton.getSlots()[attachmentTimeline->getSlotIndex()]; if (!slot->getBone().isActive()) return; - Array &frames = attachmentTimeline->getFrames(); - if (out) { - if (blend == MixBlend_Setup) setAttachment(skeleton, *slot, slot->getData().getAttachmentName(), attachments); - } else if (time < frames[0]) { - if (blend == MixBlend_Setup || blend == MixBlend_First) setAttachment(skeleton, *slot, slot->getData().getAttachmentName(), attachments); + if (out || time < attachmentTimeline->getFrames()[0]) { + if (fromSetup) setAttachment(skeleton, *slot, slot->getData().getAttachmentName(), attachments); } else { - setAttachment(skeleton, *slot, attachmentTimeline->getAttachmentNames()[Animation::search(frames, time)], attachments); + setAttachment(skeleton, *slot, attachmentTimeline->getAttachmentNames()[Animation::search(attachmentTimeline->getFrames(), time)], + attachments); } /* If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.*/ @@ -852,12 +831,12 @@ void AnimationState::applyAttachmentTimeline(AttachmentTimeline *attachmentTimel } -void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha, MixBlend blend, +void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha, bool fromSetup, Array &timelinesRotation, size_t i, bool firstFrame) { if (firstFrame) timelinesRotation[i] = 0; if (alpha == 1) { - static_cast(rotateTimeline)->apply(skeleton, 0, time, NULL, 1, blend, MixDirection_In, false); + static_cast(rotateTimeline)->apply(skeleton, 0, time, NULL, 1, fromSetup, false, false, false); return; } @@ -866,21 +845,12 @@ void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleto BoneLocal &pose = bone->_pose; BoneLocal &setup = bone->_data._setup; Array &frames = rotateTimeline->_frames; - float r1, r2; if (time < frames[0]) { - switch (blend) { - case MixBlend_Setup: - pose._rotation = setup._rotation; - default: - return; - case MixBlend_First: - r1 = pose._rotation; - r2 = setup._rotation; - } - } else { - r1 = blend == MixBlend_Setup ? setup._rotation : pose._rotation; - r2 = setup._rotation + rotateTimeline->getCurveValue(time); + if (fromSetup) pose._rotation = setup._rotation; + return; } + float r1 = fromSetup ? setup._rotation : pose._rotation; + float r2 = setup._rotation + rotateTimeline->getCurveValue(time); // Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. float total, diff = r2 - r1; @@ -934,7 +904,9 @@ bool AnimationState::updateMixingFrom(TrackEntry *to, float delta) { if (from->_totalAlpha == 0 || to->_mixDuration == 0) { to->_mixingFrom = from->_mixingFrom; if (from->_mixingFrom) from->_mixingFrom->_mixingTo = to; - to->_interruptAlpha = from->_interruptAlpha; + if (from->_totalAlpha == 0) { + for (TrackEntry *next = to; next->_mixingTo != NULL; next = next->_mixingTo) next->_keepHold = true; + } _queue->end(from); } return finished; @@ -948,86 +920,53 @@ bool AnimationState::updateMixingFrom(TrackEntry *to, float delta) { float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton) { TrackEntry *from = to->_mixingFrom; - if (from->_mixingFrom != NULL) applyMixingFrom(from, skeleton); + float fromMix = from->_mixingFrom != NULL ? applyMixingFrom(from, skeleton) : 1; + float mix = to->_mixDuration == 0 ? 1 : MathUtil::min(1.0f, to->_mixTime / to->_mixDuration); - float mix; - if (to->_mixDuration == 0)// Single frame mix to undo mixingFrom changes. - mix = 1; - else { - mix = to->_mixTime / to->_mixDuration; - if (mix > 1) { - mix = 1; - } - } + float a = from->_alpha * fromMix, keep = 1 - mix * to->_alpha; + float alphaMix = a * (1 - mix), alphaHold = keep > 0 ? alphaMix / keep : a; - bool attachments = mix < from->_mixAttachmentThreshold, drawOrder = mix < from->_mixDrawOrderThreshold; Array &timelines = from->_animation->_timelines; size_t timelineCount = timelines.size(); - float alphaHold = from->_alpha * to->_interruptAlpha, alphaMix = alphaHold * (1 - mix); + Array &timelineMode = from->_timelineMode; + Array &timelineHoldMix = from->_timelineHoldMix; + + bool attachments = mix < from->_mixAttachmentThreshold, drawOrder = mix < from->_mixDrawOrderThreshold; + bool add = from->_additive, shortestRotation = add || from->_shortestRotation; + bool firstFrame = !shortestRotation && from->_timelinesRotation.size() != timelines.size() << 1; + if (firstFrame) from->_timelinesRotation.setSize(timelines.size() << 1, 0); + Array &timelinesRotation = from->_timelinesRotation; + float animationLast = from->_animationLast, animationTime = from->getAnimationTime(); float applyTime = animationTime; Array *events = NULL; - if (from->_reverse) { + if (from->_reverse) applyTime = from->_animation->_duration - applyTime; - } else { - if (mix < from->_eventThreshold) events = &_events; - } + else if (mix < from->_eventThreshold) + events = &_events; - MixBlend blend = from->_mixBlend; - if (blend == MixBlend_Add) { - for (size_t i = 0; i < timelineCount; i++) - timelines[i]->apply(skeleton, animationLast, applyTime, events, alphaMix, blend, MixDirection_Out, false); - } else { - Array &timelineMode = from->_timelineMode; - Array &timelineHoldMix = from->_timelineHoldMix; - - bool shortestRotation = from->_shortestRotation; - bool firstFrame = !shortestRotation && from->_timelinesRotation.size() != timelines.size() << 1; - if (firstFrame) from->_timelinesRotation.setSize(timelines.size() << 1, 0); - - Array &timelinesRotation = from->_timelinesRotation; - - from->_totalAlpha = 0; - for (size_t i = 0; i < timelineCount; i++) { - Timeline *timeline = timelines[i]; - MixDirection direction = MixDirection_Out; - MixBlend timelineBlend; - float alpha; - switch (timelineMode[i]) { - case Subsequent: - if (!drawOrder && (timeline->getRTTI().isExactly(DrawOrderTimeline::rtti))) continue; - timelineBlend = blend; - alpha = alphaMix; - break; - case First: - timelineBlend = MixBlend_Setup; - alpha = alphaMix; - break; - case HoldSubsequent: - timelineBlend = blend; - alpha = alphaHold; - break; - case HoldFirst: - timelineBlend = MixBlend_Setup; - alpha = alphaHold; - break; - default: - timelineBlend = MixBlend_Setup; - TrackEntry *holdMix = timelineHoldMix[i]; - alpha = alphaHold * MathUtil::max(0.0f, 1.0f - holdMix->_mixTime / holdMix->_mixDuration); - break; - } - from->_totalAlpha += alpha; - if (!shortestRotation && (timeline->getRTTI().isExactly(RotateTimeline::rtti))) { - applyRotateTimeline((RotateTimeline *) timeline, skeleton, applyTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame); - } else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) { - applyAttachmentTimeline(static_cast(timeline), skeleton, applyTime, timelineBlend, true, - attachments && alpha >= from->_alphaAttachmentThreshold); - } else { - if (drawOrder && timeline->getRTTI().isExactly(DrawOrderTimeline::rtti) && timelineBlend == MixBlend_Setup) - direction = MixDirection_In; - timeline->apply(skeleton, animationLast, applyTime, events, alpha, timelineBlend, direction, false); - } + from->_totalAlpha = 0; + for (size_t i = 0; i < timelineCount; i++) { + Timeline *timeline = timelines[i]; + int mode = timelineMode[i]; + float alpha; + if ((mode & Hold) != 0) { + TrackEntry *holdMix = timelineHoldMix[i]; + alpha = holdMix == NULL ? alphaHold : alphaHold * MathUtil::max(0.0f, 1.0f - holdMix->_mixTime / holdMix->_mixDuration); + } else { + if (!drawOrder && timeline->getRTTI().isExactly(DrawOrderTimeline::rtti)) continue; + alpha = alphaMix; + } + from->_totalAlpha += alpha; + bool fromSetup = (mode & First) != 0; + if (!shortestRotation && timeline->getRTTI().isExactly(RotateTimeline::rtti)) { + applyRotateTimeline((RotateTimeline *) timeline, skeleton, applyTime, alpha, fromSetup, timelinesRotation, i << 1, firstFrame); + } else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) { + applyAttachmentTimeline(static_cast(timeline), skeleton, applyTime, fromSetup, true, + attachments && alpha >= from->_alphaAttachmentThreshold); + } else { + bool out = !drawOrder || !timeline->getRTTI().isExactly(DrawOrderTimeline::rtti) || !fromSetup; + timeline->apply(skeleton, animationLast, applyTime, events, alpha, fromSetup, add, out, false); } } @@ -1036,9 +975,9 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton) { } _events.clear(); + from->_nextAnimationLast = animationTime; from->_nextTrackLast = from->_trackTime; - return mix; } @@ -1094,12 +1033,6 @@ void AnimationState::setCurrent(size_t index, TrackEntry *current, bool interrup current->_mixingFrom = from; from->_mixingTo = current; current->_mixTime = 0; - - // Store interrupted mix percentage. - if (from->_mixingFrom != NULL && from->_mixDuration > 0) { - current->_interruptAlpha *= MathUtil::min(1.0f, from->_mixTime / from->_mixDuration); - } - from->_timelinesRotation.clear();// Reset rotation for mixing out, in case entry was mixed in. } @@ -1120,8 +1053,8 @@ TrackEntry *AnimationState::newTrackEntry(size_t trackIndex, Animation *animatio entry._trackIndex = (int) trackIndex; entry._animation = animation; entry._loop = loop; - entry._holdPrevious = 0; + entry._additive = false; entry._reverse = false; entry._shortestRotation = false; @@ -1145,9 +1078,8 @@ TrackEntry *AnimationState::newTrackEntry(size_t trackIndex, Animation *animatio entry._alpha = 1; entry._mixTime = 0; entry._mixDuration = (last == NULL) ? 0 : _data->getMix(*last->_animation, *animation); - entry._interruptAlpha = 1; entry._totalAlpha = 0; - entry._mixBlend = MixBlend_Replace; + entry._keepHold = false; return entryP; } @@ -1164,8 +1096,6 @@ void AnimationState::clearNext(TrackEntry *entry) { void AnimationState::animationsChanged() { _animationsChanged = false; - _propertyIDs.clear(); - for (size_t i = 0, n = _tracks.size(); i < n; ++i) { TrackEntry *entry = _tracks[i]; if (!entry) continue; @@ -1173,60 +1103,62 @@ void AnimationState::animationsChanged() { while (entry->_mixingFrom != NULL) entry = entry->_mixingFrom; do { - if (entry->_mixingTo == NULL || entry->_mixBlend != MixBlend_Add) computeHold(entry); + computeHold(entry); entry = entry->_mixingTo; } while (entry != NULL); } + _propertyIDs.clear(); } void AnimationState::computeHold(TrackEntry *entry) { - TrackEntry *to = entry->_mixingTo; Array &timelines = entry->_animation->_timelines; size_t timelinesCount = timelines.size(); Array &timelineMode = entry->_timelineMode; timelineMode.setSize(timelinesCount, 0); + entry->_timelineHoldMix.clear(); Array &timelineHoldMix = entry->_timelineHoldMix; - timelineHoldMix.setSize(timelinesCount, 0); + timelineHoldMix.setSize(timelinesCount, NULL); PropertyId drawOrderPropertyId = DrawOrderTimeline::getPropertyId(); + bool add = entry->_additive, keepHold = entry->_keepHold; + TrackEntry *to = entry->_mixingTo; - if (to != NULL && to->_holdPrevious) { - for (size_t i = 0; i < timelinesCount; i++) { - bool first = _propertyIDs.addAll(timelines[i]->getPropertyIds(), true); - if (first && timelines[i]->getRTTI().isExactly(DrawOrderFolderTimeline::rtti) && _propertyIDs.containsKey(drawOrderPropertyId)) - first = false; - timelineMode[i] = first ? HoldFirst : HoldSubsequent; - } - return; - } - - // outer: - size_t i = 0; -continue_outer: - for (; i < timelinesCount; ++i) { + for (size_t i = 0; i < timelinesCount; ++i) { Timeline *timeline = timelines[i]; Array &ids = timeline->getPropertyIds(); - if (!_propertyIDs.addAll(ids, true)) { - timelineMode[i] = Subsequent; - } else if (timeline->getRTTI().isExactly(DrawOrderFolderTimeline::rtti) && _propertyIDs.containsKey(drawOrderPropertyId)) { - timelineMode[i] = Subsequent; - } else { - if (to == NULL || timeline->getRTTI().isExactly(AttachmentTimeline::rtti) || timeline->getRTTI().isExactly(DrawOrderTimeline::rtti) || - timeline->getRTTI().isExactly(DrawOrderFolderTimeline::rtti) || timeline->getRTTI().isExactly(EventTimeline::rtti) || - !to->_animation->hasTimeline(ids)) { - timelineMode[i] = First; - } else { - for (TrackEntry *next = to->_mixingTo; next != NULL; next = next->_mixingTo) { - if (next->_animation->hasTimeline(ids)) continue; - if (next->_mixDuration > 0) { - timelineMode[i] = HoldMix; - timelineHoldMix[i] = next; - i++; - goto continue_outer;// continue outer; - } - break; - } - timelineMode[i] = HoldFirst; + bool first = _propertyIDs.addAll(ids, true) && + !(timeline->getRTTI().isExactly(DrawOrderFolderTimeline::rtti) && _propertyIDs.containsKey(drawOrderPropertyId)); + + if (add && timeline->getAdditive()) { + timelineMode[i] = first ? First : Subsequent; + continue; + } + + // Check if an earlier entry on this track keys this property. + bool found = false; + for (TrackEntry *from = entry->_mixingFrom; from != NULL; from = from->_mixingFrom) { + if (from->_animation->hasTimeline(ids)) { + timelineMode[i] = Subsequent; + found = true; + break; } } + if (found) continue; + + // Hold if the next entry will overwrite this property. + int mode; + if (to == NULL || timeline->getInstant() || (to->_additive && timeline->getAdditive()) || !to->_animation->hasTimeline(ids)) + mode = first ? First : Subsequent; + else { + mode = first ? HoldFirst : Hold; + // Find next entry that doesn't overwrite this property. Its mix fades out the hold. + for (TrackEntry *next = to->_mixingTo; next != NULL; next = next->_mixingTo) { + if ((next->_additive && timeline->getAdditive()) || !next->_animation->hasTimeline(ids)) { + if (next->_mixDuration > 0) timelineHoldMix[i] = next; + break; + } + } + } + if (keepHold) mode = (mode & ~Hold) | (timelineMode[i] & Hold); + timelineMode[i] = mode; } } diff --git a/spine-cpp/src/spine/AttachmentTimeline.cpp b/spine-cpp/src/spine/AttachmentTimeline.cpp index 485a56969..4636a5cbb 100644 --- a/spine-cpp/src/spine/AttachmentTimeline.cpp +++ b/spine-cpp/src/spine/AttachmentTimeline.cpp @@ -46,6 +46,7 @@ RTTI_IMPL_MULTI(AttachmentTimeline, Timeline, SlotTimeline) AttachmentTimeline::AttachmentTimeline(size_t frameCount, int slotIndex) : Timeline(frameCount, 1), SlotTimeline(), _slotIndex(slotIndex) { PropertyId ids[] = {((PropertyId) Property_Attachment << 32) | slotIndex}; setPropertyIds(ids, 1); + _instant = true; _attachmentNames.ensureCapacity(frameCount); for (size_t i = 0; i < frameCount; ++i) { @@ -60,20 +61,19 @@ void AttachmentTimeline::setAttachment(Skeleton &skeleton, SlotPose &pose, Strin pose.setAttachment(attachmentName == NULL || attachmentName->isEmpty() ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName)); } -void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); SP_UNUSED(alpha); + SP_UNUSED(add); Slot *slot = skeleton._slots[_slotIndex]; if (!slot->_bone.isActive()) return; SlotPose &pose = appliedPose ? *slot->_applied : slot->_pose; - if (direction == MixDirection_Out) { - if (blend == MixBlend_Setup) setAttachment(skeleton, pose, &slot->_data._attachmentName); - } else if (time < _frames[0]) { - if (blend == MixBlend_Setup || blend == MixBlend_First) setAttachment(skeleton, pose, &slot->_data._attachmentName); + if (out || time < _frames[0]) { + if (fromSetup) setAttachment(skeleton, pose, &slot->_data._attachmentName); } else { setAttachment(skeleton, pose, &_attachmentNames[Animation::search(_frames, time)]); } diff --git a/spine-cpp/src/spine/BoneTimeline.cpp b/spine-cpp/src/spine/BoneTimeline.cpp index 1b89d15db..2a2fdd20e 100644 --- a/spine-cpp/src/spine/BoneTimeline.cpp +++ b/spine-cpp/src/spine/BoneTimeline.cpp @@ -51,16 +51,17 @@ BoneTimeline1::BoneTimeline1(size_t frameCount, size_t bezierCount, int boneInde : CurveTimeline1(frameCount, bezierCount), BoneTimeline(boneIndex), _boneIndex(boneIndex) { PropertyId ids[] = {((PropertyId) property << 32) | boneIndex}; setPropertyIds(ids, 1); + _additive = true; } -void BoneTimeline1::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, MixDirection direction, +void BoneTimeline1::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); Bone *bone = skeleton._bones[_boneIndex]; if (bone->isActive()) { - _apply(appliedPose ? *bone->_applied : bone->_pose, bone->_data._setup, time, alpha, blend, direction); + _apply(appliedPose ? *bone->_applied : bone->_pose, bone->_data._setup, time, alpha, fromSetup, add, out); } } @@ -70,16 +71,17 @@ BoneTimeline2::BoneTimeline2(size_t frameCount, size_t bezierCount, int boneInde : CurveTimeline(frameCount, BoneTimeline2::ENTRIES, bezierCount), BoneTimeline(boneIndex), _boneIndex(boneIndex) { PropertyId ids[] = {((PropertyId) property1 << 32) | boneIndex, ((PropertyId) property2 << 32) | boneIndex}; setPropertyIds(ids, 2); + _additive = true; } -void BoneTimeline2::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, MixDirection direction, +void BoneTimeline2::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); Bone *bone = skeleton._bones[_boneIndex]; if (bone->isActive()) { - _apply(appliedPose ? *bone->_applied : bone->_pose, bone->_data._setup, time, alpha, blend, direction); + _apply(appliedPose ? *bone->_applied : bone->_pose, bone->_data._setup, time, alpha, fromSetup, add, out); } } diff --git a/spine-cpp/src/spine/ColorTimeline.cpp b/spine-cpp/src/spine/ColorTimeline.cpp index b3992d868..6263f57c6 100644 --- a/spine-cpp/src/spine/ColorTimeline.cpp +++ b/spine-cpp/src/spine/ColorTimeline.cpp @@ -59,20 +59,12 @@ void RGBATimeline::setFrame(int frame, float time, float r, float g, float b, fl _frames[frame + A] = a; } -void RGBATimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) { +void RGBATimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) { + SP_UNUSED(add); Color &color = pose._color; if (time < _frames[0]) { - Color &setup = slot._data._setup._color; - switch (blend) { - case MixBlend_Setup: - color.set(setup); - return; - case MixBlend_First: - color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha, (setup.a - color.a) * alpha); - return; - default: - return; - } + if (fromSetup) color.set(slot._data._setup._color); + return; } float r, g, b, a; @@ -111,8 +103,12 @@ void RGBATimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, M if (alpha == 1) color.set(r, g, b, a); else { - if (blend == MixBlend_Setup) color.set(slot._data._setup._color); - color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + if (fromSetup) { + Color &setup = slot._data._setup._color; + color.set(setup.r + (r - setup.r) * alpha, setup.g + (g - setup.g) * alpha, setup.b + (b - setup.b) * alpha, + setup.a + (a - setup.a) * alpha); + } else + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); } } @@ -134,65 +130,58 @@ void RGBTimeline::setFrame(int frame, float time, float r, float g, float b) { _frames[frame + B] = b; } -void RGBTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) { +void RGBTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) { + SP_UNUSED(add); Color &color = pose._color; float r, g, b; if (time < _frames[0]) { - Color &setup = slot._data._setup._color; - switch (blend) { - case MixBlend_Setup: - color.r = setup.r; - color.g = setup.g; - color.b = setup.b; - return; - case MixBlend_First: - r = color.r + (setup.r - color.r) * alpha; - g = color.g + (setup.g - color.g) * alpha; - b = color.b + (setup.b - color.b) * alpha; - break; - default: - return; - } - } else { - int i = Animation::search(_frames, time, ENTRIES); - int curveType = (int) _curves[i >> 2]; - switch (curveType) { - case LINEAR: { - float before = _frames[i]; - r = _frames[i + R]; - g = _frames[i + G]; - b = _frames[i + B]; - float t = (time - before) / (_frames[i + ENTRIES] - before); - r += (_frames[i + ENTRIES + R] - r) * t; - g += (_frames[i + ENTRIES + G] - g) * t; - b += (_frames[i + ENTRIES + B] - b) * t; - break; - } - case STEPPED: { - r = _frames[i + R]; - g = _frames[i + G]; - b = _frames[i + B]; - break; - } - default: { - r = getBezierValue(time, i, R, curveType - BEZIER); - g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER); - b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER); - break; - } + if (fromSetup) { + Color &setup = slot._data._setup._color; + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; } + return; + } - if (alpha != 1) { - if (blend == MixBlend_Setup) { - Color &setup = slot._data._setup._color; - r = setup.r + (r - setup.r) * alpha; - g = setup.g + (g - setup.g) * alpha; - b = setup.b + (b - setup.b) * alpha; - } else { - r = color.r + (r - color.r) * alpha; - g = color.g + (g - color.g) * alpha; - b = color.b + (b - color.b) * alpha; - } + int i = Animation::search(_frames, time, ENTRIES); + int curveType = (int) _curves[i >> 2]; + switch (curveType) { + case LINEAR: { + float before = _frames[i]; + r = _frames[i + R]; + g = _frames[i + G]; + b = _frames[i + B]; + float t = (time - before) / (_frames[i + ENTRIES] - before); + r += (_frames[i + ENTRIES + R] - r) * t; + g += (_frames[i + ENTRIES + G] - g) * t; + b += (_frames[i + ENTRIES + B] - b) * t; + break; + } + case STEPPED: { + r = _frames[i + R]; + g = _frames[i + G]; + b = _frames[i + B]; + break; + } + default: { + r = getBezierValue(time, i, R, curveType - BEZIER); + g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER); + b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER); + break; + } + } + + if (alpha != 1) { + if (fromSetup) { + Color &setup = slot._data._setup._color; + r = setup.r + (r - setup.r) * alpha; + g = setup.g + (g - setup.g) * alpha; + b = setup.b + (b - setup.b) * alpha; + } else { + r = color.r + (r - color.r) * alpha; + g = color.g + (g - color.g) * alpha; + b = color.b + (b - color.b) * alpha; } } color.r = r < 0 ? 0 : (r > 1 ? 1 : r); @@ -219,38 +208,29 @@ void AlphaTimeline::setSlotIndex(int inValue) { _slotIndex = inValue; } -void AlphaTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, MixDirection direction, +void AlphaTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(add); + SP_UNUSED(out); Slot *slot = skeleton._slots[_slotIndex]; if (!slot->_bone._active) return; Color &color = (appliedPose ? *slot->_applied : slot->_pose)._color; - float a; if (time < _frames[0]) { - Color &setup = slot->_data._setup._color; - switch (blend) { - case MixBlend_Setup: - color.a = setup.a; - return; - case MixBlend_First: - a = color.a + (setup.a - color.a) * alpha; - break; - default: - return; - } - } else { - a = getCurveValue(time); - if (alpha != 1) { - if (blend == MixBlend_Setup) { - Color &setup = slot->_data._setup._color; - a = setup.a + (a - setup.a) * alpha; - } else - a = color.a + (a - color.a) * alpha; - } + if (fromSetup) color.a = slot->_data._setup._color.a; + return; + } + + float a = getCurveValue(time); + if (alpha != 1) { + if (fromSetup) { + Color &setup = slot->_data._setup._color; + a = setup.a + (a - setup.a) * alpha; + } else + a = color.a + (a - color.a) * alpha; } color.a = a < 0 ? 0 : (a > 1 ? 1 : a); } @@ -278,93 +258,84 @@ void RGBA2Timeline::setFrame(int frame, float time, float r, float g, float b, f _frames[frame + B2] = b2; } -void RGBA2Timeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) { +void RGBA2Timeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) { + SP_UNUSED(add); Color &light = pose._color; Color &dark = pose._darkColor; float r2, g2, b2; if (time < _frames[0]) { + if (fromSetup) { + SlotPose &setup = slot._data._setup; + light.set(setup._color); + Color &setupDark = setup._darkColor; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + return; + } + + float r, g, b, a; + int i = Animation::search(_frames, time, ENTRIES); + int curveType = (int) _curves[i >> 3]; + switch (curveType) { + case LINEAR: { + float before = _frames[i]; + r = _frames[i + R]; + g = _frames[i + G]; + b = _frames[i + B]; + a = _frames[i + A]; + r2 = _frames[i + R2]; + g2 = _frames[i + G2]; + b2 = _frames[i + B2]; + float t = (time - before) / (_frames[i + ENTRIES] - before); + r += (_frames[i + ENTRIES + R] - r) * t; + g += (_frames[i + ENTRIES + G] - g) * t; + b += (_frames[i + ENTRIES + B] - b) * t; + a += (_frames[i + ENTRIES + A] - a) * t; + r2 += (_frames[i + ENTRIES + R2] - r2) * t; + g2 += (_frames[i + ENTRIES + G2] - g2) * t; + b2 += (_frames[i + ENTRIES + B2] - b2) * t; + break; + } + case STEPPED: { + r = _frames[i + R]; + g = _frames[i + G]; + b = _frames[i + B]; + a = _frames[i + A]; + r2 = _frames[i + R2]; + g2 = _frames[i + G2]; + b2 = _frames[i + B2]; + break; + } + default: { + r = getBezierValue(time, i, R, curveType - BEZIER); + g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER); + b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER); + a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER); + r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 4 - BEZIER); + g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 5 - BEZIER); + b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 6 - BEZIER); + break; + } + } + + if (alpha == 1) + light.set(r, g, b, a); + else if (fromSetup) { SlotPose &setup = slot._data._setup; Color &setupLight = setup._color; + light.set(setupLight.r + (r - setupLight.r) * alpha, setupLight.g + (g - setupLight.g) * alpha, setupLight.b + (b - setupLight.b) * alpha, + setupLight.a + (a - setupLight.a) * alpha); Color &setupDark = setup._darkColor; - switch (blend) { - case MixBlend_Setup: - light.set(setupLight); - dark.r = setupDark.r; - dark.g = setupDark.g; - dark.b = setupDark.b; - /* Fall through. */ - default: - return; - case MixBlend_First: - light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha, - (setupLight.a - light.a) * alpha); - r2 = dark.r + (setupDark.r - dark.r) * alpha; - g2 = dark.g + (setupDark.g - dark.g) * alpha; - b2 = dark.b + (setupDark.b - dark.b) * alpha; - } + r2 = setupDark.r + (r2 - setupDark.r) * alpha; + g2 = setupDark.g + (g2 - setupDark.g) * alpha; + b2 = setupDark.b + (b2 - setupDark.b) * alpha; } else { - float r, g, b, a; - int i = Animation::search(_frames, time, ENTRIES); - int curveType = (int) _curves[i >> 3]; - switch (curveType) { - case LINEAR: { - float before = _frames[i]; - r = _frames[i + R]; - g = _frames[i + G]; - b = _frames[i + B]; - a = _frames[i + A]; - r2 = _frames[i + R2]; - g2 = _frames[i + G2]; - b2 = _frames[i + B2]; - float t = (time - before) / (_frames[i + ENTRIES] - before); - r += (_frames[i + ENTRIES + R] - r) * t; - g += (_frames[i + ENTRIES + G] - g) * t; - b += (_frames[i + ENTRIES + B] - b) * t; - a += (_frames[i + ENTRIES + A] - a) * t; - r2 += (_frames[i + ENTRIES + R2] - r2) * t; - g2 += (_frames[i + ENTRIES + G2] - g2) * t; - b2 += (_frames[i + ENTRIES + B2] - b2) * t; - break; - } - case STEPPED: { - r = _frames[i + R]; - g = _frames[i + G]; - b = _frames[i + B]; - a = _frames[i + A]; - r2 = _frames[i + R2]; - g2 = _frames[i + G2]; - b2 = _frames[i + B2]; - break; - } - default: { - r = getBezierValue(time, i, R, curveType - BEZIER); - g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER); - b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER); - a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER); - r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 4 - BEZIER); - g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 5 - BEZIER); - b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 6 - BEZIER); - break; - } - } - - if (alpha == 1) - light.set(r, g, b, a); - else if (blend == MixBlend_Setup) { - SlotPose &setup = slot._data._setup; - Color &setupLight = setup._color; - light.set(setupLight.r + (r - setupLight.r) * alpha, setupLight.g + (g - setupLight.g) * alpha, setupLight.b + (b - setupLight.b) * alpha, - setupLight.a + (a - setupLight.a) * alpha); - Color &setupDark = setup._darkColor; - r2 = setupDark.r + (r2 - setupDark.r) * alpha; - g2 = setupDark.g + (g2 - setupDark.g) * alpha; - b2 = setupDark.b + (b2 - setupDark.b) * alpha; - } else { - light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); - r2 = dark.r + (r2 - dark.r) * alpha; - g2 = dark.g + (g2 - dark.g) * alpha; - b2 = dark.b + (b2 - dark.b) * alpha; - } + light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); + r2 = dark.r + (r2 - dark.r) * alpha; + g2 = dark.g + (g2 - dark.g) * alpha; + b2 = dark.b + (b2 - dark.b) * alpha; } dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2); @@ -393,93 +364,84 @@ void RGB2Timeline::setFrame(int frame, float time, float r, float g, float b, fl _frames[frame + B2] = b2; } -void RGB2Timeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) { +void RGB2Timeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) { + SP_UNUSED(add); Color &light = pose._color; Color &dark = pose._darkColor; float r, g, b, r2, g2, b2; if (time < _frames[0]) { - SlotPose &setup = slot._data._setup; - Color &setupLight = setup._color; - Color &setupDark = setup._darkColor; - switch (blend) { - case MixBlend_Setup: - light.r = setupLight.r; - light.g = setupLight.g; - light.b = setupLight.b; - dark.r = setupDark.r; - dark.g = setupDark.g; - dark.b = setupDark.b; - /* Fall through. */ - default: - return; - case MixBlend_First: - r = light.r + (setupLight.r - light.r) * alpha; - g = light.g + (setupLight.g - light.g) * alpha; - b = light.b + (setupLight.b - light.b) * alpha; - r2 = dark.r + (setupDark.r - dark.r) * alpha; - g2 = dark.g + (setupDark.g - dark.g) * alpha; - b2 = dark.b + (setupDark.b - dark.b) * alpha; - } - } else { - int i = Animation::search(_frames, time, ENTRIES); - int curveType = (int) _curves[i / ENTRIES]; - switch (curveType) { - case LINEAR: { - float before = _frames[i]; - r = _frames[i + R]; - g = _frames[i + G]; - b = _frames[i + B]; - r2 = _frames[i + R2]; - g2 = _frames[i + G2]; - b2 = _frames[i + B2]; - float t = (time - before) / (_frames[i + ENTRIES] - before); - r += (_frames[i + ENTRIES + R] - r) * t; - g += (_frames[i + ENTRIES + G] - g) * t; - b += (_frames[i + ENTRIES + B] - b) * t; - r2 += (_frames[i + ENTRIES + R2] - r2) * t; - g2 += (_frames[i + ENTRIES + G2] - g2) * t; - b2 += (_frames[i + ENTRIES + B2] - b2) * t; - break; - } - case STEPPED: { - r = _frames[i + R]; - g = _frames[i + G]; - b = _frames[i + B]; - r2 = _frames[i + R2]; - g2 = _frames[i + G2]; - b2 = _frames[i + B2]; - break; - } - default: { - r = getBezierValue(time, i, R, curveType - BEZIER); - g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER); - b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER); - r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 3 - BEZIER); - g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 4 - BEZIER); - b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 5 - BEZIER); - break; - } + if (fromSetup) { + SlotPose &setup = slot._data._setup; + Color &setupLight = setup._color; + Color &setupDark = setup._darkColor; + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; } + return; + } - if (alpha != 1) { - if (blend == MixBlend_Setup) { - SlotPose &setup = slot._data._setup; - Color &setupLight = setup._color; - r = setupLight.r + (r - setupLight.r) * alpha; - g = setupLight.g + (g - setupLight.g) * alpha; - b = setupLight.b + (b - setupLight.b) * alpha; - Color &setupDark = setup._darkColor; - r2 = setupDark.r + (r2 - setupDark.r) * alpha; - g2 = setupDark.g + (g2 - setupDark.g) * alpha; - b2 = setupDark.b + (b2 - setupDark.b) * alpha; - } else { - r = light.r + (r - light.r) * alpha; - g = light.g + (g - light.g) * alpha; - b = light.b + (b - light.b) * alpha; - r2 = dark.r + (r2 - dark.r) * alpha; - g2 = dark.g + (g2 - dark.g) * alpha; - b2 = dark.b + (b2 - dark.b) * alpha; - } + int i = Animation::search(_frames, time, ENTRIES); + int curveType = (int) _curves[i / ENTRIES]; + switch (curveType) { + case LINEAR: { + float before = _frames[i]; + r = _frames[i + R]; + g = _frames[i + G]; + b = _frames[i + B]; + r2 = _frames[i + R2]; + g2 = _frames[i + G2]; + b2 = _frames[i + B2]; + float t = (time - before) / (_frames[i + ENTRIES] - before); + r += (_frames[i + ENTRIES + R] - r) * t; + g += (_frames[i + ENTRIES + G] - g) * t; + b += (_frames[i + ENTRIES + B] - b) * t; + r2 += (_frames[i + ENTRIES + R2] - r2) * t; + g2 += (_frames[i + ENTRIES + G2] - g2) * t; + b2 += (_frames[i + ENTRIES + B2] - b2) * t; + break; + } + case STEPPED: { + r = _frames[i + R]; + g = _frames[i + G]; + b = _frames[i + B]; + r2 = _frames[i + R2]; + g2 = _frames[i + G2]; + b2 = _frames[i + B2]; + break; + } + default: { + r = getBezierValue(time, i, R, curveType - BEZIER); + g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER); + b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER); + r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 3 - BEZIER); + g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 4 - BEZIER); + b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 5 - BEZIER); + break; + } + } + + if (alpha != 1) { + if (fromSetup) { + SlotPose &setup = slot._data._setup; + Color &setupLight = setup._color; + r = setupLight.r + (r - setupLight.r) * alpha; + g = setupLight.g + (g - setupLight.g) * alpha; + b = setupLight.b + (b - setupLight.b) * alpha; + Color &setupDark = setup._darkColor; + r2 = setupDark.r + (r2 - setupDark.r) * alpha; + g2 = setupDark.g + (g2 - setupDark.g) * alpha; + b2 = setupDark.b + (b2 - setupDark.b) * alpha; + } else { + r = light.r + (r - light.r) * alpha; + g = light.g + (g - light.g) * alpha; + b = light.b + (b - light.b) * alpha; + r2 = dark.r + (r2 - dark.r) * alpha; + g2 = dark.g + (g2 - dark.g) * alpha; + b2 = dark.b + (b2 - dark.b) * alpha; } } diff --git a/spine-cpp/src/spine/CurveTimeline.cpp b/spine-cpp/src/spine/CurveTimeline.cpp index 3ceb66341..23f27508a 100644 --- a/spine-cpp/src/spine/CurveTimeline.cpp +++ b/spine-cpp/src/spine/CurveTimeline.cpp @@ -130,117 +130,30 @@ float CurveTimeline1::getCurveValue(float time) { return getBezierValue(time, i, CurveTimeline1::VALUE, curveType - CurveTimeline1::BEZIER); } -float CurveTimeline1::getRelativeValue(float time, float alpha, MixBlend blend, float current, float setup) { - if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - return setup; - case MixBlend_First: - return current + (setup - current) * alpha; - default: - return current; - } - } +float CurveTimeline1::getRelativeValue(float time, float alpha, bool fromSetup, bool add, float current, float setup) { + if (time < _frames[0]) return fromSetup ? setup : current; float value = getCurveValue(time); - switch (blend) { - case MixBlend_Setup: - return setup + value * alpha; - case MixBlend_First: - case MixBlend_Replace: - return current + (value + setup - current) * alpha; - case MixBlend_Add: - return current + value * alpha; - } - return current; + return fromSetup ? setup + value * alpha : current + (add ? value : value + setup - current) * alpha; } -float CurveTimeline1::getAbsoluteValue(float time, float alpha, MixBlend blend, float current, float setup) { - if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - return setup; - case MixBlend_First: - return current + (setup - current) * alpha; - default: - return current; - } - } +float CurveTimeline1::getAbsoluteValue(float time, float alpha, bool fromSetup, bool add, float current, float setup) { + if (time < _frames[0]) return fromSetup ? setup : current; float value = getCurveValue(time); - switch (blend) { - case MixBlend_Setup: - return setup + (value - setup) * alpha; - case MixBlend_First: - case MixBlend_Replace: - return current + (value - current) * alpha; - case MixBlend_Add: - return current + value * alpha; - } - return current; + return fromSetup ? setup + (value - setup) * alpha : current + (add ? value : value - current) * alpha; } -float CurveTimeline1::getAbsoluteValue(float time, float alpha, MixBlend blend, float current, float setup, float value) { - if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - return setup; - case MixBlend_First: - return current + (setup - current) * alpha; - default: - return current; - } - } - switch (blend) { - case MixBlend_Setup: - return setup + (value - setup) * alpha; - case MixBlend_First: - case MixBlend_Replace: - return current + (value - current) * alpha; - case MixBlend_Add: - return current + value * alpha; - } - return current; +float CurveTimeline1::getAbsoluteValue(float time, float alpha, bool fromSetup, bool add, float current, float setup, float value) { + if (time < _frames[0]) return fromSetup ? setup : current; + return fromSetup ? setup + (value - setup) * alpha : current + (add ? value : value - current) * alpha; } -float CurveTimeline1::getScaleValue(float time, float alpha, MixBlend blend, MixDirection direction, float current, float setup) { - if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - return setup; - case MixBlend_First: - return current + (setup - current) * alpha; - default: - return current; - } - } +float CurveTimeline1::getScaleValue(float time, float alpha, bool fromSetup, bool add, bool out, float current, float setup) { + if (time < _frames[0]) return fromSetup ? setup : current; float value = getCurveValue(time) * setup; - if (alpha == 1) { - if (blend == MixBlend_Add) return current + value - setup; - return value; - } - // Mixing out uses sign of setup or current pose, else use sign of key. - if (direction == MixDirection_Out) { - switch (blend) { - case MixBlend_Setup: - return setup + (MathUtil::abs(value) * MathUtil::sign(setup) - setup) * alpha; - case MixBlend_First: - case MixBlend_Replace: - return current + (MathUtil::abs(value) * MathUtil::sign(current) - current) * alpha; - default: - break; - } - } else { - float s; - switch (blend) { - case MixBlend_Setup: - s = MathUtil::abs(setup) * MathUtil::sign(value); - return s + (value - s) * alpha; - case MixBlend_First: - case MixBlend_Replace: - s = MathUtil::abs(current) * MathUtil::sign(value); - return s + (value - s) * alpha; - default: - break; - } - } - return current + (value - setup) * alpha; + if (alpha == 1 && !add) return value; + float base = fromSetup ? setup : current; + if (add) return base + (value - setup) * alpha; + if (out) return base + (MathUtil::abs(value) * MathUtil::sign(base) - base) * alpha; + base = MathUtil::abs(base) * MathUtil::sign(value); + return base + (value - base) * alpha; } diff --git a/spine-cpp/src/spine/DeformTimeline.cpp b/spine-cpp/src/spine/DeformTimeline.cpp index 7a0705eb4..b1245982c 100644 --- a/spine-cpp/src/spine/DeformTimeline.cpp +++ b/spine-cpp/src/spine/DeformTimeline.cpp @@ -47,6 +47,7 @@ DeformTimeline::DeformTimeline(size_t frameCount, size_t bezierCount, int slotIn : SlotCurveTimeline(frameCount, 1, bezierCount, slotIndex), _attachment(&attachment) { PropertyId ids[] = {((PropertyId) Property_Deform << 32) | ((slotIndex << 16 | attachment._id) & 0xffffffff)}; setPropertyIds(ids, 1); + _additive = true; _vertices.ensureCapacity(frameCount); for (size_t i = 0; i < frameCount; ++i) { @@ -56,7 +57,8 @@ DeformTimeline::DeformTimeline(size_t frameCount, size_t bezierCount, int slotIn } -void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) { +void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) { + SP_UNUSED(slot); Attachment *slotAttachment = pose._attachment; if (slotAttachment == NULL || !slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti)) { return; @@ -68,41 +70,14 @@ void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, } Array &deformArray = pose._deform; - if (deformArray.size() == 0) { - blend = MixBlend_Setup; - } + if (deformArray.size() == 0) fromSetup = true; Array> &vertices = _vertices; size_t vertexCount = vertices[0].size(); Array &frames = _frames; if (time < frames[0]) { - switch (blend) { - case MixBlend_Setup: - deformArray.clear(); - return; - case MixBlend_First: { - if (alpha == 1) { - deformArray.clear(); - return; - } - deformArray.setSize(vertexCount, 0); - Array &deform = deformArray; - if (vertexAttachment->getBones().size() == 0) { - // Unweighted vertex positions. - Array &setupVertices = vertexAttachment->getVertices(); - for (size_t i = 0; i < vertexCount; i++) deform[i] += (setupVertices[i] - deform[i]) * alpha; - } else { - // Weighted deform offsets. - alpha = 1 - alpha; - for (size_t i = 0; i < vertexCount; i++) deform[i] *= alpha; - } - break; - } - case MixBlend_Replace: - case MixBlend_Add: - break; - } + if (fromSetup) deformArray.clear(); return; } @@ -112,7 +87,7 @@ void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, if (time >= frames[frames.size() - 1]) {// Time is after last frame. Array &lastVertices = vertices[frames.size() - 1]; if (alpha == 1) { - if (blend == MixBlend_Add) { + if (add && !fromSetup) { if (vertexAttachment->getBones().size() == 0) { // Unweighted vertex positions, no alpha. Array &setupVertices = vertexAttachment->getVertices(); @@ -125,38 +100,30 @@ void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, // Vertex positions or deform offsets, no alpha. memcpy(deform.buffer(), lastVertices.buffer(), vertexCount * sizeof(float)); } - } else { - switch (blend) { - case MixBlend_Setup: { - if (vertexAttachment->getBones().size() == 0) { - // Unweighted vertex positions, with alpha. - Array &setupVertices = vertexAttachment->getVertices(); - for (size_t i = 0; i < vertexCount; i++) { - float setup = setupVertices[i]; - deform[i] = setup + (lastVertices[i] - setup) * alpha; - } - } else { - // Weighted deform offsets, with alpha. - for (size_t i = 0; i < vertexCount; i++) deform[i] = lastVertices[i] * alpha; - } - break; + } else if (fromSetup) { + if (vertexAttachment->getBones().size() == 0) { + // Unweighted vertex positions, with alpha. + Array &setupVertices = vertexAttachment->getVertices(); + for (size_t i = 0; i < vertexCount; i++) { + float setup = setupVertices[i]; + deform[i] = setup + (lastVertices[i] - setup) * alpha; } - case MixBlend_First: - case MixBlend_Replace: - // Vertex positions or deform offsets, with alpha. - for (size_t i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - deform[i]) * alpha; - break; - case MixBlend_Add: - if (vertexAttachment->getBones().size() == 0) { - // Unweighted vertex positions, with alpha. - Array &setupVertices = vertexAttachment->getVertices(); - for (size_t i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - setupVertices[i]) * alpha; - } else { - // Weighted deform offsets, alpha. - for (size_t i = 0; i < vertexCount; i++) deform[i] += lastVertices[i] * alpha; - } - break; + } else { + // Weighted deform offsets, with alpha. + for (size_t i = 0; i < vertexCount; i++) deform[i] = lastVertices[i] * alpha; } + } else if (add) { + if (vertexAttachment->getBones().size() == 0) { + // Unweighted vertex positions, with alpha. + Array &setupVertices = vertexAttachment->getVertices(); + for (size_t i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - setupVertices[i]) * alpha; + } else { + // Weighted deform offsets, with alpha. + for (size_t i = 0; i < vertexCount; i++) deform[i] += lastVertices[i] * alpha; + } + } else { + // Vertex positions or deform offsets, with alpha. + for (size_t i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - deform[i]) * alpha; } return; } @@ -168,7 +135,7 @@ void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, Array &nextVertices = vertices[frame + 1]; if (alpha == 1) { - if (blend == MixBlend_Add) { + if (add && !fromSetup) { if (vertexAttachment->getBones().size() == 0) { // Unweighted vertex positions, no alpha. Array &setupVertices = vertexAttachment->getVertices(); @@ -192,49 +159,41 @@ void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, deform[i] = prev + (nextVertices[i] - prev) * percent; } } - } else { - switch (blend) { - case MixBlend_Setup: { - if (vertexAttachment->getBones().size() == 0) { - // Unweighted vertex positions, with alpha. - Array &setupVertices = vertexAttachment->getVertices(); - for (size_t i = 0; i < vertexCount; i++) { - float prev = prevVertices[i], setup = setupVertices[i]; - deform[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha; - } - } else { - // Weighted deform offsets, with alpha. - for (size_t i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - deform[i] = (prev + (nextVertices[i] - prev) * percent) * alpha; - } - } - break; + } else if (fromSetup) { + if (vertexAttachment->getBones().size() == 0) { + // Unweighted vertex positions, with alpha. + Array &setupVertices = vertexAttachment->getVertices(); + for (size_t i = 0; i < vertexCount; i++) { + float prev = prevVertices[i], setup = setupVertices[i]; + deform[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha; } - case MixBlend_First: - case MixBlend_Replace: - // Vertex positions or deform offsets, with alpha. - for (size_t i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - deform[i] += (prev + (nextVertices[i] - prev) * percent - deform[i]) * alpha; - } - break; - case MixBlend_Add: - if (vertexAttachment->getBones().size() == 0) { - // Unweighted vertex positions, with alpha. - Array &setupVertices = vertexAttachment->getVertices(); - for (size_t i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - deform[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha; - } - } else { - // Weighted deform offsets, with alpha. - for (size_t i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - deform[i] += (prev + (nextVertices[i] - prev) * percent) * alpha; - } - } - break; + } else { + // Weighted deform offsets, with alpha. + for (size_t i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + deform[i] = (prev + (nextVertices[i] - prev) * percent) * alpha; + } + } + } else if (add) { + if (vertexAttachment->getBones().size() == 0) { + // Unweighted vertex positions, with alpha. + Array &setupVertices = vertexAttachment->getVertices(); + for (size_t i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + deform[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha; + } + } else { + // Weighted deform offsets, with alpha. + for (size_t i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + deform[i] += (prev + (nextVertices[i] - prev) * percent) * alpha; + } + } + } else { + // Vertex positions or deform offsets, with alpha. + for (size_t i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + deform[i] += (prev + (nextVertices[i] - prev) * percent - deform[i]) * alpha; } } } diff --git a/spine-cpp/src/spine/DrawOrderFolderTimeline.cpp b/spine-cpp/src/spine/DrawOrderFolderTimeline.cpp index 6ee2f623c..f3aacf29e 100644 --- a/spine-cpp/src/spine/DrawOrderFolderTimeline.cpp +++ b/spine-cpp/src/spine/DrawOrderFolderTimeline.cpp @@ -49,23 +49,23 @@ DrawOrderFolderTimeline::DrawOrderFolderTimeline(size_t frameCount, Array & _drawOrders.ensureCapacity(frameCount); _inFolder.setSize(slotCount, false); for (size_t i = 0; i < _slots.size(); ++i) _inFolder[_slots[i]] = true; + _instant = true; for (size_t i = 0; i < frameCount; ++i) { Array vec; _drawOrders.add(vec); } } -void DrawOrderFolderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void DrawOrderFolderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); SP_UNUSED(alpha); + SP_UNUSED(add); SP_UNUSED(appliedPose); - if (direction == MixDirection_Out) { - if (blend == MixBlend_Setup) setup(skeleton); - } else if (time < _frames[0]) { - if (blend == MixBlend_Setup || blend == MixBlend_First) setup(skeleton); + if (out || time < _frames[0]) { + if (fromSetup) setup(skeleton); } else { Array &drawOrder = _drawOrders[Animation::search(_frames, time)]; if (drawOrder.size() == 0) diff --git a/spine-cpp/src/spine/DrawOrderTimeline.cpp b/spine-cpp/src/spine/DrawOrderTimeline.cpp index e7133a247..8a2df734d 100644 --- a/spine-cpp/src/spine/DrawOrderTimeline.cpp +++ b/spine-cpp/src/spine/DrawOrderTimeline.cpp @@ -48,6 +48,7 @@ PropertyId DrawOrderTimeline::getPropertyId() { DrawOrderTimeline::DrawOrderTimeline(size_t frameCount) : Timeline(frameCount, 1) { PropertyId ids[] = {getPropertyId()}; setPropertyIds(ids, 1); + _instant = true; _drawOrders.ensureCapacity(frameCount); for (size_t i = 0; i < frameCount; ++i) { @@ -56,26 +57,18 @@ DrawOrderTimeline::DrawOrderTimeline(size_t frameCount) : Timeline(frameCount, 1 } } -void DrawOrderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void DrawOrderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { SP_UNUSED(appliedPose); SP_UNUSED(lastTime); SP_UNUSED(events); SP_UNUSED(alpha); + SP_UNUSED(add); Array &drawOrder = skeleton._drawOrder; Array &slots = skeleton._slots; - if (direction == MixDirection_Out) { - if (blend == MixBlend_Setup) { - drawOrder.clear(); - drawOrder.ensureCapacity(slots.size()); - for (size_t i = 0, n = slots.size(); i < n; ++i) drawOrder.add(slots[i]); - } - return; - } - - if (time < _frames[0]) { - if (blend == MixBlend_Setup || blend == MixBlend_First) { + if (out || time < _frames[0]) { + if (fromSetup) { drawOrder.clear(); drawOrder.ensureCapacity(slots.size()); for (size_t i = 0, n = slots.size(); i < n; ++i) drawOrder.add(slots[i]); diff --git a/spine-cpp/src/spine/EventTimeline.cpp b/spine-cpp/src/spine/EventTimeline.cpp index f584ec772..fa4c22704 100644 --- a/spine-cpp/src/spine/EventTimeline.cpp +++ b/spine-cpp/src/spine/EventTimeline.cpp @@ -49,14 +49,16 @@ EventTimeline::EventTimeline(size_t frameCount) : Timeline(frameCount, 1) { PropertyId ids[] = {((PropertyId) Property_Event << 32)}; setPropertyIds(ids, 1); _events.setSize(frameCount, NULL); + _instant = true; } EventTimeline::~EventTimeline() { ArrayUtils::deleteElements(_events); } -void EventTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *pEvents, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void EventTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *pEvents, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { + SP_UNUSED(skeleton); if (pEvents == NULL) return; Array &events = *pEvents; @@ -65,7 +67,7 @@ void EventTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array< if (lastTime > time) { // Apply after lastTime for looped animations. - apply(skeleton, lastTime, FLT_MAX, pEvents, alpha, blend, direction, appliedPose); + apply(skeleton, lastTime, FLT_MAX, pEvents, 0, false, false, false, false); lastTime = -1.0f; } else if (lastTime >= _frames[frameCount - 1]) { // Last time is after last frame. diff --git a/spine-cpp/src/spine/IkConstraintTimeline.cpp b/spine-cpp/src/spine/IkConstraintTimeline.cpp index 07e1707b9..f7d811509 100644 --- a/spine-cpp/src/spine/IkConstraintTimeline.cpp +++ b/spine-cpp/src/spine/IkConstraintTimeline.cpp @@ -53,35 +53,26 @@ IkConstraintTimeline::IkConstraintTimeline(size_t frameCount, size_t bezierCount IkConstraintTimeline::~IkConstraintTimeline() { } -void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); + SP_UNUSED(add); IkConstraint *constraint = (IkConstraint *) skeleton._constraints[_constraintIndex]; if (!constraint->isActive()) return; IkConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; if (time < _frames[0]) { - IkConstraintPose &setup = constraint->_data._setup; - switch (blend) { - case MixBlend_Setup: - pose._mix = setup._mix; - pose._softness = setup._softness; - pose._bendDirection = setup._bendDirection; - pose._compress = setup._compress; - pose._stretch = setup._stretch; - return; - case MixBlend_First: - pose._mix += (setup._mix - pose._mix) * alpha; - pose._softness += (setup._softness - pose._softness) * alpha; - pose._bendDirection = setup._bendDirection; - pose._compress = setup._compress; - pose._stretch = setup._stretch; - return; - default: - return; + if (fromSetup) { + IkConstraintPose &setup = constraint->_data._setup; + pose._mix = setup._mix; + pose._softness = setup._softness; + pose._bendDirection = setup._bendDirection; + pose._compress = setup._compress; + pose._stretch = setup._stretch; } + return; } float mix = 0, softness = 0; @@ -108,24 +99,20 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, } } - if (blend == MixBlend_Setup) { - IkConstraintPose &setup = constraint->_data._setup; - pose._mix = setup._mix + (mix - setup._mix) * alpha; - pose._softness = setup._softness + (softness - setup._softness) * alpha; - if (direction == MixDirection_Out) { - pose._bendDirection = setup._bendDirection; - pose._compress = setup._compress; - pose._stretch = setup._stretch; - return; + IkConstraintPose &base = fromSetup ? constraint->_data._setup : pose; + pose._mix = base._mix + (mix - base._mix) * alpha; + pose._softness = base._softness + (softness - base._softness) * alpha; + if (out) { + if (fromSetup) { + pose._bendDirection = base._bendDirection; + pose._compress = base._compress; + pose._stretch = base._stretch; } } else { - pose._mix += (mix - pose._mix) * alpha; - pose._softness += (softness - pose._softness) * alpha; - if (direction == MixDirection_Out) return; + pose._bendDirection = (int) _frames[i + BEND_DIRECTION]; + pose._compress = _frames[i + COMPRESS] != 0; + pose._stretch = _frames[i + STRETCH] != 0; } - pose._bendDirection = (int) _frames[i + BEND_DIRECTION]; - pose._compress = _frames[i + COMPRESS] != 0; - pose._stretch = _frames[i + STRETCH] != 0; } void IkConstraintTimeline::setFrame(int frame, float time, float mix, float softness, int bendDirection, bool compress, bool stretch) { diff --git a/spine-cpp/src/spine/InheritTimeline.cpp b/spine-cpp/src/spine/InheritTimeline.cpp index f01beaa2e..66836760e 100644 --- a/spine-cpp/src/spine/InheritTimeline.cpp +++ b/spine-cpp/src/spine/InheritTimeline.cpp @@ -45,6 +45,7 @@ RTTI_IMPL_MULTI(InheritTimeline, Timeline, BoneTimeline) InheritTimeline::InheritTimeline(size_t frameCount, int boneIndex) : Timeline(frameCount, ENTRIES), BoneTimeline(boneIndex) { PropertyId ids[] = {((PropertyId) Property_Inherit << 32) | boneIndex}; setPropertyIds(ids, 1); + _instant = true; } InheritTimeline::~InheritTimeline() { @@ -56,26 +57,25 @@ void InheritTimeline::setFrame(int frame, float time, Inherit inherit) { _frames[frame + INHERIT] = (float) inherit; } - -void InheritTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void InheritTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); SP_UNUSED(alpha); + SP_UNUSED(add); Bone *bone = skeleton._bones[_boneIndex]; if (!bone->isActive()) return; BoneLocal &pose = appliedPose ? *bone->_applied : bone->_pose; - if (direction == MixDirection_Out) { - if (blend == MixBlend_Setup) pose._inherit = bone->_data._setup._inherit; - return; - } - - if (time < _frames[0]) { - if (blend == MixBlend_Setup || blend == MixBlend_First) pose._inherit = bone->_data._setup._inherit; + if (out) { + if (fromSetup) pose._inherit = bone->_data._setup._inherit; } else { - int idx = Animation::search(_frames, time, ENTRIES) + INHERIT; - pose._inherit = static_cast((int) _frames[idx]); + if (time < _frames[0]) { + if (fromSetup) pose._inherit = bone->_data._setup._inherit; + } else { + int idx = Animation::search(_frames, time, ENTRIES) + INHERIT; + pose._inherit = static_cast((int) _frames[idx]); + } } } diff --git a/spine-cpp/src/spine/PathConstraintMixTimeline.cpp b/spine-cpp/src/spine/PathConstraintMixTimeline.cpp index 3e741e61a..1686b7362 100644 --- a/spine-cpp/src/spine/PathConstraintMixTimeline.cpp +++ b/spine-cpp/src/spine/PathConstraintMixTimeline.cpp @@ -48,37 +48,30 @@ PathConstraintMixTimeline::PathConstraintMixTimeline(size_t frameCount, size_t b : CurveTimeline(frameCount, PathConstraintMixTimeline::ENTRIES, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex) { PropertyId ids[] = {((PropertyId) Property_PathConstraintMix << 32) | constraintIndex}; setPropertyIds(ids, 1); + _additive = true; } PathConstraintMixTimeline::~PathConstraintMixTimeline() { } -void PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); PathConstraint *constraint = (PathConstraint *) skeleton._constraints[_constraintIndex]; if (!constraint->isActive()) return; PathConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; if (time < _frames[0]) { - PathConstraintPose &setup = constraint->_data._setup; - switch (blend) { - case MixBlend_Setup: - pose._mixRotate = setup._mixRotate; - pose._mixX = setup._mixX; - pose._mixY = setup._mixY; - return; - case MixBlend_First: - pose._mixRotate += (setup._mixRotate - pose._mixRotate) * alpha; - pose._mixX += (setup._mixX - pose._mixX) * alpha; - pose._mixY += (setup._mixY - pose._mixY) * alpha; - return; - default: - return; + if (fromSetup) { + PathConstraintPose &setup = constraint->_data._setup; + pose._mixRotate = setup._mixRotate; + pose._mixX = setup._mixX; + pose._mixY = setup._mixY; } + return; } float rotate, x, y; @@ -109,15 +102,15 @@ void PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float } } - if (blend == MixBlend_Setup) { - PathConstraintPose &setup = constraint->_data._setup; - pose._mixRotate = setup._mixRotate + (rotate - setup._mixRotate) * alpha; - pose._mixX = setup._mixX + (x - setup._mixX) * alpha; - pose._mixY = setup._mixY + (y - setup._mixY) * alpha; + PathConstraintPose &base = fromSetup ? constraint->_data._setup : pose; + if (add) { + pose._mixRotate = base._mixRotate + rotate * alpha; + pose._mixX = base._mixX + x * alpha; + pose._mixY = base._mixY + y * alpha; } else { - pose._mixRotate += (rotate - pose._mixRotate) * alpha; - pose._mixX += (x - pose._mixX) * alpha; - pose._mixY += (y - pose._mixY) * alpha; + pose._mixRotate = base._mixRotate + (rotate - base._mixRotate) * alpha; + pose._mixX = base._mixX + (x - base._mixX) * alpha; + pose._mixY = base._mixY + (y - base._mixY) * alpha; } } diff --git a/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp b/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp index e324e028f..5e10faa58 100644 --- a/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp +++ b/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp @@ -45,21 +45,22 @@ RTTI_IMPL(PathConstraintPositionTimeline, ConstraintTimeline1) PathConstraintPositionTimeline::PathConstraintPositionTimeline(size_t frameCount, size_t bezierCount, int constraintIndex) : ConstraintTimeline1(frameCount, bezierCount, constraintIndex, Property_PathConstraintPosition) { + _additive = true; } PathConstraintPositionTimeline::~PathConstraintPositionTimeline() { } -void PathConstraintPositionTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void PathConstraintPositionTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, + bool add, bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); PathConstraint *constraint = (PathConstraint *) skeleton._constraints[_constraintIndex]; if (constraint->isActive()) { PathConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; PathConstraintData &data = constraint->_data; - pose._position = getAbsoluteValue(time, alpha, blend, pose._position, data._setup._position); + pose._position = getAbsoluteValue(time, alpha, fromSetup, add, pose._position, data._setup._position); } } diff --git a/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp b/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp index 3e6d0c438..79afc29c4 100644 --- a/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp +++ b/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp @@ -50,16 +50,16 @@ PathConstraintSpacingTimeline::PathConstraintSpacingTimeline(size_t frameCount, PathConstraintSpacingTimeline::~PathConstraintSpacingTimeline() { } -void PathConstraintSpacingTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void PathConstraintSpacingTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, + bool add, bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); PathConstraint *constraint = (PathConstraint *) skeleton._constraints[_constraintIndex]; if (constraint->isActive()) { PathConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; PathConstraintData &data = constraint->_data; - pose._spacing = getAbsoluteValue(time, alpha, blend == MixBlend_Add ? MixBlend_Replace : blend, pose._spacing, data._setup._spacing); + pose._spacing = getAbsoluteValue(time, alpha, fromSetup, false, pose._spacing, data._setup._spacing); } } diff --git a/spine-cpp/src/spine/PhysicsConstraintTimeline.cpp b/spine-cpp/src/spine/PhysicsConstraintTimeline.cpp index 179899b86..99f59d8e2 100644 --- a/spine-cpp/src/spine/PhysicsConstraintTimeline.cpp +++ b/spine-cpp/src/spine/PhysicsConstraintTimeline.cpp @@ -52,14 +52,15 @@ RTTI_IMPL(PhysicsConstraintMixTimeline, PhysicsConstraintTimeline) RTTI_IMPL_MULTI(PhysicsConstraintResetTimeline, Timeline, ConstraintTimeline) PhysicsConstraintTimeline::PhysicsConstraintTimeline(size_t frameCount, size_t bezierCount, int constraintIndex, Property property) - : CurveTimeline1(frameCount, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex), _additive(false) { + : CurveTimeline1(frameCount, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex) { PropertyId ids[] = {((PropertyId) property << 32) | constraintIndex}; setPropertyIds(ids, 1); } -void PhysicsConstraintTimeline::apply(Skeleton &skeleton, float, float time, Array *, float alpha, MixBlend blend, MixDirection direction, +void PhysicsConstraintTimeline::apply(Skeleton &skeleton, float, float time, Array *, float alpha, bool fromSetup, bool add, bool out, bool appliedPose) { - if (blend == MixBlend_Add && !_additive) blend = MixBlend_Replace; + SP_UNUSED(out); + if (add && !_additive) add = false; if (_constraintIndex == -1) { float value = time >= _frames[0] ? getCurveValue(time) : 0; @@ -68,20 +69,20 @@ void PhysicsConstraintTimeline::apply(Skeleton &skeleton, float, float time, Arr PhysicsConstraint *constraint = physicsConstraints[i]; if (constraint->isActive() && global(constraint->_data)) { PhysicsConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; - set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint->_data._setup), value)); + set(pose, getAbsoluteValue(time, alpha, fromSetup, add, get(pose), get(constraint->_data._setup), value)); } } } else { PhysicsConstraint *constraint = static_cast(skeleton.getConstraints()[_constraintIndex]); if (constraint->isActive()) { PhysicsConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; - set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint->_data._setup))); + set(pose, getAbsoluteValue(time, alpha, fromSetup, add, get(pose), get(constraint->_data._setup))); } } } -void PhysicsConstraintResetTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void PhysicsConstraintResetTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { PhysicsConstraint *constraint = nullptr; if (_constraintIndex != -1) { constraint = static_cast(skeleton.getConstraints()[_constraintIndex]); @@ -89,7 +90,7 @@ void PhysicsConstraintResetTimeline::apply(Skeleton &skeleton, float lastTime, f } if (lastTime > time) {// Apply after lastTime for looped animations. - apply(skeleton, lastTime, FLT_MAX, nullptr, alpha, blend, direction, appliedPose); + apply(skeleton, lastTime, FLT_MAX, nullptr, alpha, false, false, false, false); lastTime = -1; } else if (lastTime >= _frames[_frames.size() - 1])// Last time is after last frame. return; diff --git a/spine-cpp/src/spine/RotateTimeline.cpp b/spine-cpp/src/spine/RotateTimeline.cpp index 0d1802a1d..6573a2069 100644 --- a/spine-cpp/src/spine/RotateTimeline.cpp +++ b/spine-cpp/src/spine/RotateTimeline.cpp @@ -39,7 +39,7 @@ RotateTimeline::RotateTimeline(size_t frameCount, size_t bezierCount, int boneIn : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_Rotate) { } -void RotateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - SP_UNUSED(direction); - pose._rotation = getRelativeValue(time, alpha, blend, pose._rotation, setup._rotation); +void RotateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); + pose._rotation = getRelativeValue(time, alpha, fromSetup, add, pose._rotation, setup._rotation); } \ No newline at end of file diff --git a/spine-cpp/src/spine/ScaleTimeline.cpp b/spine-cpp/src/spine/ScaleTimeline.cpp index 060b4d4ed..320d1d1b8 100644 --- a/spine-cpp/src/spine/ScaleTimeline.cpp +++ b/spine-cpp/src/spine/ScaleTimeline.cpp @@ -46,18 +46,11 @@ ScaleTimeline::ScaleTimeline(size_t frameCount, size_t bezierCount, int boneInde : BoneTimeline2(frameCount, bezierCount, boneIndex, Property_ScaleX, Property_ScaleY) { } -void ScaleTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { +void ScaleTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - pose._scaleX = setup._scaleX; - pose._scaleY = setup._scaleY; - return; - case MixBlend_First: - pose._scaleX += (setup._scaleX - pose._scaleX) * alpha; - pose._scaleY += (setup._scaleY - pose._scaleY) * alpha; - default: { - } + if (fromSetup) { + pose._scaleX = setup._scaleX; + pose._scaleY = setup._scaleY; } return; } @@ -88,54 +81,29 @@ void ScaleTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float x *= setup._scaleX; y *= setup._scaleY; - if (alpha == 1) { - if (blend == MixBlend_Add) { - pose._scaleX += x - setup._scaleX; - pose._scaleY += y - setup._scaleY; - } else { - pose._scaleX = x; - pose._scaleY = y; - } + if (alpha == 1 && !add) { + pose._scaleX = x; + pose._scaleY = y; } else { float bx, by; - if (direction == MixDirection_Out) { - switch (blend) { - case MixBlend_Setup: - bx = setup._scaleX; - by = setup._scaleY; - pose._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bx) * alpha; - pose._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - by) * alpha; - break; - case MixBlend_First: - case MixBlend_Replace: - bx = pose._scaleX; - by = pose._scaleY; - pose._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bx) * alpha; - pose._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - by) * alpha; - break; - case MixBlend_Add: - pose._scaleX += (x - setup._scaleX) * alpha; - pose._scaleY += (y - setup._scaleY) * alpha; - } + if (fromSetup) { + bx = setup._scaleX; + by = setup._scaleY; } else { - switch (blend) { - case MixBlend_Setup: - bx = MathUtil::abs(setup._scaleX) * MathUtil::sign(x); - by = MathUtil::abs(setup._scaleY) * MathUtil::sign(y); - pose._scaleX = bx + (x - bx) * alpha; - pose._scaleY = by + (y - by) * alpha; - break; - case MixBlend_First: - case MixBlend_Replace: - bx = MathUtil::abs(pose._scaleX) * MathUtil::sign(x); - by = MathUtil::abs(pose._scaleY) * MathUtil::sign(y); - pose._scaleX = bx + (x - bx) * alpha; - pose._scaleY = by + (y - by) * alpha; - break; - case MixBlend_Add: - pose._scaleX += (x - setup._scaleX) * alpha; - pose._scaleY += (y - setup._scaleY) * alpha; - } + bx = pose._scaleX; + by = pose._scaleY; + } + if (add) { + pose._scaleX = bx + (x - setup._scaleX) * alpha; + pose._scaleY = by + (y - setup._scaleY) * alpha; + } else if (out) { + pose._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bx) * alpha; + pose._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - by) * alpha; + } else { + bx = MathUtil::abs(bx) * MathUtil::sign(x); + by = MathUtil::abs(by) * MathUtil::sign(y); + pose._scaleX = bx + (x - bx) * alpha; + pose._scaleY = by + (y - by) * alpha; } } } @@ -146,8 +114,8 @@ ScaleXTimeline::ScaleXTimeline(size_t frameCount, size_t bezierCount, int boneIn : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ScaleX) { } -void ScaleXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - pose._scaleX = getScaleValue(time, alpha, blend, direction, pose._scaleX, setup._scaleX); +void ScaleXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + pose._scaleX = getScaleValue(time, alpha, fromSetup, add, out, pose._scaleX, setup._scaleX); } RTTI_IMPL(ScaleYTimeline, BoneTimeline1) @@ -156,6 +124,6 @@ ScaleYTimeline::ScaleYTimeline(size_t frameCount, size_t bezierCount, int boneIn : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ScaleY) { } -void ScaleYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - pose._scaleY = getScaleValue(time, alpha, blend, direction, pose._scaleY, setup._scaleY); +void ScaleYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + pose._scaleY = getScaleValue(time, alpha, fromSetup, add, out, pose._scaleY, setup._scaleY); } \ No newline at end of file diff --git a/spine-cpp/src/spine/SequenceTimeline.cpp b/spine-cpp/src/spine/SequenceTimeline.cpp index 0e2503ab4..952957b8c 100644 --- a/spine-cpp/src/spine/SequenceTimeline.cpp +++ b/spine-cpp/src/spine/SequenceTimeline.cpp @@ -45,6 +45,7 @@ RTTI_IMPL_MULTI(SequenceTimeline, Timeline, SlotTimeline) SequenceTimeline::SequenceTimeline(size_t frameCount, int slotIndex, Attachment &attachment) : Timeline(frameCount, ENTRIES), SlotTimeline(), _slotIndex(slotIndex), _attachment((HasTextureRegion *) &attachment) { + _instant = true; int sequenceId = 0; if (attachment.getRTTI().instanceOf(RegionAttachment::rtti)) sequenceId = ((RegionAttachment *) &attachment)->getSequence().getId(); if (attachment.getRTTI().instanceOf(MeshAttachment::rtti)) sequenceId = ((MeshAttachment *) &attachment)->getSequence().getId(); @@ -71,11 +72,12 @@ void SequenceTimeline::setSlotIndex(int inValue) { _slotIndex = inValue; } -void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { SP_UNUSED(alpha); SP_UNUSED(lastTime); SP_UNUSED(events); + SP_UNUSED(add); Slot *slot = skeleton.getSlots()[getSlotIndex()]; if (!slot->getBone().isActive()) return; @@ -90,14 +92,14 @@ void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Arr if (((Attachment *) _attachment)->getRTTI().instanceOf(MeshAttachment::rtti)) sequence = &((MeshAttachment *) _attachment)->getSequence(); if (!sequence) return; - if (direction == MixDirection_Out) { - if (blend == MixBlend_Setup) pose.setSequenceIndex(-1); + if (out) { + if (fromSetup) pose.setSequenceIndex(-1); return; } Array &frames = this->_frames; if (time < frames[0]) { - if (blend == MixBlend_Setup || blend == MixBlend_First) pose.setSequenceIndex(-1); + if (fromSetup) pose.setSequenceIndex(-1); return; } diff --git a/spine-cpp/src/spine/ShearTimeline.cpp b/spine-cpp/src/spine/ShearTimeline.cpp index 75fa8f64f..332dba53e 100644 --- a/spine-cpp/src/spine/ShearTimeline.cpp +++ b/spine-cpp/src/spine/ShearTimeline.cpp @@ -46,18 +46,12 @@ ShearTimeline::ShearTimeline(size_t frameCount, size_t bezierCount, int boneInde : BoneTimeline2(frameCount, bezierCount, boneIndex, Property_ShearX, Property_ShearY) { } -void ShearTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { +void ShearTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - pose._shearX = setup._shearX; - pose._shearY = setup._shearY; - return; - case MixBlend_First: - pose._shearX += (setup._shearX - pose._shearX) * alpha; - pose._shearY += (setup._shearY - pose._shearY) * alpha; - default: { - } + if (fromSetup) { + pose._shearX = setup._shearX; + pose._shearY = setup._shearY; } return; } @@ -86,19 +80,15 @@ void ShearTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float } } - switch (blend) { - case MixBlend_Setup: - pose._shearX = setup._shearX + x * alpha; - pose._shearY = setup._shearY + y * alpha; - break; - case MixBlend_First: - case MixBlend_Replace: - pose._shearX += (setup._shearX + x - pose._shearX) * alpha; - pose._shearY += (setup._shearY + y - pose._shearY) * alpha; - break; - case MixBlend_Add: - pose._shearX += x * alpha; - pose._shearY += y * alpha; + if (fromSetup) { + pose._shearX = setup._shearX + x * alpha; + pose._shearY = setup._shearY + y * alpha; + } else if (add) { + pose._shearX += x * alpha; + pose._shearY += y * alpha; + } else { + pose._shearX += (setup._shearX + x - pose._shearX) * alpha; + pose._shearY += (setup._shearY + y - pose._shearY) * alpha; } } @@ -108,8 +98,9 @@ ShearXTimeline::ShearXTimeline(size_t frameCount, size_t bezierCount, int boneIn : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ShearX) { } -void ShearXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - pose._shearX = getRelativeValue(time, alpha, blend, pose._shearX, setup._shearX); +void ShearXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); + pose._shearX = getRelativeValue(time, alpha, fromSetup, add, pose._shearX, setup._shearX); } RTTI_IMPL(ShearYTimeline, BoneTimeline1) @@ -118,6 +109,7 @@ ShearYTimeline::ShearYTimeline(size_t frameCount, size_t bezierCount, int boneIn : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ShearY) { } -void ShearYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - pose._shearY = getRelativeValue(time, alpha, blend, pose._shearY, setup._shearY); +void ShearYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); + pose._shearY = getRelativeValue(time, alpha, fromSetup, add, pose._shearY, setup._shearY); } \ No newline at end of file diff --git a/spine-cpp/src/spine/Skin.cpp b/spine-cpp/src/spine/Skin.cpp index 42e016ee0..2668897a5 100644 --- a/spine-cpp/src/spine/Skin.cpp +++ b/spine-cpp/src/spine/Skin.cpp @@ -49,37 +49,37 @@ static void disposeAttachment(Attachment *attachment) { if (attachment->getRefCount() == 0) delete attachment; } -void Skin::AttachmentMap::put(size_t slotIndex, const String &attachmentName, Attachment *attachment) { +void Skin::AttachmentMap::put(size_t slotIndex, const String &placeholderName, Attachment *attachment) { if (slotIndex >= _buckets.size()) _buckets.setSize(slotIndex + 1, Array()); Array &bucket = _buckets[slotIndex]; - int existing = findInBucket(bucket, attachmentName); + int existing = findInBucket(bucket, placeholderName); attachment->reference(); if (existing >= 0) { disposeAttachment(bucket[existing]._attachment); bucket[existing]._attachment = attachment; } else { - bucket.add(Entry(slotIndex, attachmentName, attachment)); + bucket.add(Entry(slotIndex, placeholderName, attachment)); } } -Attachment *Skin::AttachmentMap::get(size_t slotIndex, const String &attachmentName) { +Attachment *Skin::AttachmentMap::get(size_t slotIndex, const String &placeholderName) { if (slotIndex >= _buckets.size()) return NULL; - int existing = findInBucket(_buckets[slotIndex], attachmentName); + int existing = findInBucket(_buckets[slotIndex], placeholderName); return existing >= 0 ? _buckets[slotIndex][existing]._attachment : NULL; } -void Skin::AttachmentMap::remove(size_t slotIndex, const String &attachmentName) { +void Skin::AttachmentMap::remove(size_t slotIndex, const String &placeholderName) { if (slotIndex >= _buckets.size()) return; - int existing = findInBucket(_buckets[slotIndex], attachmentName); + int existing = findInBucket(_buckets[slotIndex], placeholderName); if (existing >= 0) { disposeAttachment(_buckets[slotIndex][existing]._attachment); _buckets[slotIndex].removeAt(existing); } } -int Skin::AttachmentMap::findInBucket(Array &bucket, const String &attachmentName) { +int Skin::AttachmentMap::findInBucket(Array &bucket, const String &placeholderName) { for (size_t i = 0; i < bucket.size(); i++) - if (bucket[i]._name == attachmentName) return (int) i; + if (bucket[i]._placeholderName == placeholderName) return (int) i; return -1; } @@ -99,16 +99,16 @@ Skin::~Skin() { } } -void Skin::setAttachment(size_t slotIndex, const String &name, Attachment *attachment) { - _attachments.put(slotIndex, name, attachment); +void Skin::setAttachment(size_t slotIndex, const String &placeholderName, Attachment *attachment) { + _attachments.put(slotIndex, placeholderName, attachment); } -Attachment *Skin::getAttachment(size_t slotIndex, const String &name) { - return _attachments.get(slotIndex, name); +Attachment *Skin::getAttachment(size_t slotIndex, const String &placeholderName) { + return _attachments.get(slotIndex, placeholderName); } -void Skin::removeAttachment(size_t slotIndex, const String &name) { - _attachments.remove(slotIndex, name); +void Skin::removeAttachment(size_t slotIndex, const String &placeholderName) { + _attachments.remove(slotIndex, placeholderName); } void Skin::findNamesForSlot(size_t slotIndex, Array &names) { @@ -116,7 +116,7 @@ void Skin::findNamesForSlot(size_t slotIndex, Array &names) { while (entries.hasNext()) { Skin::AttachmentMap::Entry &entry = entries.next(); if (entry._slotIndex == slotIndex) { - names.add(entry._name); + names.add(entry._placeholderName); } } } @@ -146,7 +146,7 @@ void Skin::attachAll(Skeleton &skeleton, Skin &oldSkin) { Slot *slot = slots[slotIndex]; if (slot->getPose().getAttachment() == entry._attachment) { - Attachment *attachment = getAttachment(slotIndex, entry._name); + Attachment *attachment = getAttachment(slotIndex, entry._placeholderName); if (attachment) slot->getPose().setAttachment(attachment); } } @@ -162,7 +162,7 @@ void Skin::addSkin(Skin &other) { AttachmentMap::Entries entries = other.getAttachments(); while (entries.hasNext()) { AttachmentMap::Entry &entry = entries.next(); - setAttachment(entry._slotIndex, entry._name, entry._attachment); + setAttachment(entry._slotIndex, entry._placeholderName, entry._attachment); } } @@ -177,9 +177,9 @@ void Skin::copySkin(Skin &other) { while (entries.hasNext()) { AttachmentMap::Entry &entry = entries.next(); if (entry._attachment->getRTTI().isExactly(MeshAttachment::rtti)) - setAttachment(entry._slotIndex, entry._name, &static_cast(entry._attachment)->newLinkedMesh()); + setAttachment(entry._slotIndex, entry._placeholderName, &static_cast(entry._attachment)->newLinkedMesh()); else - setAttachment(entry._slotIndex, entry._name, &entry._attachment->copy()); + setAttachment(entry._slotIndex, entry._placeholderName, &entry._attachment->copy()); } } diff --git a/spine-cpp/src/spine/Slider.cpp b/spine-cpp/src/spine/Slider.cpp index c996ce8c9..49622a82f 100644 --- a/spine-cpp/src/spine/Slider.cpp +++ b/spine-cpp/src/spine/Slider.cpp @@ -82,7 +82,7 @@ void Slider::update(Skeleton &skeleton, Physics physics) { const Array &indices = animation->getBones(); for (size_t i = 0, n = indices.size(); i < n; i++) bones[indices[i]]->_applied->modifyLocal(skeleton); - animation->apply(skeleton, p._time, p._time, _data._loop, NULL, p._mix, _data._additive ? MixBlend_Add : MixBlend_Replace, MixDirection_In, true); + animation->apply(skeleton, p._time, p._time, _data._loop, NULL, p._mix, false, _data._additive, false, true); } void Slider::sort(Skeleton &skeleton) { diff --git a/spine-cpp/src/spine/SliderMixTimeline.cpp b/spine-cpp/src/spine/SliderMixTimeline.cpp index 701e22e3b..abce7c81f 100644 --- a/spine-cpp/src/spine/SliderMixTimeline.cpp +++ b/spine-cpp/src/spine/SliderMixTimeline.cpp @@ -46,21 +46,22 @@ SliderMixTimeline::SliderMixTimeline(size_t frameCount, size_t bezierCount, int : ConstraintTimeline1(frameCount, bezierCount, sliderIndex, Property_SliderMix) { PropertyId ids[] = {((PropertyId) Property_SliderMix << 32) | sliderIndex}; setPropertyIds(ids, 1); + _additive = true; } SliderMixTimeline::~SliderMixTimeline() { } -void SliderMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void SliderMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); Slider *constraint = (Slider *) skeleton._constraints[_constraintIndex]; if (constraint->isActive()) { SliderPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; SliderData &data = constraint->_data; - pose._mix = getAbsoluteValue(time, alpha, blend, pose._mix, data._setup._mix); + pose._mix = getAbsoluteValue(time, alpha, fromSetup, add, pose._mix, data._setup._mix); } } \ No newline at end of file diff --git a/spine-cpp/src/spine/SliderTimeline.cpp b/spine-cpp/src/spine/SliderTimeline.cpp index 527a293f5..6fbe8279f 100644 --- a/spine-cpp/src/spine/SliderTimeline.cpp +++ b/spine-cpp/src/spine/SliderTimeline.cpp @@ -46,21 +46,22 @@ SliderTimeline::SliderTimeline(size_t frameCount, size_t bezierCount, int slider : ConstraintTimeline1(frameCount, bezierCount, sliderIndex, Property_SliderTime) { PropertyId ids[] = {((PropertyId) Property_SliderTime << 32) | sliderIndex}; setPropertyIds(ids, 1); + _additive = true; } SliderTimeline::~SliderTimeline() { } -void SliderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void SliderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); Slider *constraint = (Slider *) skeleton._constraints[_constraintIndex]; if (constraint->isActive()) { SliderPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; SliderData &data = constraint->_data; - pose._time = getAbsoluteValue(time, alpha, blend, pose._time, data._setup._time); + pose._time = getAbsoluteValue(time, alpha, fromSetup, add, pose._time, data._setup._time); } } \ No newline at end of file diff --git a/spine-cpp/src/spine/SlotCurveTimeline.cpp b/spine-cpp/src/spine/SlotCurveTimeline.cpp index 99e9cc52d..f0aa79c39 100644 --- a/spine-cpp/src/spine/SlotCurveTimeline.cpp +++ b/spine-cpp/src/spine/SlotCurveTimeline.cpp @@ -53,12 +53,12 @@ void SlotCurveTimeline::setSlotIndex(int inValue) { _slotIndex = inValue; } -void SlotCurveTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void SlotCurveTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, bool out, + bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); Slot *slot = skeleton._slots[_slotIndex]; - if (slot->_bone.isActive()) _apply(*slot, appliedPose ? *slot->_applied : slot->_pose, time, alpha, blend); + if (slot->_bone.isActive()) _apply(*slot, appliedPose ? *slot->_applied : slot->_pose, time, alpha, fromSetup, add); } \ No newline at end of file diff --git a/spine-cpp/src/spine/Timeline.cpp b/spine-cpp/src/spine/Timeline.cpp index d35eb1403..2b63f9ee7 100644 --- a/spine-cpp/src/spine/Timeline.cpp +++ b/spine-cpp/src/spine/Timeline.cpp @@ -36,7 +36,8 @@ using namespace spine; RTTI_IMPL_NOPARENT(Timeline) -Timeline::Timeline(size_t frameCount, size_t frameEntries) : _propertyIds(), _frames(), _frameEntries(frameEntries) { +Timeline::Timeline(size_t frameCount, size_t frameEntries) + : _propertyIds(), _frames(), _frameEntries(frameEntries), _additive(false), _instant(false) { _frames.setSize(frameCount * frameEntries, 0); } diff --git a/spine-cpp/src/spine/TransformConstraintTimeline.cpp b/spine-cpp/src/spine/TransformConstraintTimeline.cpp index c7f281fcb..9cd641033 100644 --- a/spine-cpp/src/spine/TransformConstraintTimeline.cpp +++ b/spine-cpp/src/spine/TransformConstraintTimeline.cpp @@ -48,43 +48,33 @@ TransformConstraintTimeline::TransformConstraintTimeline(size_t frameCount, size : CurveTimeline(frameCount, TransformConstraintTimeline::ENTRIES, bezierCount), ConstraintTimeline(), _constraintIndex(transformConstraintIndex) { PropertyId ids[] = {((PropertyId) Property_TransformConstraint << 32) | transformConstraintIndex}; setPropertyIds(ids, 1); + _additive = true; } TransformConstraintTimeline::~TransformConstraintTimeline() { } -void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, MixBlend blend, - MixDirection direction, bool appliedPose) { +void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array *events, float alpha, bool fromSetup, bool add, + bool out, bool appliedPose) { SP_UNUSED(lastTime); SP_UNUSED(events); - SP_UNUSED(direction); + SP_UNUSED(out); TransformConstraint *constraint = (TransformConstraint *) skeleton._constraints[_constraintIndex]; if (!constraint->isActive()) return; TransformConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose; if (time < _frames[0]) { - TransformConstraintPose &setup = constraint->_data._setup; - switch (blend) { - case MixBlend_Setup: - pose._mixRotate = setup._mixRotate; - pose._mixX = setup._mixX; - pose._mixY = setup._mixY; - pose._mixScaleX = setup._mixScaleX; - pose._mixScaleY = setup._mixScaleY; - pose._mixShearY = setup._mixShearY; - return; - case MixBlend_First: - pose._mixRotate += (setup._mixRotate - pose._mixRotate) * alpha; - pose._mixX += (setup._mixX - pose._mixX) * alpha; - pose._mixY += (setup._mixY - pose._mixY) * alpha; - pose._mixScaleX += (setup._mixScaleX - pose._mixScaleX) * alpha; - pose._mixScaleY += (setup._mixScaleY - pose._mixScaleY) * alpha; - pose._mixShearY += (setup._mixShearY - pose._mixShearY) * alpha; - return; - default: - return; + if (fromSetup) { + TransformConstraintPose &setup = constraint->_data._setup; + pose._mixRotate = setup._mixRotate; + pose._mixX = setup._mixX; + pose._mixY = setup._mixY; + pose._mixScaleX = setup._mixScaleX; + pose._mixScaleY = setup._mixScaleY; + pose._mixShearY = setup._mixShearY; } + return; } float rotate, x, y, scaleX, scaleY, shearY; @@ -127,34 +117,21 @@ void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, floa } } - switch (blend) { - case MixBlend_Setup: { - TransformConstraintPose &setup = constraint->_data._setup; - pose._mixRotate = setup._mixRotate + (rotate - setup._mixRotate) * alpha; - pose._mixX = setup._mixX + (x - setup._mixX) * alpha; - pose._mixY = setup._mixY + (y - setup._mixY) * alpha; - pose._mixScaleX = setup._mixScaleX + (scaleX - setup._mixScaleX) * alpha; - pose._mixScaleY = setup._mixScaleY + (scaleY - setup._mixScaleY) * alpha; - pose._mixShearY = setup._mixShearY + (shearY - setup._mixShearY) * alpha; - break; - } - case MixBlend_First: - case MixBlend_Replace: - pose._mixRotate += (rotate - pose._mixRotate) * alpha; - pose._mixX += (x - pose._mixX) * alpha; - pose._mixY += (y - pose._mixY) * alpha; - pose._mixScaleX += (scaleX - pose._mixScaleX) * alpha; - pose._mixScaleY += (scaleY - pose._mixScaleY) * alpha; - pose._mixShearY += (shearY - pose._mixShearY) * alpha; - break; - case MixBlend_Add: - pose._mixRotate += rotate * alpha; - pose._mixX += x * alpha; - pose._mixY += y * alpha; - pose._mixScaleX += scaleX * alpha; - pose._mixScaleY += scaleY * alpha; - pose._mixShearY += shearY * alpha; - break; + TransformConstraintPose &base = fromSetup ? constraint->_data._setup : pose; + if (add) { + pose._mixRotate = base._mixRotate + rotate * alpha; + pose._mixX = base._mixX + x * alpha; + pose._mixY = base._mixY + y * alpha; + pose._mixScaleX = base._mixScaleX + scaleX * alpha; + pose._mixScaleY = base._mixScaleY + scaleY * alpha; + pose._mixShearY = base._mixShearY + shearY * alpha; + } else { + pose._mixRotate = base._mixRotate + (rotate - base._mixRotate) * alpha; + pose._mixX = base._mixX + (x - base._mixX) * alpha; + pose._mixY = base._mixY + (y - base._mixY) * alpha; + pose._mixScaleX = base._mixScaleX + (scaleX - base._mixScaleX) * alpha; + pose._mixScaleY = base._mixScaleY + (scaleY - base._mixScaleY) * alpha; + pose._mixShearY = base._mixShearY + (shearY - base._mixShearY) * alpha; } } diff --git a/spine-cpp/src/spine/TranslateTimeline.cpp b/spine-cpp/src/spine/TranslateTimeline.cpp index d53fbd592..381db1e52 100644 --- a/spine-cpp/src/spine/TranslateTimeline.cpp +++ b/spine-cpp/src/spine/TranslateTimeline.cpp @@ -46,18 +46,12 @@ TranslateTimeline::TranslateTimeline(size_t frameCount, size_t bezierCount, int : BoneTimeline2(frameCount, bezierCount, boneIndex, Property_X, Property_Y) { } -void TranslateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { +void TranslateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); if (time < _frames[0]) { - switch (blend) { - case MixBlend_Setup: - pose._x = setup._x; - pose._y = setup._y; - return; - case MixBlend_First: - pose._x += (setup._x - pose._x) * alpha; - pose._y += (setup._y - pose._y) * alpha; - default: { - } + if (fromSetup) { + pose._x = setup._x; + pose._y = setup._y; } return; } @@ -86,19 +80,15 @@ void TranslateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, fl } } - switch (blend) { - case MixBlend_Setup: - pose._x = setup._x + x * alpha; - pose._y = setup._y + y * alpha; - break; - case MixBlend_First: - case MixBlend_Replace: - pose._x += (setup._x + x - pose._x) * alpha; - pose._y += (setup._y + y - pose._y) * alpha; - break; - case MixBlend_Add: - pose._x += x * alpha; - pose._y += y * alpha; + if (fromSetup) { + pose._x = setup._x + x * alpha; + pose._y = setup._y + y * alpha; + } else if (add) { + pose._x += x * alpha; + pose._y += y * alpha; + } else { + pose._x += (setup._x + x - pose._x) * alpha; + pose._y += (setup._y + y - pose._y) * alpha; } } @@ -108,8 +98,9 @@ TranslateXTimeline::TranslateXTimeline(size_t frameCount, size_t bezierCount, in : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_X) { } -void TranslateXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - pose._x = getRelativeValue(time, alpha, blend, pose._x, setup._x); +void TranslateXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); + pose._x = getRelativeValue(time, alpha, fromSetup, add, pose._x, setup._x); } RTTI_IMPL(TranslateYTimeline, BoneTimeline1) @@ -118,6 +109,7 @@ TranslateYTimeline::TranslateYTimeline(size_t frameCount, size_t bezierCount, in : BoneTimeline1(frameCount, bezierCount, boneIndex, Property_Y) { } -void TranslateYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, MixBlend blend, MixDirection direction) { - pose._y = getRelativeValue(time, alpha, blend, pose._y, setup._y); +void TranslateYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) { + SP_UNUSED(out); + pose._y = getRelativeValue(time, alpha, fromSetup, add, pose._y, setup._y); } \ No newline at end of file diff --git a/spine-cpp/tests/HeadlessTest.cpp b/spine-cpp/tests/HeadlessTest.cpp index 5027beafe..bce96bd1e 100644 --- a/spine-cpp/tests/HeadlessTest.cpp +++ b/spine-cpp/tests/HeadlessTest.cpp @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { setlocale(LC_ALL, "C"); if (argc < 3) { - fprintf(stderr, "Usage: DebugPrinter [animation-name]\n"); + fprintf(stderr, "Usage: HeadlessTest [animation-name] [animation-name-2]\n"); return 1; } @@ -81,6 +81,7 @@ int main(int argc, char *argv[]) { const char *skeletonPath = argv[1]; const char *atlasPath = argv[2]; const char *animationName = argc >= 4 ? argv[3] : nullptr; + const char *animationName2 = argc >= 5 ? argv[4] : nullptr; // Load atlas with headless texture loader HeadlessTextureLoader textureLoader; @@ -147,6 +148,47 @@ int main(int argc, char *argv[]) { printf("%s", serializer.serializeAnimationState(state).buffer()); } + // Transition test: if a second animation is provided, play A for 10 frames, transition to B, + // then sample skeleton state at frames 5, 10, 15, 20 during the mix. + if (state != nullptr && animationName2 != nullptr) { + Animation *animation2 = skeletonData->findAnimation(animationName2); + if (!animation2) { + fprintf(stderr, "Animation not found: %s\n", animationName2); + delete state; + delete stateData; + delete skeletonData; + delete atlas; + return 1; + } + + // Reset skeleton and state + skeleton.setupPose(); + state->clearTracks(); + state->setAnimation(0, *skeletonData->findAnimation(animationName), true); + + // Run 10 frames of animation A + for (int i = 0; i < 10; i++) { + state->update(1 / 60.0f); + state->apply(skeleton); + skeleton.updateWorldTransform(Physics_Update); + } + + // Transition to animation B + state->setAnimation(0, *animation2, true); + + // Run 20 frames through the mix, serializing at frames 5, 10, 15, 20 + for (int i = 1; i <= 20; i++) { + state->update(1 / 60.0f); + state->apply(skeleton); + skeleton.updateWorldTransform(Physics_Update); + if (i == 5 || i == 10 || i == 15 || i == 20) { + SkeletonSerializer transSerializer; + printf("\n=== TRANSITION FRAME %d ===\n", i); + printf("%s", transSerializer.serializeSkeleton(&skeleton).buffer()); + } + } + } + // Cleanup if (state != nullptr) { delete state; diff --git a/spine-cpp/tests/SkeletonSerializer.h b/spine-cpp/tests/SkeletonSerializer.h index 9176edf1b..023c8653a 100644 --- a/spine-cpp/tests/SkeletonSerializer.h +++ b/spine-cpp/tests/SkeletonSerializer.h @@ -1864,21 +1864,8 @@ namespace spine { _json.writeName("mixDuration"); _json.writeValue(obj->getMixDuration()); - _json.writeName("mixBlend"); - _json.writeValue([&]() -> String { - switch (obj->getMixBlend()) { - case MixBlend_Setup: - return "setup"; - case MixBlend_First: - return "first"; - case MixBlend_Replace: - return "replace"; - case MixBlend_Add: - return "add"; - default: - return "unknown"; - } - }()); + _json.writeName("additive"); + _json.writeValue(obj->getAdditive()); _json.writeName("mixingFrom"); if (obj->getMixingFrom() == nullptr) { @@ -1894,8 +1881,6 @@ namespace spine { writeTrackEntry(obj->getMixingTo()); } - _json.writeName("holdPrevious"); - _json.writeValue(obj->getHoldPrevious()); _json.writeName("shortestRotation"); _json.writeValue(obj->getShortestRotation()); @@ -2208,11 +2193,15 @@ namespace spine { writeColor(obj->getColor()); _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - _json.writeValue(obj->getBones()[i]); + if (obj->getBones().size() == 0) { + _json.writeNull(); + } else { + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); + } + _json.writeArrayEnd(); } - _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); @@ -2271,11 +2260,15 @@ namespace spine { writeColor(obj->getColor()); _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - _json.writeValue(obj->getBones()[i]); + if (obj->getBones().size() == 0) { + _json.writeNull(); + } else { + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); + } + _json.writeArrayEnd(); } - _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); @@ -2605,11 +2598,7 @@ namespace spine { _json.writeValue(obj->getHeight()); _json.writeName("sequence"); - if (!obj->getSequence().hasPathSuffix()) { - _json.writeNull(); - } else { - writeSequence(&obj->getSequence()); - } + writeSequence(&obj->getSequence()); _json.writeName("parentMesh"); if (obj->getParentMesh() == nullptr) { @@ -2619,11 +2608,15 @@ namespace spine { } _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - _json.writeValue(obj->getBones()[i]); + if (obj->getBones().size() == 0) { + _json.writeNull(); + } else { + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); + } + _json.writeArrayEnd(); } - _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); @@ -2688,11 +2681,15 @@ namespace spine { writeColor(obj->getColor()); _json.writeName("bones"); - _json.writeArrayStart(); - for (size_t i = 0; i < obj->getBones().size(); i++) { - _json.writeValue(obj->getBones()[i]); + if (obj->getBones().size() == 0) { + _json.writeNull(); + } else { + _json.writeArrayStart(); + for (size_t i = 0; i < obj->getBones().size(); i++) { + _json.writeValue(obj->getBones()[i]); + } + _json.writeArrayEnd(); } - _json.writeArrayEnd(); _json.writeName("vertices"); _json.writeArrayStart(); @@ -3128,11 +3125,7 @@ namespace spine { _json.writeValue(obj->getPath()); _json.writeName("sequence"); - if (!obj->getSequence().hasPathSuffix()) { - _json.writeNull(); - } else { - writeSequence(&obj->getSequence()); - } + writeSequence(&obj->getSequence()); _json.writeName("name"); _json.writeValue(obj->getName()); @@ -3440,10 +3433,10 @@ namespace spine { void writeSkinEntry(Skin::AttachmentMap::Entry *obj) { _json.writeObjectStart(); - String name = obj->_name; + String placeholderName = obj->_placeholderName; String refString; - if (!name.isEmpty()) { - refString.append(""); + if (!placeholderName.isEmpty()) { + refString.append(""); } else { refString.append(""); } @@ -3454,7 +3447,7 @@ namespace spine { _json.writeName("slotIndex"); _json.writeValue((int) obj->_slotIndex); _json.writeName("name"); - _json.writeValue(obj->_name); + _json.writeValue(obj->_placeholderName); _json.writeName("attachment"); writeAttachment(obj->_attachment); _json.writeObjectEnd();