[cpp] 4.3 porting WIP

This commit is contained in:
Mario Zechner 2025-06-12 17:34:15 +02:00
parent 7a99a2f487
commit 4f728c6fd2
71 changed files with 321 additions and 372 deletions

View File

@ -41,13 +41,11 @@ namespace spine {
class AtlasRegion;
/// An AttachmentLoader that configures attachments using texture regions from an Atlas.
///
///
/// See https://esotericsoftware.com/spine-loading-skeleton-data#JSON-and-binary-data Loading skeleton data in the
/// Spine Runtimes Guide.
class SP_API AtlasAttachmentLoader : public AttachmentLoader {
public:
RTTI_DECL
explicit AtlasAttachmentLoader(Atlas *atlas);
virtual RegionAttachment *newRegionAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence);

View File

@ -36,7 +36,7 @@
namespace spine {
class SP_API Attachment : public SpineObject {
RTTI_DECL
RTTI_DECL_NOPARENT
public:
explicit Attachment(const String &name);

View File

@ -55,8 +55,6 @@ namespace spine {
class SP_API AttachmentLoader : public SpineObject {
public:
RTTI_DECL
AttachmentLoader();
virtual ~AttachmentLoader();

View File

@ -36,6 +36,7 @@
#include <spine/MixBlend.h>
#include <spine/MixDirection.h>
#include <spine/SpineString.h>
#include <spine/SlotTimeline.h>
namespace spine {
@ -43,9 +44,11 @@ namespace spine {
class Slot;
class SlotPose;
class Event;
class SP_API AttachmentTimeline : public Timeline {
class SP_API AttachmentTimeline : public Timeline, public SlotTimeline {
friend class SkeletonBinary;
friend class SkeletonJson;
@ -59,23 +62,17 @@ namespace spine {
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction);
MixDirection direction, bool appliedPose) override;
/// Sets the time and value of the specified keyframe.
void setFrame(int frame, float time, const String &attachmentName);
Vector<String> &getAttachmentNames();
int getSlotIndex() { return _slotIndex; }
void setSlotIndex(int inValue) { _slotIndex = inValue; }
protected:
int _slotIndex;
Vector<String> _attachmentNames;
void setAttachment(Skeleton &skeleton, Slot &slot, String *attachmentName);
void setAttachment(Skeleton &skeleton, SlotPose &pose, String *attachmentName);
};
}

View File

@ -70,7 +70,7 @@ namespace spine {
friend class TranslateYTimeline;
friend class InheritTimeline;
RTTI_DECL
RTTI_DECL_NOPARENT
public:
/// @param parent May be NULL.

View File

@ -38,7 +38,6 @@
namespace spine {
class SP_API BoneData : public PosedData<BoneLocal> {
RTTI_DECL
friend class SkeletonBinary;
friend class SkeletonJson;

View File

@ -52,8 +52,6 @@ namespace spine {
friend class TranslateXTimeline;
friend class TranslateYTimeline;
RTTI_DECL
protected:
float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
Inherit _inherit;

View File

@ -40,7 +40,6 @@ namespace spine {
class SP_API BonePose : public BoneLocal, public Update {
friend class IkConstraint;
RTTI_DECL
public:
Bone* _bone;
@ -55,17 +54,17 @@ namespace spine {
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.
///
///
/// See <a href="https://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
/// Runtimes Guide.
void updateWorldTransform(Skeleton& skeleton);
/// 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);
@ -132,7 +131,7 @@ 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);

View File

@ -44,7 +44,7 @@ namespace spine {
Color &getColor();
virtual Attachment *copy();
virtual Attachment *copy() override;
private:
Color _color;

View File

@ -54,7 +54,7 @@ namespace spine {
Color &getColor();
virtual Attachment *copy();
virtual Attachment *copy() override;
private:
SlotData *_endSlot;

View File

@ -47,8 +47,6 @@ namespace spine {
virtual ~RGBATimeline();
int getFrameEntries();
/// Sets the time and color for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
@ -77,8 +75,6 @@ namespace spine {
virtual ~RGBTimeline();
int getFrameEntries();
/// Sets the time and color for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
@ -108,11 +104,6 @@ namespace spine {
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose) override;
virtual int getSlotIndex() override;
protected:
int _slotIndex;
};
/// Changes a slot's SlotPose::getColor() and SlotPose::getDarkColor() for two color tinting.
@ -128,8 +119,6 @@ namespace spine {
virtual ~RGBA2Timeline();
int getFrameEntries();
/// Sets the time, light color, and dark color for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.
@ -161,8 +150,6 @@ namespace spine {
virtual ~RGB2Timeline();
int getFrameEntries();
/// Sets the time, light color, and dark color for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.

View File

@ -37,15 +37,22 @@
namespace spine {
class Skeleton;
class SP_API Constraint: public Update {
RTTI_DECL_NOPARENT
public:
Constraint();
virtual ~Constraint();
};
template<class T, class D, class P>
class SP_API Constraint : public PosedActive<D, P, P>, public Update {
class SP_API ConstraintGeneric : public PosedActive<D, P, P>, public Constraint {
RTTI_DECL
public:
Constraint(D& data) : PosedActive<D, P, P>(data) {
ConstraintGeneric(D& data) : PosedActive<D, P, P>(data), Constraint() {
}
virtual ~Constraint() {
virtual ~ConstraintGeneric() {
}
virtual void sort(Skeleton& skeleton) = 0;
@ -55,7 +62,7 @@ namespace spine {
}
// Inherited from Update
virtual void update(Skeleton& skeleton, Physics physics) = 0;
virtual void update(Skeleton& skeleton, Physics physics) override = 0;
};
}

View File

@ -39,8 +39,8 @@ namespace spine {
/// Base class for all constraint data types.
class SP_API ConstraintData : public SpineObject {
RTTI_DECL
public:
RTTI_DECL_NOPARENT
ConstraintData(const String &name);
virtual ~ConstraintData();
const String &getName() const;

View File

@ -75,8 +75,6 @@ namespace spine {
virtual ~CurveTimeline1();
size_t getFrameEntries();
/// Sets the time and value for the specified frame.
/// @param frame Between 0 and frameCount, inclusive.
/// @param time The frame time in seconds.

View File

@ -30,13 +30,12 @@
#ifndef Spine_DeformTimeline_h
#define Spine_DeformTimeline_h
#include <spine/CurveTimeline.h>
#include <spine/SlotTimeline.h>
#include <spine/SlotCurveTimeline.h>
namespace spine {
class VertexAttachment;
class SP_API DeformTimeline : public CurveTimeline, public SlotTimeline {
class SP_API DeformTimeline : public SlotCurveTimeline {
friend class SkeletonBinary;
friend class SkeletonJson;
@ -48,7 +47,7 @@ namespace spine {
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction) override;
MixDirection direction, bool appliedPose) override;
/// Sets the time and vertices for the specified frame.
void setFrame(int frameIndex, float time, Vector<float> &vertices);
@ -67,18 +66,12 @@ namespace spine {
float getCurvePercent(float time, int frame);
int getSlotIndex() override { return _slotIndex; }
void setSlotIndex(int inValue) { _slotIndex = inValue; }
size_t getFrameCount() { return _frames.size(); }
protected:
void apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend);
void apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) override;
private:
int _slotIndex;
Vector <Vector<float>> _vertices;
VertexAttachment *_attachment;

View File

@ -41,7 +41,7 @@ namespace spine {
class Bone;
class BonePose;
class SP_API IkConstraint : public Constraint<IkConstraint, IkConstraintData, IkConstraintPose> {
class SP_API IkConstraint : public ConstraintGeneric<IkConstraint, IkConstraintData, IkConstraintPose> {
friend class Skeleton;
friend class IkConstraintTimeline;
@ -63,11 +63,11 @@ namespace spine {
IkConstraint(IkConstraintData &data, Skeleton &skeleton);
virtual void update(Skeleton& skeleton, Physics physics);
virtual void update(Skeleton& skeleton, Physics physics) override;
virtual void sort(Skeleton& skeleton);
virtual void sort(Skeleton& skeleton) override;
virtual bool isSourceActive();
virtual bool isSourceActive() override;
virtual IkConstraint* copy(Skeleton& skeleton);

View File

@ -51,9 +51,9 @@ namespace spine {
friend class IkConstraintTimeline;
public:
RTTI_DECL
public:
explicit IkConstraintData(const String &name);
/// The bones that are constrained by this IK Constraint.

View File

@ -38,7 +38,6 @@ namespace spine {
/// Stores the current pose for an IK constraint.
class SP_API IkConstraintPose : public Pose<IkConstraintPose> {
friend class IkConstraint;
RTTI_DECL
public:
IkConstraintPose();
@ -47,7 +46,7 @@ namespace spine {
virtual void set(IkConstraintPose& pose) override;
/// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation.
///
///
/// For two bone IK: if the parent bone has local nonuniform scale, the child bone's local Y translation is set to 0.
float getMix();
void setMix(float mix);
@ -66,7 +65,7 @@ namespace spine {
void setCompress(bool compress);
/// When true and the target is out of range, the parent bone is scaled to reach it.
///
///
/// For two bone IK: 1) the child bone's local Y translation is set to 0, 2) stretch is not applied if getSoftness() is
/// > 0, and 3) if the parent bone has local nonuniform scale, stretch is not applied.
bool getStretch();

View File

@ -56,7 +56,7 @@ namespace spine {
using VertexAttachment::computeWorldVertices;
virtual void computeWorldVertices(Skeleton &skeleton, Slot &slot, size_t start, size_t count, float *worldVertices, size_t offset,
size_t stride = 2);
size_t stride = 2) override;
void updateRegion();
@ -100,7 +100,7 @@ namespace spine {
void setHeight(float inValue);
virtual Attachment *copy();
virtual Attachment *copy() override;
MeshAttachment *newLinkedMesh();

View File

@ -57,7 +57,7 @@ namespace spine {
Color &getColor();
virtual Attachment *copy();
virtual Attachment *copy() override;
private:
Vector<float> _lengths;

View File

@ -49,7 +49,7 @@ namespace spine {
/// constrained bones so they follow a PathAttachment.
///
/// See https://esotericsoftware.com/spine-path-constraints Path constraints in the Spine User Guide.
class SP_API PathConstraint : public Constraint<PathConstraint, PathConstraintData, PathConstraintPose> {
class SP_API PathConstraint : public ConstraintGeneric<PathConstraint, PathConstraintData, PathConstraintPose> {
friend class Skeleton;
friend class PathConstraintMixTimeline;
friend class PathConstraintPositionTimeline;
@ -63,11 +63,11 @@ namespace spine {
PathConstraint(PathConstraintData &data, Skeleton &skeleton);
virtual void update(Skeleton& skeleton, Physics physics);
virtual void update(Skeleton& skeleton, Physics physics) override;
virtual void sort(Skeleton& skeleton);
virtual void sort(Skeleton& skeleton) override;
virtual bool isSourceActive();
virtual bool isSourceActive() override;
PathConstraintData &getData();

View File

@ -42,7 +42,7 @@ namespace spine {
class Skeleton;
/// Controls how the first bone is positioned along the path.
///
///
/// See https://esotericsoftware.com/spine-path-constraints#Position-mode Position mode in the Spine User Guide.
enum PositionMode {
PositionMode_Fixed,
@ -50,7 +50,7 @@ namespace spine {
};
/// Controls how bones after the first bone are positioned along the path.
///
///
/// See https://esotericsoftware.com/spine-path-constraints#Spacing-mode Spacing mode in the Spine User Guide.
enum SpacingMode {
SpacingMode_Length,
@ -60,7 +60,7 @@ namespace spine {
};
/// Controls how bones are rotated, translated, and scaled to match the path.
///
///
/// See https://esotericsoftware.com/spine-path-constraints#Rotate-Mix Rotate mode in the Spine User Guide.
enum RotateMode {
RotateMode_Tangent,
@ -71,7 +71,7 @@ namespace spine {
};
/// Stores the setup pose for a PathConstraint.
///
///
/// See https://esotericsoftware.com/spine-path-constraints Path constraints in the Spine User Guide.
class SP_API PathConstraintData : public ConstraintDataGeneric<PathConstraint, PathConstraintPose> {
friend class SkeletonBinary;
@ -87,8 +87,9 @@ namespace spine {
friend class PathConstraintPositionTimeline;
friend class PathConstraintSpacingTimeline;
public:
RTTI_DECL
public:
explicit PathConstraintData(const String &name);

View File

@ -37,38 +37,36 @@ namespace spine {
/// Stores a pose for a path constraint.
class SP_API PathConstraintPose : public Pose<PathConstraintPose> {
friend class PathConstraint;
RTTI_DECL
private:
float _position;
float _spacing;
float _mixRotate;
float _mixX;
float _mixY;
public:
PathConstraintPose();
virtual ~PathConstraintPose();
virtual void set(PathConstraintPose& pose) override;
/// The position along the path.
float getPosition();
void setPosition(float position);
/// The spacing between bones.
float getSpacing();
void setSpacing(float spacing);
/// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation.
float getMixRotate();
void setMixRotate(float mixRotate);
/// A percentage (0-1) that controls the mix between the constrained and unconstrained translation X.
float getMixX();
void setMixX(float mixX);
/// A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y.
float getMixY();
void setMixY(float mixY);

View File

@ -44,7 +44,7 @@ namespace spine {
/// Stores the current pose for a physics constraint. A physics constraint applies physics to bones.
///
/// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide.
class SP_API PhysicsConstraint : public Constraint<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose> {
class SP_API PhysicsConstraint : public ConstraintGeneric<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose> {
friend class Skeleton;
friend class PhysicsConstraintTimeline;
friend class PhysicsConstraintInertiaTimeline;
@ -62,8 +62,8 @@ namespace spine {
PhysicsConstraint(PhysicsConstraintData& data, Skeleton& skeleton);
void update(Skeleton& skeleton, Physics physics) override;
void sort(Skeleton& skeleton);
bool isSourceActive();
void sort(Skeleton& skeleton) override;
bool isSourceActive() override;
PhysicsConstraint* copy(Skeleton& skeleton);
/// Translates the physics constraint so next update() forces are applied as if the bone moved an additional amount in world space.

View File

@ -38,7 +38,7 @@ namespace spine {
class PhysicsConstraint;
/// Stores the setup pose for a PhysicsConstraint.
///
///
/// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide.
class SP_API PhysicsConstraintData : public ConstraintDataGeneric<PhysicsConstraint, PhysicsConstraintPose> {
friend class SkeletonBinary;
@ -46,9 +46,8 @@ namespace spine {
friend class PhysicsConstraint;
friend class Skeleton;
public:
RTTI_DECL
public:
explicit PhysicsConstraintData(const String &name);
/// The bone constrained by this physics constraint.

View File

@ -36,10 +36,8 @@
namespace spine {
/// Stores a pose for a physics constraint.
class SP_API PhysicsConstraintPose : public Pose<PhysicsConstraintPose> {
RTTI_DECL
friend class PhysicsConstraint;
private:
float _inertia;
float _strength;
@ -48,31 +46,31 @@ namespace spine {
float _wind;
float _gravity;
float _mix;
public:
PhysicsConstraintPose();
virtual ~PhysicsConstraintPose();
virtual void set(PhysicsConstraintPose& pose) override;
float getInertia();
void setInertia(float inertia);
float getStrength();
void setStrength(float strength);
float getDamping();
void setDamping(float damping);
float getMassInverse();
void setMassInverse(float massInverse);
float getWind();
void setWind(float wind);
float getGravity();
void setGravity(float gravity);
/// A percentage (0-1) that controls the mix between the constrained and unconstrained poses.
float getMix();
void setMix(float mix);

View File

@ -71,7 +71,7 @@ namespace spine {
float computeWorldRotation(BonePose &bone);
virtual Attachment *copy();
virtual Attachment *copy() override;
private:
float _x, _y, _rotation;

View File

@ -56,11 +56,16 @@ namespace spine {
};
}
#define RTTI_DECL \
#define RTTI_DECL_NOPARENT \
public: \
static const spine::RTTI rtti; \
virtual const spine::RTTI& getRTTI() const;
#define RTTI_DECL \
public: \
static const spine::RTTI rtti; \
virtual const spine::RTTI& getRTTI() const override;
#define RTTI_IMPL_NOPARENT(name) \
const spine::RTTI name::rtti(#name); \
const spine::RTTI& name::getRTTI() const { return rtti; }

View File

@ -42,6 +42,7 @@
namespace spine {
class Bone;
class Slot;
/// Attachment that displays a texture region.
class SP_API RegionAttachment : public Attachment {
@ -115,7 +116,7 @@ namespace spine {
Vector<float> &getUVs();
virtual Attachment *copy();
virtual Attachment *copy() override;
private:
static const int BLX;

View File

@ -43,7 +43,6 @@ namespace spine {
class SkeletonJson;
class SP_API Sequence : public SpineObject {
RTTI_DECL
friend class SkeletonBinary;
friend class SkeletonJson;
public:

View File

@ -31,12 +31,14 @@
#define Spine_SequenceTimeline_h
#include <spine/Timeline.h>
#include <spine/SlotTimeline.h>
#include <spine/Sequence.h>
namespace spine {
class Attachment;
class HasTextureRegion;
class SP_API SequenceTimeline : public Timeline {
class SP_API SequenceTimeline : public Timeline, public SlotTimeline {
friend class SkeletonBinary;
friend class SkeletonJson;
@ -50,19 +52,14 @@ namespace spine {
virtual void
apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
MixDirection direction);
MixDirection direction, bool appliedPose) override;
void setFrame(int frame, float time, SequenceMode mode, int index, float delay);
int getSlotIndex() { return _slotIndex; };
void setSlotIndex(int inValue) { _slotIndex = inValue; }
Attachment *getAttachment() { return _attachment; }
Attachment *getAttachment() { return (Attachment*)_attachment; }
protected:
int _slotIndex;
Attachment *_attachment;
HasTextureRegion *_attachment;
static const int ENTRIES = 3;
static const int MODE = 1;

View File

@ -127,6 +127,8 @@ namespace spine {
friend class PhysicsConstraint;
friend class BonePose;
public:
explicit Skeleton(SkeletonData *skeletonData);
@ -290,6 +292,7 @@ namespace spine {
float _x, _y;
float _time;
float _windX, _windY, _gravityX, _gravityY;
int _update;
void sortIkConstraint(IkConstraint *constraint);

View File

@ -55,7 +55,7 @@ namespace spine {
class ConstraintData;
/// Stores the setup pose and all of the stateless data for a skeleton.
///
///
/// See <a href="https://esotericsoftware.com/spine-runtime-architecture#Data-objects">Data objects</a> in the Spine Runtimes
/// Guide.
class SP_API SkeletonData : public SpineObject {
@ -145,7 +145,7 @@ namespace spine {
getConstraints(); // Ensure constraints array is populated
for (size_t i = 0, n = _constraints.size(); i < n; i++) {
ConstraintData *constraint = _constraints[i];
if (constraint->getName().equals(constraintName)) {
if (constraint->getName() == constraintName) {
if (constraint->rtti.isExactly(T::rtti)) {
return static_cast<T*>(constraint);
}

View File

@ -37,12 +37,11 @@
namespace spine {
class Skeleton;
class Bone;
enum Physics;
/// Stores the setup pose for a PhysicsConstraint.
///
///
/// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide.
class SP_API Slider : public Constraint<Slider, SliderData, SliderPose> {
class SP_API Slider : public ConstraintGeneric<Slider, SliderData, SliderPose> {
friend class Skeleton;
public:
@ -57,7 +56,9 @@ namespace spine {
virtual void update(Skeleton& skeleton, Physics physics) override;
/// Called by Skeleton to sort constraints.
void sort(Skeleton& skeleton);
void sort(Skeleton& skeleton) override;
bool isSourceActive() override;
Bone* getBone();
void setBone(Bone* bone);

View File

@ -42,16 +42,16 @@ namespace spine {
class Skeleton;
/// Stores the setup pose for a PhysicsConstraint.
///
///
/// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide.
class SP_API SliderData : public ConstraintDataGeneric<Slider, SliderPose> {
friend class SkeletonBinary;
friend class SkeletonJson;
friend class Slider;
public:
RTTI_DECL
public:
explicit SliderData(const String &name);
/// Creates a slider instance.

View File

@ -36,7 +36,6 @@
namespace spine {
/// Stores a pose for a slider.
class SP_API SliderPose : public Pose<SliderPose> {
RTTI_DECL
private:
float _time, _mix;

View File

@ -49,16 +49,12 @@ namespace spine {
virtual ~SlotCurveTimeline();
virtual int getSlotIndex() override;
virtual void apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction, bool appliedPose) override;
protected:
/// Applies the timeline to the slot pose.
virtual void apply(Slot& slot, SlotPose& pose, float time, float alpha, MixBlend blend) = 0;
int _slotIndex;
};
}

View File

@ -41,8 +41,6 @@ namespace spine {
/// Stores the setup pose for a Slot.
class SP_API SlotData : public PosedData<SlotPose> {
RTTI_DECL
friend class SkeletonBinary;
friend class SkeletonJson;
friend class PathConstraint;

View File

@ -43,14 +43,13 @@ namespace spine {
class SP_API SlotPose : public Pose<SlotPose> {
friend class Slot;
friend class SlotCurveTimeline;
friend class DeformTimeline;
friend class RGBATimeline;
friend class RGBTimeline;
friend class AlphaTimeline;
friend class RGBA2Timeline;
friend class RGB2Timeline;
RTTI_DECL
private:
Color _color;
Color _darkColor;
@ -91,7 +90,7 @@ namespace spine {
/// Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a
/// weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions.
///
///
/// See VertexAttachment::computeWorldVertices() and DeformTimeline.
Vector<float>& getDeform();
};

View File

@ -37,10 +37,16 @@ namespace spine {
/// An interface for timelines which change the property of a slot.
class SP_API SlotTimeline {
RTTI_DECL
RTTI_DECL_NOPARENT
friend class AlphaTimeline;
friend class AttachmentTimeline;
friend class SequenceTimeline;
friend class SlotCurveTimeline;
public:
virtual ~SlotTimeline() {}
SlotTimeline(int slotIndex);
virtual ~SlotTimeline();
/// The index of the slot in Skeleton::getSlots() that will be changed when this timeline is applied.
virtual int getSlotIndex();

View File

@ -43,7 +43,7 @@ namespace spine {
class Event;
class SP_API Timeline : public SpineObject {
RTTI_DECL
RTTI_DECL_NOPARENT
public:
Timeline(size_t frameCount, size_t frameEntries);

View File

@ -40,7 +40,7 @@ namespace spine {
class Bone;
class BonePose;
class SP_API TransformConstraint : public Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose> {
class SP_API TransformConstraint : public ConstraintGeneric<TransformConstraint, TransformConstraintData, TransformConstraintPose> {
friend class Skeleton;
friend class TransformConstraintTimeline;
@ -52,11 +52,11 @@ namespace spine {
TransformConstraint copy(Skeleton& skeleton);
/// Applies the constraint to the constrained bones.
void update(Skeleton& skeleton, Physics physics);
void update(Skeleton& skeleton, Physics physics) override;
void sort(Skeleton& skeleton);
void sort(Skeleton& skeleton) override;
bool isSourceActive();
bool isSourceActive() override;
/// The bones that will be modified by this transform constraint.
Vector<BonePose*>& getBones();

View File

@ -43,16 +43,16 @@ namespace spine {
/// Source property for a TransformConstraint.
class SP_API FromProperty : public SpineObject {
public:
/// The value of this property that corresponds to ToProperty offset.
float offset;
/// Constrained properties.
Vector<class ToProperty*> to;
FromProperty();
virtual ~FromProperty();
/// Reads this property from the specified bone.
virtual float value(BonePose& source, bool local, float* offsets) = 0;
};
@ -60,22 +60,22 @@ namespace spine {
/// Constrained property for a TransformConstraint.
class SP_API ToProperty : public SpineObject {
public:
/// The value of this property that corresponds to FromProperty offset.
float offset;
/// The maximum value of this property when clamped.
float max;
/// The scale of the FromProperty value in relation to this property.
float scale;
ToProperty();
virtual ~ToProperty();
/// Reads the mix for this property from the specified pose.
virtual float mix(TransformConstraintPose& pose) = 0;
/// Applies the value to this property.
virtual void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) = 0;
};
@ -147,10 +147,11 @@ namespace spine {
};
/// Stores the setup pose for a TransformConstraint.
///
///
/// See https://esotericsoftware.com/spine-transform-constraints Transform constraints in the Spine User Guide.
class SP_API TransformConstraintData : public ConstraintDataGeneric<TransformConstraint, TransformConstraintPose> {
public:
RTTI_DECL
static const int ROTATION = 0, X = 1, Y = 2, SCALEX = 3, SCALEY = 4, SHEARY = 5;
friend class SkeletonBinary;
friend class SkeletonJson;
@ -159,8 +160,6 @@ namespace spine {
friend class TransformConstraintTimeline;
public:
RTTI_DECL
explicit TransformConstraintData(const String &name);
~TransformConstraintData();

View File

@ -36,8 +36,6 @@
namespace spine {
/// Stores a pose for a transform constraint.
class SP_API TransformConstraintPose : public Pose<TransformConstraintPose> {
RTTI_DECL
friend class FromProperty;
friend class ToProperty;
friend class FromRotate;
@ -52,7 +50,7 @@ namespace spine {
friend class ToScaleY;
friend class FromShearY;
friend class ToShearY;
private:
float _mixRotate, _mixX, _mixY, _mixScaleX, _mixScaleY, _mixShearY;

View File

@ -40,7 +40,7 @@ namespace spine {
/// The interface for items updated by Skeleton::updateWorldTransform().
class SP_API Update : public SpineObject {
RTTI_DECL
RTTI_DECL_NOPARENT
public:
Update();
virtual ~Update();

View File

@ -38,75 +38,72 @@
#include <spine/Atlas.h>
namespace spine {
RTTI_IMPL(AtlasAttachmentLoader, AttachmentLoader)
using namespace spine;
AtlasAttachmentLoader::AtlasAttachmentLoader(Atlas *atlas) : AttachmentLoader(), _atlas(atlas) {
AtlasAttachmentLoader::AtlasAttachmentLoader(Atlas *atlas) : AttachmentLoader(), _atlas(atlas) {
}
bool loadSequence(Atlas *atlas, const String &basePath, Sequence *sequence) {
Vector<TextureRegion *> &regions = sequence->getRegions();
for (int i = 0, n = (int) regions.size(); i < n; i++) {
String path = sequence->getPath(basePath, i);
regions[i] = atlas->findRegion(path);
if (!regions[i]) return false;
}
return true;
}
bool loadSequence(Atlas *atlas, const String &basePath, Sequence *sequence) {
Vector<TextureRegion *> &regions = sequence->getRegions();
for (int i = 0, n = (int) regions.size(); i < n; i++) {
String path = sequence->getPath(basePath, i);
regions[i] = atlas->findRegion(path);
if (!regions[i]) return false;
}
return true;
RegionAttachment *AtlasAttachmentLoader::newRegionAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) {
SP_UNUSED(skin);
RegionAttachment *attachment = new (__FILE__, __LINE__) RegionAttachment(name);
if (sequence) {
if (!loadSequence(_atlas, path, sequence)) return NULL;
} else {
AtlasRegion *region = findRegion(path);
if (!region) return NULL;
attachment->setRegion(region);
}
return attachment;
}
RegionAttachment *AtlasAttachmentLoader::newRegionAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) {
SP_UNUSED(skin);
RegionAttachment *attachment = new (__FILE__, __LINE__) RegionAttachment(name);
if (sequence) {
if (!loadSequence(_atlas, path, sequence)) return NULL;
} else {
AtlasRegion *region = findRegion(path);
if (!region) return NULL;
attachment->setRegion(region);
}
return attachment;
MeshAttachment *AtlasAttachmentLoader::newMeshAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) {
SP_UNUSED(skin);
MeshAttachment *attachment = new (__FILE__, __LINE__) MeshAttachment(name);
if (sequence) {
if (!loadSequence(_atlas, path, sequence)) return NULL;
} else {
AtlasRegion *region = findRegion(path);
if (!region) return NULL;
attachment->setRegion(region);
}
return attachment;
}
MeshAttachment *AtlasAttachmentLoader::newMeshAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) {
SP_UNUSED(skin);
MeshAttachment *attachment = new (__FILE__, __LINE__) MeshAttachment(name);
BoundingBoxAttachment *AtlasAttachmentLoader::newBoundingBoxAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) BoundingBoxAttachment(name);
}
if (sequence) {
if (!loadSequence(_atlas, path, sequence)) return NULL;
} else {
AtlasRegion *region = findRegion(path);
if (!region) return NULL;
attachment->setRegion(region);
}
return attachment;
}
PathAttachment *AtlasAttachmentLoader::newPathAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) PathAttachment(name);
}
BoundingBoxAttachment *AtlasAttachmentLoader::newBoundingBoxAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) BoundingBoxAttachment(name);
}
PointAttachment *AtlasAttachmentLoader::newPointAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) PointAttachment(name);
}
PathAttachment *AtlasAttachmentLoader::newPathAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) PathAttachment(name);
}
ClippingAttachment *AtlasAttachmentLoader::newClippingAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) ClippingAttachment(name);
}
PointAttachment *AtlasAttachmentLoader::newPointAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) PointAttachment(name);
}
void AtlasAttachmentLoader::configureAttachment(Attachment *attachment) {
SP_UNUSED(attachment);
}
ClippingAttachment *AtlasAttachmentLoader::newClippingAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) ClippingAttachment(name);
}
void AtlasAttachmentLoader::configureAttachment(Attachment *attachment) {
SP_UNUSED(attachment);
}
AtlasRegion *AtlasAttachmentLoader::findRegion(const String &name) {
return _atlas->findRegion(name);
}
}// namespace spine
AtlasRegion *AtlasAttachmentLoader::findRegion(const String &name) {
return _atlas->findRegion(name);
}

View File

@ -39,8 +39,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(AttachmentLoader)
AttachmentLoader::AttachmentLoader() {
}

View File

@ -37,13 +37,14 @@
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/SlotPose.h>
using namespace spine;
RTTI_IMPL(AttachmentTimeline, Timeline)
AttachmentTimeline::AttachmentTimeline(size_t frameCount, int slotIndex) : Timeline(frameCount, 1),
_slotIndex(slotIndex) {
SlotTimeline(slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Attachment << 32) | slotIndex};
setPropertyIds(ids, 1);
@ -55,39 +56,27 @@ AttachmentTimeline::AttachmentTimeline(size_t frameCount, int slotIndex) : Timel
AttachmentTimeline::~AttachmentTimeline() {}
void AttachmentTimeline::setAttachment(Skeleton &skeleton, Slot &slot, String *attachmentName) {
slot.setAttachment(attachmentName == NULL || attachmentName->isEmpty() ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
void AttachmentTimeline::setAttachment(Skeleton &skeleton, SlotPose &pose, String *attachmentName) {
pose.setAttachment(attachmentName == NULL || attachmentName->isEmpty() ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
}
void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction) {
MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(alpha);
Slot *slot = skeleton._slots[_slotIndex];
if (!slot->_bone._active) return;
SlotPose &pose = appliedPose ? *slot->_applied : slot->_pose;
if (direction == MixDirection_Out) {
if (blend == MixBlend_Setup) setAttachment(skeleton, *slot, &slot->_data._attachmentName);
return;
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);
} else {
setAttachment(skeleton, pose, &_attachmentNames[Animation::search(_frames, time)]);
}
if (time < _frames[0]) {
// Time is before first frame.
if (blend == MixBlend_Setup || blend == MixBlend_First) {
setAttachment(skeleton, *slot, &slot->_data._attachmentName);
}
return;
}
if (time < _frames[0]) {
if (blend == MixBlend_Setup || blend == MixBlend_First)
setAttachment(skeleton, *slot, &slot->_data._attachmentName);
return;
}
setAttachment(skeleton, *slot, &_attachmentNames[Animation::search(_frames, time)]);
}
void AttachmentTimeline::setFrame(int frame, float time, const String &attachmentName) {

View File

@ -33,8 +33,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(BoneData)
BoneData::BoneData(int index, const String &name, BoneData *parent) : PosedData<BoneLocal>(name),
_index(index),
_parent(parent),

View File

@ -31,8 +31,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(BoneLocal)
BoneLocal::BoneLocal() : _x(0), _y(0), _rotation(0), _scaleX(1), _scaleY(1), _shearX(0), _shearY(0), _inherit(Inherit_Normal) {
}

View File

@ -36,8 +36,6 @@
using namespace spine;
RTTI_IMPL(BonePose, BoneLocal)
BonePose::BonePose() : BoneLocal(), _bone(nullptr), _a(0), _b(0), _worldX(0), _c(0), _d(0), _worldY(0), _world(0), _local(0) {
}
@ -45,14 +43,14 @@ BonePose::~BonePose() {
}
void BonePose::update(Skeleton& skeleton, Physics physics) {
if (_world != skeleton.getUpdate()) updateWorldTransform(skeleton);
if (_world != skeleton._update) updateWorldTransform(skeleton);
}
void BonePose::updateWorldTransform(Skeleton& skeleton) {
if (_local == skeleton.getUpdate())
if (_local == skeleton._update)
updateLocalTransform(skeleton);
else
_world = skeleton.getUpdate();
_world = skeleton._update;
if (_bone->getParent() == nullptr) { // Root bone.
float sx = skeleton.getScaleX(), sy = skeleton.getScaleY();
@ -67,7 +65,7 @@ void BonePose::updateWorldTransform(Skeleton& skeleton) {
return;
}
BonePose& parent = _bone->getParent()->getApplied();
BonePose& parent = _bone->getParent()->getAppliedPose();
float pa = parent._a, pb = parent._b, pc = parent._c, pd = parent._d;
_worldX = pa * _x + pb * _y + parent._worldX;
_worldY = pc * _x + pd * _y + parent._worldY;
@ -158,7 +156,7 @@ void BonePose::updateWorldTransform(Skeleton& skeleton) {
void BonePose::updateLocalTransform(Skeleton& skeleton) {
_local = 0;
_world = skeleton.getUpdate();
_world = skeleton._update;
if (_bone->getParent() == nullptr) {
_x = _worldX - skeleton.getX();
@ -172,7 +170,7 @@ void BonePose::updateLocalTransform(Skeleton& skeleton) {
return;
}
BonePose& parent = _bone->getParent()->getApplied();
BonePose& parent = _bone->getParent()->getAppliedPose();
float pa = parent._a, pb = parent._b, pc = parent._c, pd = parent._d;
float pid = 1 / (pa * pd - pb * pc);
float ia = pd * pid, ib = pb * pid, ic = pc * pid, id = pa * pid;
@ -243,13 +241,13 @@ void BonePose::updateLocalTransform(Skeleton& skeleton) {
}
void BonePose::validateLocalTransform(Skeleton& skeleton) {
if (_local == skeleton.getUpdate()) updateLocalTransform(skeleton);
if (_local == skeleton._update) updateLocalTransform(skeleton);
}
void BonePose::modifyLocal(Skeleton& skeleton) {
if (_local == skeleton.getUpdate()) updateLocalTransform(skeleton);
if (_local == skeleton._update) updateLocalTransform(skeleton);
_world = 0;
resetWorld(skeleton.getUpdate());
resetWorld(skeleton._update);
}
void BonePose::modifyWorld(int update) {
@ -261,7 +259,7 @@ void BonePose::modifyWorld(int update) {
void BonePose::resetWorld(int update) {
Vector<Bone*>& children = _bone->getChildren();
for (size_t i = 0, n = children.size(); i < n; i++) {
BonePose& child = children[i]->getApplied();
BonePose& child = children[i]->getAppliedPose();
if (child._world == update) {
child._world = 0;
child._local = 0;
@ -352,7 +350,7 @@ void BonePose::worldToParent(float worldX, float worldY, float& outParentX, floa
outParentX = worldX;
outParentY = worldY;
} else {
_bone->getParent()->getApplied().worldToLocal(worldX, worldY, outParentX, outParentY);
_bone->getParent()->getAppliedPose().worldToLocal(worldX, worldY, outParentX, outParentY);
}
}
@ -361,7 +359,7 @@ void BonePose::parentToWorld(float parentX, float parentY, float& outWorldX, flo
outWorldX = parentX;
outWorldY = parentY;
} else {
_bone->getParent()->getApplied().localToWorld(parentX, parentY, outWorldX, outWorldY);
_bone->getParent()->getAppliedPose().localToWorld(parentX, parentY, outWorldX, outWorldY);
}
}

View File

@ -42,7 +42,7 @@ using namespace spine;
RTTI_IMPL(RGBATimeline, SlotCurveTimeline)
RGBATimeline::RGBATimeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGBATimeline::RGBATimeline(size_t frameCount, size_t bezierCount, int slotIndex)
: SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex,
((PropertyId) Property_Alpha << 32) | slotIndex};
@ -52,10 +52,6 @@ RGBATimeline::RGBATimeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGBATimeline::~RGBATimeline() {
}
int RGBATimeline::getFrameEntries() {
return ENTRIES;
}
void RGBATimeline::setFrame(int frame, float time, float r, float g, float b, float a) {
frame *= ENTRIES;
_frames[frame] = time;
@ -68,13 +64,13 @@ void RGBATimeline::setFrame(int frame, float time, float r, float g, float b, fl
void RGBATimeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, MixBlend blend) {
Color& color = pose._color;
if (time < _frames[0]) {
Color& setup = slot._data._setup->_color;
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,
color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha,
(setup.b - color.b) * alpha, (setup.a - color.a) * alpha);
return;
default:
@ -118,15 +114,15 @@ void RGBATimeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, Mi
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,
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);
}
}
RTTI_IMPL(RGBTimeline, SlotCurveTimeline)
RGBTimeline::RGBTimeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGBTimeline::RGBTimeline(size_t frameCount, size_t bezierCount, int slotIndex)
: SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex};
setPropertyIds(ids, 1);
@ -135,10 +131,6 @@ RGBTimeline::RGBTimeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGBTimeline::~RGBTimeline() {
}
int RGBTimeline::getFrameEntries() {
return ENTRIES;
}
void RGBTimeline::setFrame(int frame, float time, float r, float g, float b) {
frame <<= 2;
_frames[frame] = time;
@ -150,7 +142,7 @@ void RGBTimeline::setFrame(int frame, float time, float r, float g, float b) {
void RGBTimeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, MixBlend blend) {
Color& color = pose._color;
if (time < _frames[0]) {
Color& setup = slot._data._setup->_color;
Color& setup = slot._data._setup._color;
switch (blend) {
case MixBlend_Setup:
color.r = setup.r;
@ -202,7 +194,7 @@ void RGBTimeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, Mix
color.b = b;
} else {
if (blend == MixBlend_Setup) {
Color& setup = slot._data._setup->_color;
Color& setup = slot._data._setup._color;
color.r = setup.r;
color.g = setup.g;
color.b = setup.b;
@ -213,10 +205,10 @@ void RGBTimeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, Mix
}
}
RTTI_IMPL(AlphaTimeline, CurveTimeline1)
RTTI_IMPL(AlphaTimeline, SlotTimeline)
AlphaTimeline::AlphaTimeline(size_t frameCount, size_t bezierCount, int slotIndex)
: CurveTimeline1(frameCount, bezierCount), _slotIndex(slotIndex) {
AlphaTimeline::AlphaTimeline(size_t frameCount, size_t bezierCount, int slotIndex)
: CurveTimeline1(frameCount, bezierCount), SlotTimeline(slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Alpha << 32) | slotIndex};
setPropertyIds(ids, 1);
}
@ -233,9 +225,9 @@ void AlphaTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector
Slot *slot = skeleton._slots[_slotIndex];
if (!slot->_bone._active) return;
Color& color = (appliedPose ? slot->_applied : slot->_pose)._color;
Color& color = (appliedPose ? *slot->_applied : slot->_pose)._color;
if (time < _frames[0]) {
Color& setup = slot->_data._setup->_color;
Color& setup = slot->_data._setup._color;
switch (blend) {
case MixBlend_Setup:
color.a = setup.a;
@ -252,18 +244,14 @@ void AlphaTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector
if (alpha == 1)
color.a = a;
else {
if (blend == MixBlend_Setup) color.a = slot->_data._setup->_color.a;
if (blend == MixBlend_Setup) color.a = slot->_data._setup._color.a;
color.a += (a - color.a) * alpha;
}
}
int AlphaTimeline::getSlotIndex() {
return _slotIndex;
}
RTTI_IMPL(RGBA2Timeline, SlotCurveTimeline)
RGBA2Timeline::RGBA2Timeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGBA2Timeline::RGBA2Timeline(size_t frameCount, size_t bezierCount, int slotIndex)
: SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex,
((PropertyId) Property_Alpha << 32) | slotIndex,
@ -274,10 +262,6 @@ RGBA2Timeline::RGBA2Timeline(size_t frameCount, size_t bezierCount, int slotInde
RGBA2Timeline::~RGBA2Timeline() {
}
int RGBA2Timeline::getFrameEntries() {
return ENTRIES;
}
void RGBA2Timeline::setFrame(int frame, float time, float r, float g, float b, float a, float r2, float g2, float b2) {
frame <<= 3;
_frames[frame] = time;
@ -294,7 +278,7 @@ void RGBA2Timeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, M
Color& light = pose._color;
Color& dark = pose._darkColor;
if (time < _frames[0]) {
SlotPose& setup = *slot._data._setup;
SlotPose& setup = slot._data._setup;
Color& setupLight = setup._color;
Color& setupDark = setup._darkColor;
switch (blend) {
@ -368,14 +352,14 @@ void RGBA2Timeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, M
dark.b = b2;
} else {
if (blend == MixBlend_Setup) {
SlotPose& setup = *slot._data._setup;
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;
}
light.add((r - light.r) * alpha, (g - light.g) * alpha,
light.add((r - light.r) * alpha, (g - light.g) * alpha,
(b - light.b) * alpha, (a - light.a) * alpha);
dark.r += (r2 - dark.r) * alpha;
dark.g += (g2 - dark.g) * alpha;
@ -385,7 +369,7 @@ void RGBA2Timeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, M
RTTI_IMPL(RGB2Timeline, SlotCurveTimeline)
RGB2Timeline::RGB2Timeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGB2Timeline::RGB2Timeline(size_t frameCount, size_t bezierCount, int slotIndex)
: SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex,
((PropertyId) Property_Rgb2 << 32) | slotIndex};
@ -395,10 +379,6 @@ RGB2Timeline::RGB2Timeline(size_t frameCount, size_t bezierCount, int slotIndex)
RGB2Timeline::~RGB2Timeline() {
}
int RGB2Timeline::getFrameEntries() {
return ENTRIES;
}
void RGB2Timeline::setFrame(int frame, float time, float r, float g, float b, float r2, float g2, float b2) {
frame *= ENTRIES;
_frames[frame] = time;
@ -414,7 +394,7 @@ void RGB2Timeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, Mi
Color& light = pose._color;
Color& dark = pose._darkColor;
if (time < _frames[0]) {
SlotPose& setup = *slot._data._setup;
SlotPose& setup = slot._data._setup;
Color& setupLight = setup._color;
Color& setupDark = setup._darkColor;
switch (blend) {
@ -489,7 +469,7 @@ void RGB2Timeline::apply(Slot& slot, SlotPose& pose, float time, float alpha, Mi
dark.b = b2;
} else {
if (blend == MixBlend_Setup) {
SlotPose& setup = *slot._data._setup;
SlotPose& setup = slot._data._setup;
light.r = setup._color.r;
light.g = setup._color.g;
light.b = setup._color.b;

View File

@ -0,0 +1,38 @@
/******************************************************************************
* 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/Constraint.h>
using namespace spine;
Constraint::Constraint() {
}
Constraint::~Constraint() {
}

View File

@ -104,10 +104,6 @@ CurveTimeline1::CurveTimeline1(size_t frameCount, size_t bezierCount) : CurveTim
CurveTimeline1::~CurveTimeline1() {
}
size_t CurveTimeline1::getFrameEntries() {
return ENTRIES;
}
void CurveTimeline1::setFrame(size_t frame, float time, float value) {
frame <<= 1;
_frames[frame] = time;

View File

@ -44,7 +44,7 @@ using namespace spine;
RTTI_IMPL(DeformTimeline, CurveTimeline)
DeformTimeline::DeformTimeline(size_t frameCount, size_t bezierCount, int slotIndex, VertexAttachment *attachment)
: CurveTimeline(frameCount, 1, bezierCount), _slotIndex(slotIndex), _attachment(attachment) {
: SlotCurveTimeline(frameCount, 1, bezierCount, slotIndex), _attachment(attachment) {
PropertyId ids[] = {((PropertyId) Property_Deform << 32) | ((slotIndex << 16 | attachment->_id) & 0xffffffff)};
setPropertyIds(ids, 1);
@ -56,7 +56,7 @@ DeformTimeline::DeformTimeline(size_t frameCount, size_t bezierCount, int slotIn
}
void DeformTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction) {
MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
@ -64,12 +64,13 @@ void DeformTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vecto
Slot *slotP = skeleton._slots[_slotIndex];
Slot &slot = *slotP;
if (!slot._bone.isActive()) return;
SlotPose& pose = appliedPose ? *slot._applied : slot._pose;
apply(slot, slot._pose, time, alpha, blend);
apply(slot, pose, time, alpha, blend);
}
void DeformTimeline::apply(Slot &slot, SlotPose &pose, float time, float alpha, MixBlend blend) {
Attachment *slotAttachment = pose.attachment;
Attachment *slotAttachment = pose._attachment;
if (slotAttachment == NULL || !slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti)) {
return;
}
@ -79,7 +80,7 @@ void DeformTimeline::apply(Slot &slot, SlotPose &pose, float time, float alpha,
return;
}
Vector<float> &deformArray = pose.deform;
Vector<float> &deformArray = pose._deform;
if (deformArray.size() == 0) {
blend = MixBlend_Setup;
}

View File

@ -39,7 +39,7 @@
using namespace spine;
RTTI_IMPL_NOPARENT(IkConstraint)
RTTI_IMPL(IkConstraint, Constraint)
void IkConstraint::apply(Skeleton& skeleton, BonePose& bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float mix) {
bone.modifyLocal(skeleton);
@ -249,10 +249,10 @@ void IkConstraint::apply(Skeleton& skeleton, BonePose& parent, BonePose& child,
child._rotation += a2 * mix;
}
IkConstraint::IkConstraint(IkConstraintData &data, Skeleton &skeleton) :
Constraint<IkConstraint, IkConstraintData, IkConstraintPose>(data),
IkConstraint::IkConstraint(IkConstraintData &data, Skeleton &skeleton) :
ConstraintGeneric<IkConstraint, IkConstraintData, IkConstraintPose>(data),
_target(skeleton.findBone(data.getTarget()->getName())) {
_bones.ensureCapacity(data.getBones().size());
for (size_t i = 0; i < data.getBones().size(); i++) {
BoneData *boneData = data.getBones()[i];

View File

@ -31,8 +31,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(IkConstraintPose)
IkConstraintPose::IkConstraintPose() : _bendDirection(0), _compress(false), _stretch(false), _mix(0), _softness(0) {
}

View File

@ -44,17 +44,17 @@
using namespace spine;
RTTI_IMPL_NOPARENT(PathConstraint)
RTTI_IMPL(PathConstraint, Constraint)
const float PathConstraint::epsilon = 0.00001f;
const int PathConstraint::NONE = -1;
const int PathConstraint::BEFORE = -2;
const int PathConstraint::AFTER = -3;
PathConstraint::PathConstraint(PathConstraintData &data, Skeleton &skeleton) :
Constraint<PathConstraint, PathConstraintData, PathConstraintPose>(data),
PathConstraint::PathConstraint(PathConstraintData &data, Skeleton &skeleton) :
ConstraintGeneric<PathConstraint, PathConstraintData, PathConstraintPose>(data),
_slot(skeleton._slots.buffer()[data._slot->_index]) {
_bones.ensureCapacity(data.getBones().size());
for (size_t i = 0; i < data.getBones().size(); i++) {
BoneData *boneData = data.getBones()[i];
@ -247,7 +247,6 @@ Slot *PathConstraint::getSlot() {
}
void PathConstraint::setSlot(Slot *slot) {
if (slot == NULL) throw;
_slot = slot;
}

View File

@ -31,8 +31,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(PathConstraintPose)
PathConstraintPose::PathConstraintPose() : Pose<PathConstraintPose>(), _position(0), _spacing(0), _mixRotate(0), _mixX(0), _mixY(0) {
}

View File

@ -39,15 +39,15 @@
using namespace spine;
RTTI_IMPL_NOPARENT(PhysicsConstraint)
RTTI_IMPL(PhysicsConstraint, Constraint)
PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skeleton) :
Constraint<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose>(data),
PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skeleton) :
ConstraintGeneric<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose>(data),
_reset(true), _ux(0), _uy(0), _cx(0), _cy(0), _tx(0), _ty(0),
_xOffset(0), _xLag(0), _xVelocity(0), _yOffset(0), _yLag(0), _yVelocity(0),
_rotateOffset(0), _rotateLag(0), _rotateVelocity(0), _scaleOffset(0), _scaleLag(0), _scaleVelocity(0),
_remaining(0), _lastTime(0) {
_bone = &skeleton.getBones()[(size_t)data.getBone()->getIndex()]->getAppliedPose();
}

View File

@ -31,8 +31,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(PhysicsConstraintPose)
PhysicsConstraintPose::PhysicsConstraintPose() : Pose<PhysicsConstraintPose>(), _inertia(0), _strength(0), _damping(0), _massInverse(0), _wind(0), _gravity(0), _mix(0) {
}

View File

@ -36,8 +36,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(Sequence)
int Sequence::_nextID = 0;
Sequence::Sequence(int count) : _id(nextID()),

View File

@ -31,18 +31,19 @@
#include <spine/Bone.h>
#include <spine/RegionAttachment.h>
#include <spine/MeshAttachment.h>
#include <spine/VertexAttachment.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Attachment.h>
#include <spine/PathConstraintData.h>
#include <spine/Slot.h>
#include <spine/Animation.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL(SequenceTimeline, Timeline)
SequenceTimeline::SequenceTimeline(size_t frameCount, int slotIndex, Attachment *attachment) : Timeline(frameCount, ENTRIES), _slotIndex(slotIndex), _attachment(attachment) {
SequenceTimeline::SequenceTimeline(size_t frameCount, int slotIndex, Attachment *attachment) : Timeline(frameCount, ENTRIES), SlotTimeline(slotIndex), _attachment((HasTextureRegion*)attachment) {
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();
@ -62,31 +63,32 @@ void SequenceTimeline::setFrame(int frame, float time, SequenceMode mode, int in
}
void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
float alpha, MixBlend blend, MixDirection direction) {
float alpha, MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(alpha);
SP_UNUSED(lastTime);
SP_UNUSED(pEvents);
SP_UNUSED(direction);
Slot *slot = skeleton.getSlots()[_slotIndex];
Slot *slot = skeleton.getSlots()[getSlotIndex()];
if (!slot->getBone().isActive()) return;
Attachment *slotAttachment = slot->getAttachment();
if (slotAttachment != _attachment) {
if (slotAttachment == NULL || !slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti) || ((VertexAttachment *) slotAttachment)->getTimelineAttachment() != _attachment) return;
SlotPose& pose = appliedPose ? slot->getAppliedPose() : slot->getPose();
Attachment *slotAttachment = pose.getAttachment();
if (slotAttachment != (Attachment*)_attachment) {
if (slotAttachment == NULL || !slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti) || ((VertexAttachment *) slotAttachment)->getTimelineAttachment() != (Attachment*)_attachment) return;
}
Sequence *sequence = NULL;
if (_attachment->getRTTI().instanceOf(RegionAttachment::rtti)) sequence = ((RegionAttachment *) _attachment)->getSequence();
if (_attachment->getRTTI().instanceOf(MeshAttachment::rtti)) sequence = ((MeshAttachment *) _attachment)->getSequence();
if (((Attachment*)_attachment)->getRTTI().instanceOf(RegionAttachment::rtti)) sequence = ((RegionAttachment *) _attachment)->getSequence();
if (((Attachment*)_attachment)->getRTTI().instanceOf(MeshAttachment::rtti)) sequence = ((MeshAttachment *) _attachment)->getSequence();
if (!sequence) return;
if (direction == MixDirection_Out) {
if (blend == MixBlend_Setup) slot->setSequenceIndex(-1);
if (blend == MixBlend_Setup) pose.setSequenceIndex(-1);
return;
}
Vector<float> &frames = this->_frames;
if (time < frames[0]) {// Time is before first frame.
if (blend == MixBlend_Setup || blend == MixBlend_First) slot->setSequenceIndex(-1);
if (time < frames[0]) {
if (blend == MixBlend_Setup || blend == MixBlend_First) pose.setSequenceIndex(-1);
return;
}
@ -122,8 +124,9 @@ void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vec
int n = (count << 1) - 2;
index = n == 0 ? 0 : (index + count - 1) % n;
if (index >= count) index = n - index;
break;
}
}
}
slot->setSequenceIndex(index);
pose.setSequenceIndex(index);
}

View File

@ -40,11 +40,11 @@
using namespace spine;
RTTI_IMPL(Slider, Update)
RTTI_IMPL(Slider, Constraint)
float Slider::_offsets[6];
Slider::Slider(SliderData& data, Skeleton& skeleton) : Constraint<Slider, SliderData, SliderPose>(data), _bone(NULL) {
Slider::Slider(SliderData& data, Skeleton& skeleton) : ConstraintGeneric<Slider, SliderData, SliderPose>(data), _bone(NULL) {
if (data.getBone() != NULL) {
_bone = skeleton.findBone(data.getBone()->getName());
}
@ -81,7 +81,7 @@ void Slider::update(Skeleton& skeleton, Physics physics) {
// }
// TODO: Implement when Animation is ported
// animation->apply(skeleton, p.getTime(), p.getTime(), _data.getLoop(), NULL, p.getMix(),
// animation->apply(skeleton, p.getTime(), p.getTime(), _data.getLoop(), NULL, p.getMix(),
// _data.getAdditive() ? MixBlend_Add : MixBlend_Replace, MixDirection_In);
}

View File

@ -31,8 +31,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(SliderPose)
SliderPose::SliderPose() : _time(0), _mix(0) {
}

View File

@ -39,16 +39,12 @@ using namespace spine;
RTTI_IMPL(SlotCurveTimeline, CurveTimeline)
SlotCurveTimeline::SlotCurveTimeline(size_t frameCount, size_t frameEntries, size_t bezierCount, int slotIndex)
: CurveTimeline(frameCount, frameEntries, bezierCount), _slotIndex(slotIndex) {
: CurveTimeline(frameCount, frameEntries, bezierCount), SlotTimeline(slotIndex) {
}
SlotCurveTimeline::~SlotCurveTimeline() {
}
int SlotCurveTimeline::getSlotIndex() {
return _slotIndex;
}
void SlotCurveTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction, bool appliedPose) {
SP_UNUSED(lastTime);
@ -56,5 +52,5 @@ void SlotCurveTimeline::apply(Skeleton &skeleton, float lastTime, float time, Ve
SP_UNUSED(direction);
Slot *slot = skeleton._slots[_slotIndex];
if (slot->_bone._active) apply(*slot, appliedPose ? slot->_applied : slot->_pose, time, alpha, blend);
if (slot->_bone._active) apply(*slot, appliedPose ? *slot->_applied : slot->_pose, time, alpha, blend);
}

View File

@ -35,9 +35,7 @@
using namespace spine;
RTTI_IMPL_NOPARENT(SlotData)
SlotData::SlotData(int index, const String& name, BoneData& boneData) :
SlotData::SlotData(int index, const String& name, BoneData& boneData) :
PosedData<SlotPose>(name),
_index(index),
_boneData(boneData),

View File

@ -33,8 +33,6 @@
using namespace spine;
RTTI_IMPL_NOPARENT(SlotPose)
SlotPose::SlotPose() : _color(1, 1, 1, 1), _darkColor(0, 0, 0, 0), _hasDarkColor(false), _attachment(nullptr), _sequenceIndex(-1) {
}
@ -69,7 +67,7 @@ Attachment* SlotPose::getAttachment() {
void SlotPose::setAttachment(Attachment* attachment) {
if (_attachment == attachment) return;
// Check if we need to clear deform based on timeline attachment
if (!attachment ||
!_attachment ||

View File

@ -33,6 +33,12 @@ using namespace spine;
RTTI_IMPL_NOPARENT(SlotTimeline)
SlotTimeline::SlotTimeline(int slotIndex) : _slotIndex(slotIndex) {
}
SlotTimeline::~SlotTimeline() {
}
int SlotTimeline::getSlotIndex() {
return _slotIndex;
}

View File

@ -39,11 +39,10 @@
using namespace spine;
RTTI_IMPL_NOPARENT(TransformConstraint)
RTTI_IMPL(TransformConstraint, Constraint)
TransformConstraint::TransformConstraint(TransformConstraintData& data, Skeleton& skeleton) :
Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose>(data) {
if (&skeleton == NULL) throw;
TransformConstraint::TransformConstraint(TransformConstraintData& data, Skeleton& skeleton) :
ConstraintGeneric<TransformConstraint, TransformConstraintData, TransformConstraintPose>(data) {
_bones.ensureCapacity(data.getBones().size());
for (size_t i = 0; i < data.getBones().size(); i++) {
@ -140,6 +139,5 @@ Bone* TransformConstraint::getSource() {
}
void TransformConstraint::setSource(Bone* source) {
if (source == NULL) throw;
_source = source;
}

View File

@ -31,9 +31,7 @@
using namespace spine;
RTTI_IMPL_NOPARENT(TransformConstraintPose)
TransformConstraintPose::TransformConstraintPose() :
TransformConstraintPose::TransformConstraintPose() :
_mixRotate(0), _mixX(0), _mixY(0), _mixScaleX(0), _mixScaleY(0), _mixShearY(0) {
}