[cpp] Inherit timeline, latest ports from reference implementation, excluding loaders

This commit is contained in:
Mario Zechner 2024-03-28 12:09:20 +01:00
parent ce9bcd711d
commit 8210d25e2e
27 changed files with 439 additions and 197 deletions

View File

@ -250,6 +250,8 @@ namespace spine {
void setMixDuration(float inValue);
void setMixDuration(float mixDuration, float delay);
MixBlend getMixBlend();
void setMixBlend(MixBlend blend);
@ -277,6 +279,9 @@ namespace spine {
void setListener(AnimationStateListenerObject *listener);
/// Returns true if this track entry has been applied at least once.
///
/// See AnimationState::apply(Skeleton).
bool wasApplied();
private:

View File

@ -33,6 +33,7 @@
#include <spine/Updatable.h>
#include <spine/SpineObject.h>
#include <spine/Vector.h>
#include <spine/Inherit.h>
namespace spine {
class BoneData;
@ -95,6 +96,8 @@ namespace spine {
friend class TranslateYTimeline;
friend class InheritTimeline;
RTTI_DECL
public:
@ -125,8 +128,12 @@ namespace spine {
void worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY);
void worldToParent(float worldX, float worldY, float &outParentX, float &outParentY);
void localToWorld(float localX, float localY, float &outWorldX, float &outWorldY);
void parentToWorld(float worldX, float worldY, float &outX, float &outY);
float worldToLocalRotation(float worldRotation);
float localToWorldRotation(float localRotation);
@ -255,6 +262,10 @@ namespace spine {
void setActive(bool inValue);
Inherit getInherit() { return _inherit; }
void setInherit(Inherit inValue) { _inherit = inValue; }
private:
static bool yDown;
@ -268,6 +279,7 @@ namespace spine {
float _c, _d, _worldY;
bool _sorted;
bool _active;
Inherit _inherit;
};
}

View File

@ -30,7 +30,7 @@
#ifndef Spine_BoneData_h
#define Spine_BoneData_h
#include <spine/TransformMode.h>
#include <spine/Inherit.h>
#include <spine/SpineObject.h>
#include <spine/SpineString.h>
#include <spine/Color.h>
@ -115,9 +115,9 @@ namespace spine {
void setShearY(float inValue);
/// The transform mode for how parent world transforms affect this bone.
TransformMode getTransformMode();
Inherit getInherit();
void setTransformMode(TransformMode inValue);
void setInherit(Inherit inValue);
bool isSkinRequired();
@ -139,7 +139,7 @@ namespace spine {
BoneData *_parent;
float _length;
float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
TransformMode _transformMode;
Inherit _inherit;
bool _skinRequired;
Color _color;
String _icon;

View File

@ -31,12 +31,12 @@
#define Spine_TransformMode_h
namespace spine {
enum TransformMode {
TransformMode_Normal = 0,
TransformMode_OnlyTranslation,
TransformMode_NoRotationOrReflection,
TransformMode_NoScale,
TransformMode_NoScaleOrReflection
enum Inherit {
Inherit_Normal = 0,
Inherit_OnlyTranslation,
Inherit_NoRotationOrReflection,
Inherit_NoScale,
Inherit_NoScaleOrReflection
};
}

View File

@ -0,0 +1,68 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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_InheritTimeline_h
#define Spine_InheritTimeline_h
#include <spine/Timeline.h>
#include <spine/Animation.h>
#include <spine/Property.h>
#include <spine/Inherit.h>
namespace spine {
class SP_API InheritTimeline : public Timeline {
friend class SkeletonBinary;
friend class SkeletonJson;
RTTI_DECL
public:
explicit InheritTimeline(size_t frameCount, int boneIndex);
virtual ~InheritTimeline();
void setFrame(int frame, float time, Inherit inherit);
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction);
int getBoneIndex() { return _boneIndex; }
void setBoneIndex(int inValue) { _boneIndex = inValue; }
private:
int _boneIndex;
};
}
#endif /* Spine_InheritTimeline_h */

View File

@ -76,6 +76,10 @@ namespace spine {
float getShearX() const;
void setLimit(float limit);
float getLimit() const;
void setStep(float step);
float getStep() const;
@ -138,7 +142,7 @@ namespace spine {
private:
BoneData *_bone;
float _x, _y, _rotate, _scaleX, _shearX;
float _x, _y, _rotate, _scaleX, _shearX, _limit;
float _step, _inertia, _strength, _damping, _massInverse, _wind, _gravity, _mix;
bool _inertiaGlobal, _strengthGlobal, _dampingGlobal, _massGlobal, _windGlobal, _gravityGlobal, _mixGlobal;
};

View File

@ -40,27 +40,28 @@ namespace spine {
Property_ScaleY = 1 << 4,
Property_ShearX = 1 << 5,
Property_ShearY = 1 << 6,
Property_Rgb = 1 << 7,
Property_Alpha = 1 << 8,
Property_Rgb2 = 1 << 9,
Property_Attachment = 1 << 10,
Property_Deform = 1 << 11,
Property_Event = 1 << 12,
Property_DrawOrder = 1 << 13,
Property_IkConstraint = 1 << 14,
Property_TransformConstraint = 1 << 15,
Property_PathConstraintPosition = 1 << 16,
Property_PathConstraintSpacing = 1 << 17,
Property_PathConstraintMix = 1 << 18,
Property_PhysicsConstraintInertia = 1 << 19,
Property_PhysicsConstraintStrength = 1 << 20,
Property_PhysicsConstraintDamping = 1 << 21,
Property_PhysicsConstraintMass = 1 << 22,
Property_PhysicsConstraintWind = 1 << 23,
Property_PhysicsConstraintGravity = 1 << 24,
Property_PhysicsConstraintMix = 1 << 25,
Property_PhysicsConstraintReset = 1 << 26,
Property_Sequence = 1 << 27
Property_Inherit = 1 << 7,
Property_Rgb = 1 << 8,
Property_Alpha = 1 << 9,
Property_Rgb2 = 1 << 10,
Property_Attachment = 1 << 11,
Property_Deform = 1 << 12,
Property_Event = 1 << 13,
Property_DrawOrder = 1 << 14,
Property_IkConstraint = 1 << 15,
Property_TransformConstraint = 1 << 16,
Property_PathConstraintPosition = 1 << 17,
Property_PathConstraintSpacing = 1 << 18,
Property_PathConstraintMix = 1 << 19,
Property_PhysicsConstraintInertia = 1 << 20,
Property_PhysicsConstraintStrength = 1 << 21,
Property_PhysicsConstraintDamping = 1 << 22,
Property_PhysicsConstraintMass = 1 << 23,
Property_PhysicsConstraintWind = 1 << 24,
Property_PhysicsConstraintGravity = 1 << 25,
Property_PhysicsConstraintMix = 1 << 26,
Property_PhysicsConstraintReset = 1 << 27,
Property_Sequence = 1 << 28
};
}

View File

@ -30,7 +30,7 @@
#ifndef Spine_SkeletonBinary_h
#define Spine_SkeletonBinary_h
#include <spine/TransformMode.h>
#include <spine/Inherit.h>
#include <spine/Vector.h>
#include <spine/SpineObject.h>
#include <spine/SpineString.h>

View File

@ -141,6 +141,10 @@ namespace spine {
void setHeight(float inValue);
float getReferenceScale();
void setReferenceScale(float inValue);
/// The Spine version used to export this data, or NULL.
const String &getVersion();
@ -176,6 +180,7 @@ namespace spine {
Vector<PathConstraintData *> _pathConstraints;
Vector<PhysicsConstraintData *> _physicsConstraints;
float _x, _y, _width, _height;
float _referenceScale;
String _version;
String _hash;
Vector<char *> _strings;

View File

@ -32,6 +32,7 @@
#include <spine/Vector.h>
#include <spine/SpineString.h>
#include <spine/Color.h>
namespace spine {
class Attachment;
@ -153,11 +154,14 @@ namespace spine {
Vector<ConstraintData *> &getConstraints();
Color &getColor() { return _color; }
private:
const String _name;
AttachmentMap _attachments;
Vector<BoneData *> _bones;
Vector<ConstraintData *> _constraints;
Color _color;
/// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.
void attachAll(Skeleton &skeleton, Skin &oldSkin);

View File

@ -109,6 +109,10 @@ namespace spine {
void setVisible(bool inValue);
String &getPath() { return _path; }
void setPath(const String &inValue) { _path = inValue; }
private:
const int _index;
String _name;
@ -120,6 +124,7 @@ namespace spine {
String _attachmentName;
BlendMode _blendMode;
bool _visible;
String _path;
};
}

View File

@ -60,6 +60,7 @@
#include <spine/IkConstraint.h>
#include <spine/IkConstraintData.h>
#include <spine/IkConstraintTimeline.h>
#include <spine/InheritTimeline.h>
#include <spine/Json.h>
#include <spine/LinkedMesh.h>
#include <spine/MathUtil.h>
@ -101,7 +102,7 @@
#include <spine/TransformConstraint.h>
#include <spine/TransformConstraintData.h>
#include <spine/TransformConstraintTimeline.h>
#include <spine/TransformMode.h>
#include <spine/Inherit.h>
#include <spine/TranslateTimeline.h>
#include <spine/Triangulator.h>
#include <spine/Updatable.h>

View File

@ -162,6 +162,12 @@ float TrackEntry::getMixDuration() { return _mixDuration; }
void TrackEntry::setMixDuration(float inValue) { _mixDuration = inValue; }
void TrackEntry::setMixDuration(float mixDuration, float delay) {
_mixDuration = mixDuration;
if (_previous && delay <= 0) delay += _previous->getTrackComplete() - mixDuration;
this->_delay = delay;
}
TrackEntry *TrackEntry::getMixingFrom() { return _mixingFrom; }
TrackEntry *TrackEntry::getMixingTo() { return _mixingTo; }
@ -484,7 +490,7 @@ bool AnimationState::apply(Skeleton &skeleton) {
timelineBlend, timelinesRotation, ii << 1, firstFrame);
else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, applyTime,
timelineBlend, true);
blend, attachments);
else
timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend,
MixDirection_In);
@ -928,10 +934,16 @@ void AnimationState::queueEvents(TrackEntry *entry, float animationTime) {
// Queue complete if completed a loop iteration or the animation.
bool complete = false;
if (entry->_loop)
complete = duration == 0 || (trackLastWrapped > MathUtil::fmod(entry->_trackTime, duration));
else
complete = animationTime >= animationEnd && entry->_animationLast < animationEnd;
if (entry->_loop) {
if (duration == 0)
complete = true;
else {
int cycles = (int) (entry->_trackTime / duration);
complete = cycles > 0 && cycles > (int) (entry->_trackLast / duration);
}
} else {
complete = animationTime >= animationEnd && entry->_animationLast < animationEnd;
}
if (complete) _queue->complete(entry);
// Queue events after complete.
@ -985,8 +997,8 @@ TrackEntry *AnimationState::newTrackEntry(size_t trackIndex, Animation *animatio
entry._shortestRotation = false;
entry._eventThreshold = 0;
entry._mixAttachmentThreshold = 0;
entry._alphaAttachmentThreshold = 0;
entry._mixAttachmentThreshold = 0;
entry._mixDrawOrderThreshold = 0;
entry._animationStart = 0;

View File

@ -71,7 +71,8 @@ Bone::Bone(BoneData &data, Skeleton &skeleton, Bone *parent) : Updatable(),
_d(1),
_worldY(0),
_sorted(false),
_active(false) {
_active(false),
_inherit(Inherit_Normal){
setToSetupPose();
}
@ -118,8 +119,8 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
_worldX = pa * x + pb * y + parent->_worldX;
_worldY = pc * x + pd * y + parent->_worldY;
switch (_data.getTransformMode()) {
case TransformMode_Normal: {
switch (_inherit) {
case Inherit_Normal: {
float rx = (rotation + shearX) * MathUtil::Deg_Rad;
float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
float la = MathUtil::cos(rx) * scaleX;
@ -132,7 +133,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
_d = pc * lb + pd * ld;
return;
}
case TransformMode_OnlyTranslation: {
case Inherit_OnlyTranslation: {
float rx = (rotation + shearX) * MathUtil::Deg_Rad;
float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
_a = MathUtil::cos(rx) * scaleX;
@ -141,7 +142,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
_d = MathUtil::sin(ry) * scaleY;
break;
}
case TransformMode_NoRotationOrReflection: {
case Inherit_NoRotationOrReflection: {
float s = pa * pa + pc * pc;
float prx;
if (s > 0.0001f) {
@ -150,11 +151,11 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
pc /= _skeleton.getScaleY();
pb = pc * s;
pd = pa * s;
prx = MathUtil::atan2(pc, pa) * MathUtil::Rad_Deg;
prx = MathUtil::atan2Deg(pc, pa);
} else {
pa = 0;
pc = 0;
prx = 90 - MathUtil::atan2(pd, pb) * MathUtil::Rad_Deg;
prx = 90 - MathUtil::atan2Deg(pd, pb);
}
float rx = (rotation + shearX - prx) * MathUtil::Deg_Rad;
float ry = (rotation + shearY - prx + 90) * MathUtil::Deg_Rad;
@ -168,8 +169,8 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
_d = pc * lb + pd * ld;
break;
}
case TransformMode_NoScale:
case TransformMode_NoScaleOrReflection: {
case Inherit_NoScale:
case Inherit_NoScaleOrReflection: {
rotation *= MathUtil::Deg_Rad;
float cosine = MathUtil::cos(rotation);
float sine = MathUtil::sin(rotation);
@ -180,7 +181,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
za *= s;
zc *= s;
s = MathUtil::sqrt(za * za + zc * zc);
if (_data.getTransformMode() == TransformMode_NoScale &&
if (_inherit == Inherit_NoScale &&
(pa * pd - pb * pc < 0) != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
s = -s;
rotation = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
@ -213,6 +214,7 @@ void Bone::setToSetupPose() {
_scaleY = data.getScaleY();
_shearX = data.getShearX();
_shearY = data.getShearY();
_inherit = data.getInherit();
}
void Bone::worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY) {
@ -229,25 +231,39 @@ void Bone::worldToLocal(float worldX, float worldY, float &outLocalX, float &out
outLocalY = (y * a * invDet - x * c * invDet);
}
void Bone::worldToParent(float worldX, float worldY, float &outParentX, float &outParentY) {
if (!_parent) {
outParentX = worldX;
outParentY = worldY;
} else {
_parent->worldToLocal(worldX, worldY, outParentX, outParentY);
}
}
void Bone::localToWorld(float localX, float localY, float &outWorldX, float &outWorldY) {
outWorldX = localX * _a + localY * _b + _worldX;
outWorldY = localX * _c + localY * _d + _worldY;
}
float Bone::worldToLocalRotation(float worldRotation) {
float sin = MathUtil::sinDeg(worldRotation);
float cos = MathUtil::cosDeg(worldRotation);
void Bone::parentToWorld(float worldX, float worldY, float &outX, float &outY) {
if (!_parent) {
outX = worldX;
outY = worldY;
} else {
_parent->localToWorld(worldX, worldY, outX, outY);
}
}
return MathUtil::atan2(_a * sin - _c * cos, _d * cos - _b * sin) * MathUtil::Rad_Deg + this->_rotation -
this->_shearX;
float Bone::worldToLocalRotation(float worldRotation) {
worldRotation *= MathUtil::Deg_Rad;
float sine = MathUtil::sin(worldRotation), cosine = MathUtil::cos(worldRotation);
return MathUtil::atan2Deg(_a * sine - _c * cosine, _d * cosine - _b * sine) + _rotation - _shearX;
}
float Bone::localToWorldRotation(float localRotation) {
localRotation -= this->_rotation - this->_shearX;
float sin = MathUtil::sinDeg(localRotation);
float cos = MathUtil::cosDeg(localRotation);
return MathUtil::atan2(cos * _c + sin * _d, cos * _a + sin * _b) * MathUtil::Rad_Deg;
localRotation = (localRotation - _rotation - _shearX) * MathUtil::Deg_Rad;
float sine = MathUtil::sin(localRotation), cosine = MathUtil::cos(localRotation);
return MathUtil::atan2Deg(cosine * _c + sine * _d, cosine * _a + sine * _b);
}
void Bone::rotateWorld(float degrees) {
@ -469,11 +485,11 @@ void Bone::setWorldY(float inValue) {
}
float Bone::getWorldRotationX() {
return MathUtil::atan2(_c, _a) * MathUtil::Rad_Deg;
return MathUtil::atan2Deg(_c, _a);
}
float Bone::getWorldRotationY() {
return MathUtil::atan2(_d, _b) * MathUtil::Rad_Deg;
return MathUtil::atan2Deg(_d, _b);
}
float Bone::getWorldScaleX() {
@ -489,11 +505,11 @@ void Bone::updateAppliedTransform() {
if (!parent) {
_ax = _worldX - _skeleton.getX();
_ay = _worldY - _skeleton.getY();
_arotation = MathUtil::atan2(_c, _a) * MathUtil::Rad_Deg;
_arotation = MathUtil::atan2Deg(_c, _a);
_ascaleX = MathUtil::sqrt(_a * _a + _c * _c);
_ascaleY = MathUtil::sqrt(_b * _b + _d * _d);
_ashearX = 0;
_ashearY = MathUtil::atan2(_a * _b + _c * _d, _a * _d - _b * _c) * MathUtil::Rad_Deg;
_ashearY = MathUtil::atan2Deg(_a * _b + _c * _d, _a * _d - _b * _c);
}
float pa = parent->_a, pb = parent->_b, pc = parent->_c, pd = parent->_d;
float pid = 1 / (pa * pd - pb * pc);
@ -503,14 +519,14 @@ void Bone::updateAppliedTransform() {
_ay = (dy * id - dx * ic);
float ra, rb, rc, rd;
if (_data.getTransformMode() == TransformMode_OnlyTranslation) {
if (_inherit == Inherit_OnlyTranslation) {
ra = _a;
rb = _b;
rc = _c;
rd = _d;
} else {
switch (_data.getTransformMode()) {
case TransformMode_NoRotationOrReflection: {
switch (_inherit) {
case Inherit_NoRotationOrReflection: {
float s = MathUtil::abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
float sa = pa / _skeleton.getScaleX();
float sc = pc / _skeleton.getScaleY();
@ -521,9 +537,10 @@ void Bone::updateAppliedTransform() {
ib = pb * pid;
break;
}
case TransformMode_NoScale:
case TransformMode_NoScaleOrReflection: {
float cos = MathUtil::cosDeg(_rotation), sin = MathUtil::sinDeg(_rotation);
case Inherit_NoScale:
case Inherit_NoScaleOrReflection: {
float r = _rotation * MathUtil::Deg_Rad;
float cos = MathUtil::cos(r), sin = MathUtil::sin(r);
pa = (pa * cos + pb * sin) / _skeleton.getScaleX();
pc = (pc * cos + pd * sin) / _skeleton.getScaleY();
float s = MathUtil::sqrt(pa * pa + pc * pc);
@ -531,10 +548,10 @@ void Bone::updateAppliedTransform() {
pa *= s;
pc *= s;
s = MathUtil::sqrt(pa * pa + pc * pc);
if (_data.getTransformMode() == TransformMode_NoScale &&
if (_inherit == Inherit_NoScale &&
pid < 0 != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
s = -s;
float r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
pb = MathUtil::cos(r) * s;
pd = MathUtil::sin(r) * s;
pid = 1 / (pa * pd - pb * pc);
@ -544,8 +561,8 @@ void Bone::updateAppliedTransform() {
id = pa * pid;
break;
}
case TransformMode_Normal:
case TransformMode_OnlyTranslation:
case Inherit_Normal:
case Inherit_OnlyTranslation:
break;
}
ra = ia * _a - ib * _c;
@ -559,13 +576,13 @@ void Bone::updateAppliedTransform() {
if (_ascaleX > 0.0001f) {
float det = ra * rd - rb * rc;
_ascaleY = det / _ascaleX;
_ashearY = -MathUtil::atan2(ra * rb + rc * rd, det) * MathUtil::Rad_Deg;
_arotation = MathUtil::atan2(rc, ra) * MathUtil::Rad_Deg;
_ashearY = -MathUtil::atan2Deg(ra * rb + rc * rd, det);
_arotation = MathUtil::atan2Deg(rc, ra);
} else {
_ascaleX = 0;
_ascaleY = MathUtil::sqrt(rb * rb + rd * rd);
_ashearY = 0;
_arotation = 90 - MathUtil::atan2(rd, rb) * MathUtil::Rad_Deg;
_arotation = 90 - MathUtil::atan2Deg(rd, rb);
}
}

View File

@ -34,21 +34,21 @@
using namespace spine;
BoneData::BoneData(int index, const String &name, BoneData *parent) : _index(index),
_name(name),
_parent(parent),
_length(0),
_x(0),
_y(0),
_rotation(0),
_scaleX(1),
_scaleY(1),
_shearX(0),
_shearY(0),
_transformMode(TransformMode_Normal),
_skinRequired(false),
_color(),
_icon(),
_visible(true) {
_name(name),
_parent(parent),
_length(0),
_x(0),
_y(0),
_rotation(0),
_scaleX(1),
_scaleY(1),
_shearX(0),
_shearY(0),
_inherit(Inherit_Normal),
_skinRequired(false),
_color(),
_icon(),
_visible(true) {
assert(index >= 0);
assert(_name.length() > 0);
}
@ -129,12 +129,12 @@ void BoneData::setShearY(float inValue) {
_shearY = inValue;
}
TransformMode BoneData::getTransformMode() {
return _transformMode;
Inherit BoneData::getInherit() {
return _inherit;
}
void BoneData::setTransformMode(TransformMode inValue) {
_transformMode = inValue;
void BoneData::setInherit(Inherit inValue) {
_inherit = inValue;
}
bool BoneData::isSkinRequired() {

View File

@ -45,18 +45,18 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
float rotationIK = -bone._ashearX - bone._arotation;
float tx = 0, ty = 0;
switch (bone._data.getTransformMode()) {
case TransformMode_OnlyTranslation:
switch (bone._data.getInherit()) {
case Inherit_OnlyTranslation:
tx = (targetX - bone._worldX) * MathUtil::sign(bone.getSkeleton().getScaleX());
ty = (targetY - bone._worldY) * MathUtil::sign(bone.getSkeleton().getScaleY());
break;
case TransformMode_NoRotationOrReflection: {
case Inherit_NoRotationOrReflection: {
float s = MathUtil::abs(pa * pd - pb * pc) / MathUtil::max(0.0001f, pa * pa + pc * pc);
float sa = pa / bone._skeleton.getScaleX();
float sc = pc / bone._skeleton.getScaleY();
pb = -sc * s * bone._skeleton.getScaleX();
pd = sa * s * bone._skeleton.getScaleY();
rotationIK += MathUtil::atan2(sc, sa) * MathUtil::Rad_Deg;
rotationIK += MathUtil::atan2Deg(sc, sa);
}
default:
float x = targetX - p->_worldX, y = targetY - p->_worldY;
@ -69,7 +69,7 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
ty = (y * pa - x * pc) / d - bone._ay;
}
}
rotationIK += MathUtil::atan2(ty, tx) * MathUtil::Rad_Deg;
rotationIK += MathUtil::atan2Deg(ty, tx);
if (bone._ascaleX < 0) rotationIK += 180;
if (rotationIK > 180) rotationIK -= 360;
else if (rotationIK < -180)
@ -77,9 +77,9 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
float sx = bone._ascaleX;
float sy = bone._ascaleY;
if (compress || stretch) {
switch (bone._data.getTransformMode()) {
case TransformMode_NoScale:
case TransformMode_NoScaleOrReflection:
switch (bone._data.getInherit()) {
case Inherit_NoScale:
case Inherit_NoScaleOrReflection:
tx = targetX - bone._worldX;
ty = targetY - bone._worldY;
default:;

View File

@ -0,0 +1,80 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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/InheritTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(InheritTimeline, Timeline)
#define ENTRIES 2
#define INHERIT 1
InheritTimeline::InheritTimeline(size_t frameCount, int boneIndex) : Timeline(frameCount, ENTRIES),
_boneIndex(boneIndex) {
PropertyId ids[] = {((PropertyId) Property_Inherit << 32) | boneIndex };
setPropertyIds(ids, 1);
}
InheritTimeline::~InheritTimeline() {
}
void InheritTimeline::setFrame(int frame, float time, Inherit inherit) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + INHERIT] = inherit;
}
void InheritTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
SP_UNUSED(alpha);
Bone *bone = skeleton.getBones()[_boneIndex];
if (!bone->isActive()) return;
if (time < _frames[0]) {
if (blend == MixBlend_Setup || blend == MixBlend_First) bone->_inherit = bone->_data.getInherit();
return;
}
int idx = Animation::search(_frames, time, ENTRIES) + INHERIT;
bone->_inherit = (Inherit)_frames[idx];
}

View File

@ -32,6 +32,7 @@
#include <spine/Bone.h>
#include <spine/Skeleton.h>
#include <spine/SkeletonData.h>
#include <spine/BoneData.h>
using namespace spine;
@ -41,7 +42,6 @@ RTTI_IMPL(PhysicsConstraint, Updatable)
PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skeleton)
: _data(data), _skeleton(skeleton) {
_bone = skeleton.getBones()[data.getBone()->getIndex()];
_inertia = data.getInertia();
_strength = data.getStrength();
_damping = data.getDamping();
@ -324,7 +324,8 @@ void PhysicsConstraint::update(Physics physics) {
reset();
// Fall through.
case Physics::Physics_Update: {
_remaining += MathUtil::max(_skeleton.getTime() - _lastTime, 0.0f);
float delta = MathUtil::max(_skeleton.getTime() - _lastTime, 0.0f);
_remaining += delta;
_lastTime = _skeleton.getTime();
float bx = bone->_worldX, by = bone->_worldY;
@ -333,83 +334,92 @@ void PhysicsConstraint::update(Physics physics) {
_ux = bx;
_uy = by;
} else {
float remaining = _remaining, i = _inertia, step = _data._step;
float a = _remaining, i = _inertia, q = _data._limit * delta, t = _data._step, f = _skeleton.getData()->getReferenceScale(), d = -1;
if (x || y) {
if (x) {
_xOffset += (_ux - bx) * i;
_ux = bx;
}
if (y) {
_yOffset += (_uy - by) * i;
_uy = by;
}
if (remaining >= step) {
float m = _massInverse * step, e = _strength, w = _wind * 100, g = _gravity * -100;
float d = MathUtil::pow(_damping, 60 * step);
do {
if (x) {
_xVelocity += (w - _xOffset * e) * m;
_xOffset += _xVelocity * step;
_xVelocity *= d;
}
if (y) {
_yVelocity += (g - _yOffset * e) * m;
_yOffset += _yVelocity * step;
_yVelocity *= d;
}
remaining -= step;
} while (remaining >= step);
if (x) {
float u = (_ux - bx) * i;
_xOffset += u > q ? q : u < -q ? -q : u;
_ux = bx;
}
if (y) {
float u = (_uy - by) * i;
_yOffset += u > q ? q : u < -q ? -q : u;
_uy = by;
}
if (a >= t) {
d = MathUtil::pow(_damping, 60 * t);
float m = _massInverse * t, e = _strength, w = _wind * f, g = _gravity * f;
do {
if (x) {
_xVelocity += (w - _xOffset * e) * m;
_xOffset += _xVelocity * t;
_xVelocity *= d;
}
if (y) {
_yVelocity -= (g + _yOffset * e) * m;
_yOffset += _yVelocity * t;
_yVelocity *= d;
}
a -= t;
} while (a >= t);
}
if (x) bone->_worldX += _xOffset * mix * _data._x;
if (y) bone->_worldY += _yOffset * mix * _data._y;
}
if (rotateOrShearX || scaleX) {
float ca = MathUtil::atan2(bone->_c, bone->_a), c = 0, s = 0, mr = 0;
if (rotateOrShearX) {
mr = (_data._rotate + _data._shearX) * mix;
float dx = _cx - bone->_worldX, dy = _cy - bone->_worldY;
float r = MathUtil::atan2(dy + _ty, dx + _tx) - ca - _rotateOffset * mr;
_rotateOffset += (r - MathUtil::ceil(r * MathUtil::InvPi_2 - 0.5) * MathUtil::Pi_2) * i;
r = _rotateOffset * mr + ca;
c = MathUtil::cos(r);
s = MathUtil::sin(r);
if (scaleX) {
r = l * bone->getWorldScaleX();
if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
}
} else {
c = MathUtil::cos(ca);
s = MathUtil::sin(ca);
float r = l * bone->getWorldScaleX();
if (r > 0) _scaleOffset += ((this->_cx - bone->_worldX) * c + (this->_cy - bone->_worldY) * s) * i / r;
}
remaining = _remaining;
if (remaining >= step) {
float m = _massInverse * step, e = _strength;
float d = MathUtil::pow(_damping, 60 * step);
while (true) {
remaining -= step;
if (scaleX) {
_scaleVelocity += (_wind * c - _gravity * s - _scaleOffset * e) * m;
_scaleOffset += _scaleVelocity * step;
_scaleVelocity *= d;
}
if (rotateOrShearX) {
_rotateVelocity += (-0.01f * l * (_wind * s + _gravity * c) - _rotateOffset * e) * m;
_rotateOffset += _rotateVelocity * step;
_rotateVelocity *= d;
if (remaining < step) break;
float r = _rotateOffset * mr + ca;
c = MathUtil::cos(r);
s = MathUtil::sin(r);
} else if (remaining < step)//
break;
}
}
}
_remaining = remaining;
if (rotateOrShearX || scaleX) {
float ca = MathUtil::atan2(bone->_c, bone->_a), c, s, mr = 0;
float dx = _cx - bone->_worldX, dy = _cy - bone->_worldY;
if (dx > q)
dx = q;
else if (dx < -q) //
dx = -q;
if (dy > q)
dy = q;
else if (dy < -q) //
dy = -q;
if (rotateOrShearX) {
mr = (_data._rotate + _data._shearX) * mix;
float r = MathUtil::atan2(dy + _ty, dx + _tx) - ca - _rotateOffset * mr;
_rotateOffset += (r - MathUtil::ceil(r * MathUtil::InvPi_2 - 0.5f) * MathUtil::Pi_2) * i;
r = _rotateOffset * mr + ca;
c = MathUtil::cos(r);
s = MathUtil::sin(r);
if (scaleX) {
r = l * bone->getWorldScaleX();
if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
}
} else {
c = MathUtil::cos(ca);
s = MathUtil::sin(ca);
float r = l * bone->getWorldScaleX();
if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
}
a = _remaining;
if (a >= t) {
if (d == -1) d = MathUtil::pow(_damping, 60 * t);
float m = _massInverse * t, e = _strength, w = _wind, g = _gravity, h = l / f;
while (true) {
a -= t;
if (scaleX) {
_scaleVelocity += (w * c - g * s - _scaleOffset * e) * m;
_scaleOffset += _scaleVelocity * t;
_scaleVelocity *= d;
}
if (rotateOrShearX) {
_rotateVelocity -= ((w * s + g * c) * h + _rotateOffset * e) * m;
_rotateOffset += _rotateVelocity * t;
_rotateVelocity *= d;
if (a < t) break;
float r = _rotateOffset * mr + ca;
c = MathUtil::cos(r);
s = MathUtil::sin(r);
} else if (a < t) //
break;
}
}
}
_remaining = a;
}
_cx = bone->_worldX;
@ -466,12 +476,9 @@ void PhysicsConstraint::update(Physics physics) {
}
void PhysicsConstraint::rotate(float x, float y, float degrees) {
float r = degrees * MathUtil::Deg_Rad, cos = MathUtil::cos(r), sin = MathUtil::sin(r);
r = _tx * cos - _ty * sin;
_ty = _tx * sin + _ty * cos;
_tx = r;
float dx = _cx - x, dy = _cy - y;
translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy);
float r = degrees * MathUtil::Deg_Rad, cos = MathUtil::cos(r), sin = MathUtil::sin(r);
float dx = _cx - x, dy = _cy - y;
translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy);
}
void PhysicsConstraint::translate(float x, float y) {

View File

@ -39,7 +39,7 @@ RTTI_IMPL(PhysicsConstraintData, ConstraintData)
PhysicsConstraintData::PhysicsConstraintData(const String &name) : ConstraintData(name),
_bone(nullptr),
_x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0),
_x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0), _limit(0),
_step(0), _inertia(0), _strength(0), _damping(0), _massInverse(0), _wind(0), _gravity(0), _mix(0),
_inertiaGlobal(false), _strengthGlobal(false), _dampingGlobal(false), _massGlobal(false),
_windGlobal(false), _gravityGlobal(false), _mixGlobal(false) {
@ -94,6 +94,14 @@ float PhysicsConstraintData::getShearX() const {
return _shearX;
}
void PhysicsConstraintData::setLimit(float limit) {
_limit = limit;
}
float PhysicsConstraintData::getLimit() const {
return _limit;
}
void PhysicsConstraintData::setStep(float step) {
_step = step;
}

View File

@ -93,7 +93,7 @@ void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vec
int index = modeAndIndex >> 4, count = (int) sequence->getRegions().size();
int mode = modeAndIndex & 0xf;
if (mode != SequenceMode::hold) {
index += (int) (((time - before) / delay + 0.00001));
index += (int) (((time - before) / delay + 0.0001));
switch (mode) {
case SequenceMode::once:
index = MathUtil::min(count - 1, index);

View File

@ -158,5 +158,5 @@ void ShearYTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vecto
SP_UNUSED(direction);
Bone *bone = skeleton._bones[_boneIndex];
if (bone->_active) bone->_shearY = getRelativeValue(time, alpha, blend, bone->_shearX, bone->_data._shearY);
if (bone->_active) bone->_shearY = getRelativeValue(time, alpha, blend, bone->_shearY, bone->_data._shearY);
}

View File

@ -163,7 +163,6 @@ void Skeleton::updateCache() {
size_t transformCount = _transformConstraints.size();
size_t pathCount = _pathConstraints.size();
size_t physicsCount = _physicsConstraints.size();
size_t constraintCount = ikCount + transformCount + pathCount + physicsCount;
size_t i = 0;
@ -510,6 +509,10 @@ Vector<TransformConstraint *> &Skeleton::getTransformConstraints() {
return _transformConstraints;
}
Vector<PhysicsConstraint *> &Skeleton::getPhysicsConstraints() {
return _physicsConstraints;
}
Skin *Skeleton::getSkin() {
return _skin;
}

View File

@ -157,7 +157,7 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
data->_shearX = readFloat(input);
data->_shearY = readFloat(input);
data->_length = readFloat(input) * _scale;
data->_transformMode = static_cast<TransformMode>(readVarint(input, true));
data->_inherit = static_cast<Inherit>(readVarint(input, true));
data->_skinRequired = readBoolean(input);
if (nonessential) {
readColor(input, data->getColor());

View File

@ -49,6 +49,7 @@ SkeletonData::SkeletonData() : _name(),
_y(0),
_width(0),
_height(0),
_referenceScale(100),
_version(),
_hash(),
_fps(0),
@ -193,6 +194,14 @@ void SkeletonData::setHeight(float inValue) {
_height = inValue;
}
float SkeletonData::getReferenceScale() {
return _referenceScale;
}
void SkeletonData::setReferenceScale(float inValue) {
_referenceScale = inValue;
}
const String &SkeletonData::getVersion() {
return _version;
}

View File

@ -194,17 +194,17 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
data->_scaleY = Json::getFloat(boneMap, "scaleY", 1);
data->_shearX = Json::getFloat(boneMap, "shearX", 0);
data->_shearY = Json::getFloat(boneMap, "shearY", 0);
transformMode = Json::getString(boneMap, "transform", "normal");
data->_transformMode = TransformMode_Normal;
if (strcmp(transformMode, "normal") == 0) data->_transformMode = TransformMode_Normal;
transformMode = Json::getString(boneMap, "inherit", "normal");
data->_inherit = Inherit_Normal;
if (strcmp(transformMode, "normal") == 0) data->_inherit = Inherit_Normal;
else if (strcmp(transformMode, "onlyTranslation") == 0)
data->_transformMode = TransformMode_OnlyTranslation;
data->_inherit = Inherit_OnlyTranslation;
else if (strcmp(transformMode, "noRotationOrReflection") == 0)
data->_transformMode = TransformMode_NoRotationOrReflection;
data->_inherit = Inherit_NoRotationOrReflection;
else if (strcmp(transformMode, "noScale") == 0)
data->_transformMode = TransformMode_NoScale;
data->_inherit = Inherit_NoScale;
else if (strcmp(transformMode, "noScaleOrReflection") == 0)
data->_transformMode = TransformMode_NoScaleOrReflection;
data->_inherit = Inherit_NoScaleOrReflection;
data->_skinRequired = Json::getBoolean(boneMap, "skin", false);
const char *color = Json::getString(boneMap, "color", NULL);

View File

@ -88,7 +88,7 @@ Skin::AttachmentMap::Entries Skin::AttachmentMap::getEntries() {
return Skin::AttachmentMap::Entries(_buckets);
}
Skin::Skin(const String &name) : _name(name), _attachments() {
Skin::Skin(const String &name) : _name(name), _attachments(), _color(0.99607843f, 0.61960787f, 0.30980393f, 1) {
assert(_name.length() > 0);
}

View File

@ -54,7 +54,8 @@ SkeletonDrawable::~SkeletonDrawable() {
void SkeletonDrawable::update(float delta) {
animationState->update(delta);
animationState->apply(*skeleton);
skeleton->updateWorldTransform();
skeleton->update(delta);
skeleton->updateWorldTransform(Physics_Update);
}
void SkeletonDrawable::draw(SDL_Renderer *renderer) {