[cpp] 4.3 porting WIP

This commit is contained in:
Mario Zechner 2025-06-24 21:44:32 +02:00
parent 5f74729a2e
commit cba2d4d0d7
26 changed files with 472 additions and 138 deletions

View File

@ -64,9 +64,12 @@ namespace spine {
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose) override;
/// Sets the time and value of the specified keyframe.
/// Sets the time and attachment name for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
void setFrame(int frame, float time, const String &attachmentName);
/// The attachment name for each frame. May contain null values to clear the attachment.
Vector<String> &getAttachmentNames();
protected:

View File

@ -42,6 +42,7 @@ namespace spine {
friend class BoneTimeline1;
friend class BoneTimeline2;
friend class RotateTimeline;
friend class InheritTimeline;
friend class ScaleTimeline;
friend class ScaleXTimeline;
friend class ScaleYTimeline;

View File

@ -38,6 +38,7 @@ namespace spine {
/// Stores the current pose for an IK constraint.
class SP_API IkConstraintPose : public Pose<IkConstraintPose> {
friend class IkConstraint;
friend class IkConstraintTimeline;
public:
IkConstraintPose();

View File

@ -45,11 +45,16 @@ namespace spine {
public:
explicit IkConstraintTimeline(size_t frameCount, size_t bezierCount, int ikConstraintIndex);
virtual ~IkConstraintTimeline();
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose) override;
/// Sets the time, mix and bend direction of the specified keyframe.
/// Sets the time, mix, softness, bend direction, compress, and stretch for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
/// @param bendDirection 1 or -1.
void setFrame(int frame, float time, float mix, float softness, int bendDirection, bool compress, bool stretch);
private:

View File

@ -50,6 +50,9 @@ namespace spine {
virtual ~InheritTimeline();
/// Sets the inherit transform mode for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
void setFrame(int frame, float time, Inherit inherit);
virtual void

View File

@ -53,6 +53,7 @@ namespace spine {
friend class Skeleton;
friend class PathConstraintMixTimeline;
friend class PathConstraintPositionTimeline;
friend class PathConstraintPositionTimeline;
friend class PathConstraintSpacingTimeline;
RTTI_DECL

View File

@ -45,12 +45,16 @@ namespace spine {
public:
explicit PathConstraintMixTimeline(size_t frameCount, size_t bezierCount, int pathConstraintIndex);
virtual ~PathConstraintMixTimeline();
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose);
/// Sets the time and mixes of the specified keyframe.
void setFrame(int frameIndex, float time, float mixRotate, float mixX, float mixY);
/// Sets the time and color for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
void setFrame(int frame, float time, float mixRotate, float mixX, float mixY);
private:
static const int ENTRIES = 4;

View File

@ -37,6 +37,9 @@ namespace spine {
/// Stores a pose for a path constraint.
class SP_API PathConstraintPose : public Pose<PathConstraintPose> {
friend class PathConstraint;
friend class PathConstraintPositionTimeline;
friend class PathConstraintSpacingTimeline;
friend class PathConstraintMixTimeline;
private:
float _position;

View File

@ -30,9 +30,10 @@
#ifndef Spine_PathConstraintSpacingTimeline_h
#define Spine_PathConstraintSpacingTimeline_h
#include <spine/PathConstraintPositionTimeline.h>
#include <spine/ConstraintTimeline1.h>
namespace spine {
/// Changes a path constraint's PathConstraintPose::getSpacing().
class SP_API PathConstraintSpacingTimeline : public ConstraintTimeline1 {
friend class SkeletonBinary;
@ -43,6 +44,8 @@ namespace spine {
public:
explicit PathConstraintSpacingTimeline(size_t frameCount, size_t bezierCount, int pathConstraintIndex);
virtual ~PathConstraintSpacingTimeline();
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose);

View File

@ -61,7 +61,9 @@ namespace spine {
Property_PhysicsConstraintGravity = 1 << 25,
Property_PhysicsConstraintMix = 1 << 26,
Property_PhysicsConstraintReset = 1 << 27,
Property_Sequence = 1 << 28
Property_Sequence = 1 << 28,
Property_SliderTime = 1 << 29,
Property_SliderMix = 1 << 30
};
}

View File

@ -94,6 +94,8 @@ namespace spine {
friend class IkConstraintTimeline;
friend class InheritTimeline;
friend class PathConstraint;
friend class PathConstraintMixTimeline;
@ -102,6 +104,10 @@ namespace spine {
friend class PathConstraintSpacingTimeline;
friend class SliderTimeline;
friend class SliderMixTimeline;
friend class ScaleTimeline;
friend class ScaleXTimeline;

View File

@ -49,6 +49,8 @@ namespace spine {
friend class SkeletonBinary;
friend class SkeletonJson;
friend class Slider;
friend class SliderMixTimeline;
friend class SliderTimeline;
RTTI_DECL

View File

@ -0,0 +1,54 @@
/******************************************************************************
* 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_SliderMixTimeline_h
#define Spine_SliderMixTimeline_h
#include <spine/ConstraintTimeline1.h>
namespace spine {
/// Changes a slider's SliderPose::getMix().
class SP_API SliderMixTimeline : public ConstraintTimeline1 {
friend class SkeletonBinary;
friend class SkeletonJson;
RTTI_DECL
public:
explicit SliderMixTimeline(size_t frameCount, size_t bezierCount, int sliderIndex);
virtual ~SliderMixTimeline();
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose);
};
}
#endif /* Spine_SliderMixTimeline_h */

View File

@ -35,10 +35,12 @@
namespace spine {
class Slider;
/// Stores a pose for a slider.
class SP_API SliderPose : public Pose<SliderPose> {
friend class Slider;
friend class SliderMixTimeline;
friend class SliderTimeline;
private:
float _time, _mix;

View File

@ -0,0 +1,53 @@
/******************************************************************************
* 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_SliderTimeline_h
#define Spine_SliderTimeline_h
#include <spine/ConstraintTimeline1.h>
namespace spine {
class SP_API SliderTimeline : public ConstraintTimeline1 {
friend class SkeletonBinary;
friend class SkeletonJson;
RTTI_DECL
public:
explicit SliderTimeline(size_t frameCount, size_t bezierCount, int sliderIndex);
virtual ~SliderTimeline();
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose);
};
}
#endif /* Spine_SliderTimeline_h */

View File

@ -51,6 +51,7 @@ namespace spine {
friend class FromShearY;
friend class ToShearY;
friend class TransformConstraint;
friend class TransformConstraintTimeline;
private:
float _mixRotate, _mixX, _mixY, _mixScaleX, _mixScaleY, _mixShearY;

View File

@ -45,11 +45,16 @@ namespace spine {
public:
explicit TransformConstraintTimeline(size_t frameCount, size_t bezierCount, int transformConstraintIndex);
virtual ~TransformConstraintTimeline();
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose);
void setFrame(size_t frameIndex, float time, float mixRotate, float mixX, float mixY, float mixScaleX,
/// Sets the time, rotate mix, translate mix, scale mix, and shear mix for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
void setFrame(int frame, float time, float mixRotate, float mixX, float mixY, float mixScaleX,
float mixScaleY, float mixShearY);
private:

View File

@ -67,7 +67,7 @@ void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, V
SP_UNUSED(alpha);
Slot *slot = skeleton._slots[_slotIndex];
if (!slot->_bone._active) return;
if (!slot->_bone.isActive()) return;
SlotPose &pose = appliedPose ? *slot->_applied : slot->_pose;
if (direction == MixDirection_Out) {

View File

@ -35,6 +35,7 @@
#include <spine/Animation.h>
#include <spine/IkConstraint.h>
#include <spine/IkConstraintData.h>
#include <spine/IkConstraintPose.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
@ -49,33 +50,34 @@ IkConstraintTimeline::IkConstraintTimeline(size_t frameCount, size_t bezierCount
setPropertyIds(ids, 1);
}
IkConstraintTimeline::~IkConstraintTimeline() {
}
void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(appliedPose);
IkConstraint *constraintP = (IkConstraint *) skeleton._constraints[_constraintIndex];
IkConstraint &constraint = *constraintP;
if (!constraint.isActive()) return;
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:
constraint.getAppliedPose().setMix(constraint._data.getSetupPose().getMix());
constraint.getAppliedPose().setSoftness(constraint._data.getSetupPose().getSoftness());
constraint.getAppliedPose().setBendDirection(constraint._data.getSetupPose().getBendDirection());
constraint.getAppliedPose().setCompress(constraint._data.getSetupPose().getCompress());
constraint.getAppliedPose().setStretch(constraint._data.getSetupPose().getStretch());
pose._mix = setup._mix;
pose._softness = setup._softness;
pose._bendDirection = setup._bendDirection;
pose._compress = setup._compress;
pose._stretch = setup._stretch;
return;
case MixBlend_First:
constraint.getAppliedPose().setMix(constraint.getAppliedPose().getMix() +
(constraint._data.getSetupPose().getMix() - constraint.getAppliedPose().getMix()) * alpha);
constraint.getAppliedPose().setSoftness(constraint.getAppliedPose().getSoftness() +
(constraint._data.getSetupPose().getSoftness() - constraint.getAppliedPose().getSoftness()) * alpha);
constraint.getAppliedPose().setBendDirection(constraint._data.getSetupPose().getBendDirection());
constraint.getAppliedPose().setCompress(constraint._data.getSetupPose().getCompress());
constraint.getAppliedPose().setStretch(constraint._data.getSetupPose().getStretch());
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;
@ -83,57 +85,59 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time,
}
float mix = 0, softness = 0;
int i = Animation::search(_frames, time, IkConstraintTimeline::ENTRIES);
int curveType = (int) _curves[i / IkConstraintTimeline::ENTRIES];
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i / ENTRIES];
switch (curveType) {
case IkConstraintTimeline::LINEAR: {
case LINEAR: {
float before = _frames[i];
mix = _frames[i + IkConstraintTimeline::MIX];
softness = _frames[i + IkConstraintTimeline::SOFTNESS];
float t = (time - before) / (_frames[i + IkConstraintTimeline::ENTRIES] - before);
mix += (_frames[i + IkConstraintTimeline::ENTRIES + IkConstraintTimeline::MIX] - mix) * t;
softness += (_frames[i + IkConstraintTimeline::ENTRIES + IkConstraintTimeline::SOFTNESS] - softness) * t;
mix = _frames[i + MIX];
softness = _frames[i + SOFTNESS];
float t = (time - before) / (_frames[i + ENTRIES] - before);
mix += (_frames[i + ENTRIES + MIX] - mix) * t;
softness += (_frames[i + ENTRIES + SOFTNESS] - softness) * t;
break;
}
case IkConstraintTimeline::STEPPED: {
mix = _frames[i + IkConstraintTimeline::MIX];
softness = _frames[i + IkConstraintTimeline::SOFTNESS];
case STEPPED: {
mix = _frames[i + MIX];
softness = _frames[i + SOFTNESS];
break;
}
default: {
mix = getBezierValue(time, i, IkConstraintTimeline::MIX, curveType - IkConstraintTimeline::BEZIER);
softness = getBezierValue(time, i, IkConstraintTimeline::SOFTNESS,
curveType + IkConstraintTimeline::BEZIER_SIZE -
IkConstraintTimeline::BEZIER);
mix = getBezierValue(time, i, MIX, curveType - BEZIER);
softness = getBezierValue(time, i, SOFTNESS,
curveType + BEZIER_SIZE -
BEZIER);
}
}
if (blend == MixBlend_Setup) {
constraint.getAppliedPose().setMix(constraint._data.getSetupPose().getMix() +
(mix - constraint._data.getSetupPose().getMix()) * alpha);
constraint.getAppliedPose().setSoftness(constraint._data.getSetupPose().getSoftness() +
(softness - constraint._data.getSetupPose().getSoftness()) * alpha);
if (direction == MixDirection_Out) {
constraint.getAppliedPose().setBendDirection(constraint._data.getSetupPose().getBendDirection());
constraint.getAppliedPose().setCompress(constraint._data.getSetupPose().getCompress());
constraint.getAppliedPose().setStretch(constraint._data.getSetupPose().getStretch());
} else {
constraint.getAppliedPose().setBendDirection(_frames[i + IkConstraintTimeline::BEND_DIRECTION]);
constraint.getAppliedPose().setCompress(_frames[i + IkConstraintTimeline::COMPRESS] != 0);
constraint.getAppliedPose().setStretch(_frames[i + IkConstraintTimeline::STRETCH] != 0);
}
} else {
constraint.getAppliedPose().setMix(constraint.getAppliedPose().getMix() +
(mix - constraint.getAppliedPose().getMix()) * alpha);
constraint.getAppliedPose().setSoftness(constraint.getAppliedPose().getSoftness() +
(softness - constraint.getAppliedPose().getSoftness()) * alpha);
if (direction == MixDirection_In) {
constraint.getAppliedPose().setBendDirection(_frames[i + IkConstraintTimeline::BEND_DIRECTION]);
constraint.getAppliedPose().setCompress(_frames[i + IkConstraintTimeline::COMPRESS] != 0);
constraint.getAppliedPose().setStretch(_frames[i + IkConstraintTimeline::STRETCH] != 0);
switch (blend) {
case 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;
}
break;
}
case MixBlend_First:
case MixBlend_Replace:
pose._mix += (mix - pose._mix) * alpha;
pose._softness += (softness - pose._softness) * alpha;
if (direction == MixDirection_Out) return;
break;
case MixBlend_Add:
pose._mix += mix * alpha;
pose._softness += softness * alpha;
if (direction == MixDirection_Out) return;
break;
}
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,

View File

@ -34,6 +34,7 @@
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/BoneLocal.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
@ -53,7 +54,7 @@ InheritTimeline::~InheritTimeline() {
void InheritTimeline::setFrame(int frame, float time, Inherit inherit) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + INHERIT] = inherit;
_frames[frame + INHERIT] = (float)inherit;
}
@ -61,22 +62,21 @@ void InheritTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vect
MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
SP_UNUSED(alpha);
SP_UNUSED(appliedPose);
Bone *bone = skeleton.getBones()[_boneIndex];
Bone *bone = skeleton._bones[_boneIndex];
if (!bone->isActive()) return;
BoneLocal &pose = appliedPose ? *bone->_applied : bone->_pose;
if (direction == MixDirection_Out) {
if (blend == MixBlend_Setup) bone->_inherit = bone->_data.getInherit();
if (blend == MixBlend_Setup) pose._inherit = bone->_data._setup._inherit;
return;
}
if (time < _frames[0]) {
if (blend == MixBlend_Setup || blend == MixBlend_First) bone->_inherit = bone->_data.getInherit();
return;
if (blend == MixBlend_Setup || blend == MixBlend_First) pose._inherit = bone->_data._setup._inherit;
} else {
int idx = Animation::search(_frames, time, ENTRIES) + INHERIT;
pose._inherit = static_cast<Inherit>((int)_frames[idx]);
}
int idx = Animation::search(_frames, time, ENTRIES) + INHERIT;
bone->_inherit = static_cast<Inherit>(_frames[idx]);
}

View File

@ -35,6 +35,7 @@
#include <spine/Animation.h>
#include <spine/PathConstraint.h>
#include <spine/PathConstraintData.h>
#include <spine/PathConstraintPose.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
@ -50,31 +51,35 @@ PathConstraintMixTimeline::PathConstraintMixTimeline(size_t frameCount, size_t b
setPropertyIds(ids, 1);
}
PathConstraintMixTimeline::~PathConstraintMixTimeline() {
}
void PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
PathConstraint *constraintP = skeleton._cons[_constraintIndex];
PathConstraint &constraint = *constraintP;
if (!constraint.isActive()) return;
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:
constraint._mixRotate = constraint._data._mixRotate;
constraint._mixX = constraint._data._mixX;
constraint._mixY = constraint._data._mixY;
pose._mixRotate = setup._mixRotate;
pose._mixX = setup._mixX;
pose._mixY = setup._mixY;
return;
case MixBlend_First:
constraint._mixRotate += (constraint._data._mixRotate - constraint._mixRotate) * alpha;
constraint._mixX += (constraint._data._mixX - constraint._mixX) * alpha;
constraint._mixY += (constraint._data._mixY - constraint._mixY) * alpha;
default: {
}
pose._mixRotate += (setup._mixRotate - pose._mixRotate) * alpha;
pose._mixX += (setup._mixX - pose._mixX) * alpha;
pose._mixY += (setup._mixY - pose._mixY) * alpha;
return;
default:
return;
}
return;
}
float rotate, x, y;
@ -105,15 +110,25 @@ void PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float
}
}
if (blend == MixBlend_Setup) {
PathConstraintData data = constraint._data;
constraint._mixRotate = data._mixRotate + (rotate - data._mixRotate) * alpha;
constraint._mixX = data._mixX + (x - data._mixX) * alpha;
constraint._mixY = data._mixY + (y - data._mixY) * alpha;
} else {
constraint._mixRotate += (rotate - constraint._mixRotate) * alpha;
constraint._mixX += (x - constraint._mixX) * alpha;
constraint._mixY += (y - constraint._mixY) * alpha;
switch (blend) {
case 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;
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;
break;
case MixBlend_Add:
pose._mixRotate += rotate * alpha;
pose._mixX += x * alpha;
pose._mixY += y * alpha;
break;
}
}

View File

@ -45,9 +45,9 @@ RTTI_IMPL(PathConstraintPositionTimeline, ConstraintTimeline1)
PathConstraintPositionTimeline::PathConstraintPositionTimeline(size_t frameCount, size_t bezierCount,
int pathConstraintIndex) : ConstraintTimeline1(frameCount,
bezierCount,
pathConstraintIndex,
Property_PathConstraintPosition) {
bezierCount,
pathConstraintIndex,
Property_PathConstraintPosition) {
PropertyId ids[] = {((PropertyId) Property_PathConstraintPosition << 32) | pathConstraintIndex};
setPropertyIds(ids, 1);
}
@ -61,6 +61,10 @@ void PathConstraintPositionTimeline::apply(Skeleton &skeleton, float lastTime, f
SP_UNUSED(pEvents);
SP_UNUSED(direction);
PathConstraint *constraint = skeleton._pathConstraints[_constraintIndex];
if (constraint->_active) constraint->_position = getAbsoluteValue(time, alpha, blend, constraint->_position, constraint->_data._position);
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);
}
}

View File

@ -52,13 +52,19 @@ PathConstraintSpacingTimeline::PathConstraintSpacingTimeline(size_t frameCount,
setPropertyIds(ids, 1);
}
PathConstraintSpacingTimeline::~PathConstraintSpacingTimeline() {
}
void PathConstraintSpacingTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
float alpha, MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
PathConstraint *constraint = skeleton._pathConstraints[_pathConstraintIndex];
if (constraint->_active)
constraint->_spacing = getAbsoluteValue(time, alpha, blend, constraint->_spacing, constraint->_data._spacing);
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, pose._spacing, data._setup._spacing);
}
}

View File

@ -0,0 +1,69 @@
/******************************************************************************
* 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.
*****************************************************************************/
#include <spine/SliderMixTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Slider.h>
#include <spine/SliderData.h>
#include <spine/SliderPose.h>
#include <spine/Property.h>
using namespace spine;
RTTI_IMPL(SliderMixTimeline, ConstraintTimeline1)
SliderMixTimeline::SliderMixTimeline(size_t frameCount, size_t bezierCount,
int sliderIndex) : ConstraintTimeline1(frameCount,
bezierCount,
sliderIndex,
Property_SliderMix) {
PropertyId ids[] = {((PropertyId) Property_SliderMix << 32) | sliderIndex};
setPropertyIds(ids, 1);
}
SliderMixTimeline::~SliderMixTimeline() {
}
void SliderMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
float alpha, MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
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);
}
}

View File

@ -0,0 +1,69 @@
/******************************************************************************
* 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.
*****************************************************************************/
#include <spine/SliderTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Slider.h>
#include <spine/SliderData.h>
#include <spine/SliderPose.h>
#include <spine/Property.h>
using namespace spine;
RTTI_IMPL(SliderTimeline, ConstraintTimeline1)
SliderTimeline::SliderTimeline(size_t frameCount, size_t bezierCount,
int sliderIndex) : ConstraintTimeline1(frameCount,
bezierCount,
sliderIndex,
Property_SliderTime) {
PropertyId ids[] = {((PropertyId) Property_SliderTime << 32) | sliderIndex};
setPropertyIds(ids, 1);
}
SliderTimeline::~SliderTimeline() {
}
void SliderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
float alpha, MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
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);
}
}

View File

@ -38,6 +38,7 @@
#include <spine/SlotData.h>
#include <spine/TransformConstraint.h>
#include <spine/TransformConstraintData.h>
#include <spine/TransformConstraintPose.h>
using namespace spine;
@ -52,34 +53,37 @@ TransformConstraintTimeline::TransformConstraintTimeline(size_t frameCount, size
setPropertyIds(ids, 1);
}
TransformConstraintTimeline::~TransformConstraintTimeline() {
}
void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
float alpha, MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
TransformConstraint *constraintP = skeleton._transformConstraints[_constraintIndex];
TransformConstraint &constraint = *constraintP;
if (!constraint.isActive()) return;
TransformConstraint *constraint = (TransformConstraint *) skeleton._constraints[_constraintIndex];
if (!constraint->isActive()) return;
TransformConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
TransformConstraintData &data = constraint._data;
if (time < _frames[0]) {
TransformConstraintPose &setup = constraint->_data._setup;
switch (blend) {
case MixBlend_Setup:
constraint._mixRotate = data._mixRotate;
constraint._mixX = data._mixX;
constraint._mixY = data._mixY;
constraint._mixScaleX = data._mixScaleX;
constraint._mixScaleY = data._mixScaleY;
constraint._mixShearY = data._mixShearY;
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:
constraint._mixRotate += (data._mixRotate - constraint._mixRotate) * alpha;
constraint._mixX += (data._mixX - constraint._mixX) * alpha;
constraint._mixY += (data._mixY - constraint._mixY) * alpha;
constraint._mixScaleX += (data._mixScaleX - constraint._mixScaleX) * alpha;
constraint._mixScaleY += (data._mixScaleY - constraint._mixScaleY) * alpha;
constraint._mixShearY += (data._mixShearY - constraint._mixShearY) * alpha;
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;
@ -87,10 +91,10 @@ void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, floa
}
float rotate, x, y, scaleX, scaleY, shearY;
int i = Animation::search(_frames, time, TransformConstraintTimeline::ENTRIES);
int curveType = (int) _curves[i / TransformConstraintTimeline::ENTRIES];
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i / ENTRIES];
switch (curveType) {
case TransformConstraintTimeline::LINEAR: {
case LINEAR: {
float before = _frames[i];
rotate = _frames[i + ROTATE];
x = _frames[i + X];
@ -107,7 +111,7 @@ void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, floa
shearY += (_frames[i + ENTRIES + SHEARY] - shearY) * t;
break;
}
case TransformConstraintTimeline::STEPPED: {
case STEPPED: {
rotate = _frames[i + ROTATE];
x = _frames[i + X];
y = _frames[i + Y];
@ -126,24 +130,38 @@ void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, floa
}
}
if (blend == MixBlend_Setup) {
constraint._mixRotate = data._mixRotate + (rotate - data._mixRotate) * alpha;
constraint._mixX = data._mixX + (x - data._mixX) * alpha;
constraint._mixY = data._mixY + (y - data._mixY) * alpha;
constraint._mixScaleX = data._mixScaleX + (scaleX - data._mixScaleX) * alpha;
constraint._mixScaleY = data._mixScaleY + (scaleY - data._mixScaleY) * alpha;
constraint._mixShearY = data._mixShearY + (shearY - data._mixShearY) * alpha;
} else {
constraint._mixRotate += (rotate - constraint._mixRotate) * alpha;
constraint._mixX += (x - constraint._mixX) * alpha;
constraint._mixY += (y - constraint._mixY) * alpha;
constraint._mixScaleX += (scaleX - constraint._mixScaleX) * alpha;
constraint._mixScaleY += (scaleY - constraint._mixScaleY) * alpha;
constraint._mixShearY += (shearY - constraint._mixShearY) * alpha;
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;
}
}
void TransformConstraintTimeline::setFrame(size_t frame, float time, float mixRotate, float mixX, float mixY,
void TransformConstraintTimeline::setFrame(int frame, float time, float mixRotate, float mixX, float mixY,
float mixScaleX, float mixScaleY, float mixShearY) {
frame *= ENTRIES;
_frames[frame] = time;
@ -153,4 +171,4 @@ void TransformConstraintTimeline::setFrame(size_t frame, float time, float mixRo
_frames[frame + SCALEX] = mixScaleX;
_frames[frame + SCALEY] = mixScaleY;
_frames[frame + SHEARY] = mixShearY;
}
}